diff --git a/src/chrome/PluginInstaller.tsx b/src/chrome/PluginInstaller.tsx index 82534f4e8..86020aa04 100644 --- a/src/chrome/PluginInstaller.tsx +++ b/src/chrome/PluginInstaller.tsx @@ -20,12 +20,18 @@ import { Glyph, Link, Text, + LoadingIndicator, } from 'flipper'; import React, {useCallback, useState, useMemo, useEffect} from 'react'; import {remote} from 'electron'; import {List} from 'immutable'; import algoliasearch from 'algoliasearch'; +import path from 'path'; +import fs from 'fs-extra'; +import download from 'download-tarball'; +import {homedir} from 'os'; +const PLUGIN_DIR = path.join(homedir(), '.flipper', 'thirdparty'); const ALGOLIA_APPLICATION_ID = 'OFCNCOG2CU'; const ALGOLIA_API_KEY = 'f54e21fa3a2a0160595bb058179bfb1e'; @@ -127,6 +133,48 @@ const TableButton = styled(Button)({ marginTop: 2, }); +function InstallButton(props: { + name: string; + version: string; + onInstall: () => void; +}) { + type InstallAction = 'Install' | 'Downloading' | 'Remove'; + + const onInstall = useCallback(async () => { + setAction('Downloading'); + const filename = `${props.name}-${props.version}.tgz`; + await download({ + url: `https://registry.npmjs.org/${props.name}/-/${filename}`, + dir: PLUGIN_DIR, + }); + await fs.rename( + path.join(PLUGIN_DIR, 'package'), + path.join(PLUGIN_DIR, props.name), + ); + props.onInstall(); + setAction('Remove'); + }, [props.name, props.version]); + + const onRemove = useCallback(async () => { + fs.remove(path.join(PLUGIN_DIR, props.name)); + setAction('Install'); + }, [props.name]); + + const [action, setAction] = useState('Install'); + + if (action === 'Downloading') { + return ; + } + return ( + + {action} + + ); +} + function useNPMSearch( setRestartRequired: (restart: boolean) => void, query: string, @@ -137,6 +185,10 @@ function useNPMSearch( return client.initIndex('npm-search'); }, []); + const onInstall = useCallback(async () => { + setRestartRequired(true); + }, []); + const createRow = useCallback( (h: PluginDefinition) => ({ key: h.name, @@ -158,7 +210,13 @@ function useNPMSearch( ), }, install: { - value: Install, + value: ( + + ), align: 'center' as 'center', }, }, diff --git a/static/index.js b/static/index.js index b0c149a37..540f4eb00 100644 --- a/static/index.js +++ b/static/index.js @@ -74,6 +74,7 @@ const {config, configPath, flipperDir} = setup(argv); const pluginPaths = config.pluginPaths .concat( + path.join(configPath, 'thirdparty'), path.join(__dirname, '..', 'src', 'plugins'), path.join(__dirname, '..', 'src', 'fb', 'plugins'), ) diff --git a/types/download-tarball.d.tsx b/types/download-tarball.d.tsx new file mode 100644 index 000000000..85d6c533b --- /dev/null +++ b/types/download-tarball.d.tsx @@ -0,0 +1,14 @@ +/** + * Copyright 2018-present Facebook. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * @format + */ + +declare module 'download-tarball' { + export default function(options: { + url: string; + dir: string; + gotOpts?: any; + }): Promise; +}