From 97b814d70e352c84b3e4d2c6147e425934382d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20B=C3=BCchele?= Date: Tue, 17 Sep 2019 06:19:30 -0700 Subject: [PATCH] installed plugins Summary: Checking `~/.flipper/thirdparty` for already installed plugins and displaying them on top of the table Reviewed By: jknoxville Differential Revision: D17394821 fbshipit-source-id: 65f392c8beaf72d9effcae9f47a60bcbb9194025 --- src/chrome/PluginInstaller.tsx | 65 ++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/src/chrome/PluginInstaller.tsx b/src/chrome/PluginInstaller.tsx index 86020aa04..79b2f48b2 100644 --- a/src/chrome/PluginInstaller.tsx +++ b/src/chrome/PluginInstaller.tsx @@ -133,15 +133,20 @@ const TableButton = styled(Button)({ marginTop: 2, }); +const Spinner = styled(LoadingIndicator)({ + marginTop: 6, +}); + function InstallButton(props: { name: string; version: string; onInstall: () => void; + installed: boolean; }) { - type InstallAction = 'Install' | 'Downloading' | 'Remove'; + type InstallAction = 'Install' | 'Waiting' | 'Remove'; const onInstall = useCallback(async () => { - setAction('Downloading'); + setAction('Waiting'); const filename = `${props.name}-${props.version}.tgz`; await download({ url: `https://registry.npmjs.org/${props.name}/-/${filename}`, @@ -156,14 +161,18 @@ function InstallButton(props: { }, [props.name, props.version]); const onRemove = useCallback(async () => { - fs.remove(path.join(PLUGIN_DIR, props.name)); + setAction('Waiting'); + await fs.remove(path.join(PLUGIN_DIR, props.name)); + props.onInstall(); setAction('Install'); }, [props.name]); - const [action, setAction] = useState('Install'); + const [action, setAction] = useState( + props.installed ? 'Remove' : 'Install', + ); - if (action === 'Downloading') { - return ; + if (action === 'Waiting') { + return ; } return ( (), + ); + + useEffect(() => { + getInstalledPlugns().then(setInstalledPlugins); + }, []); + const onInstall = useCallback(async () => { + setInstalledPlugins(await getInstalledPlugns()); setRestartRequired(true); }, []); @@ -215,13 +233,14 @@ function useNPMSearch( name={h.name} version={h.version} onInstall={onInstall} + installed={installedPlugins.has(h.name)} /> ), align: 'center' as 'center', }, }, }), - [], + [installedPlugins], ); const [searchResults, setSearchResults] = useState([]); @@ -234,10 +253,36 @@ function useNPMSearch( hitsPerPage: 20, }); - setSearchResults(hits); + setSearchResults(hits.filter(hit => !installedPlugins.has(hit.name))); setQuery(query); })(); - }, [query]); + }, [query, installedPlugins]); - return List(searchResults.map(createRow)); + const results = Array.from(installedPlugins.values()).concat(searchResults); + return List(results.map(createRow)); +} + +async function getInstalledPlugns() { + const dirs = await fs.readdir(PLUGIN_DIR); + const plugins = await Promise.all<[string, PluginDefinition]>( + dirs.map( + name => + new Promise(async (resolve, reject) => { + if (!(await fs.lstat(path.join(PLUGIN_DIR, name))).isDirectory()) { + return resolve(undefined); + } + + const packageJSON = await fs.readFile( + path.join(PLUGIN_DIR, name, 'package.json'), + ); + + try { + resolve([name, JSON.parse(packageJSON.toString())]); + } catch (e) { + reject(e); + } + }), + ), + ); + return new Map(plugins.filter(Boolean)); }