From e7fbabd19c64c09bb0df9b3131e61328ff822af6 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 12:51:40 -0400 Subject: [PATCH 1/8] rebase --- .env | 4 + biome.json | 3 +- src/components/DisplayPage/index.tsx | 11 +- .../PluginCatalog/PluginCatalog.tsx | 5 +- src/components/PluginCatalog/index.tsx | 2 + src/components/Store/index.tsx | 311 ++++++++++++++++++ src/components/Wrapper/Sidebar.tsx | 4 + src/routes.tsx | 5 + tsconfig.json | 4 + 9 files changed, 339 insertions(+), 10 deletions(-) create mode 100644 src/components/Store/index.tsx diff --git a/.env b/.env index 0a97350a9..6f9c9f87a 100644 --- a/.env +++ b/.env @@ -16,3 +16,7 @@ VITE_PFDCM_URL="http://localhost:4005/" VITE_PFDCM_CUBEKEY="local" VITE_PFDCM_SWIFTKEY="local" VITE_SOURCEMAP='false' + +# Set URL for the store + +VITE_CHRIS_STORE_URL= 'http://rc-live.tch.harvard.edu:32222/api/v1/' \ No newline at end of file diff --git a/biome.json b/biome.json index 0ebcd2d04..7ba3b8f89 100644 --- a/biome.json +++ b/biome.json @@ -25,8 +25,7 @@ "useExhaustiveDependencies": "off" }, "suspicious": { - "noExplicitAny": "off", - "noArrayIndexKey": "off" + "noExplicitAny": "off" } } }, diff --git a/src/components/DisplayPage/index.tsx b/src/components/DisplayPage/index.tsx index 2dfb6cf4d..aa183f7d6 100644 --- a/src/components/DisplayPage/index.tsx +++ b/src/components/DisplayPage/index.tsx @@ -123,10 +123,9 @@ const DisplayPage = ({ const updateDropdownValue = (type: string) => { setDropdownValue(type); if (isPlugin) { - handlePluginSearch && handlePluginSearch("", dropdownValue.toLowerCase()); + handlePluginSearch?.("", dropdownValue.toLowerCase()); } else { - handleComputeSearch && - handleComputeSearch("", dropdownValue.toLowerCase()); + handleComputeSearch?.("", dropdownValue.toLowerCase()); } }; const dropdownItems = isPlugin @@ -272,13 +271,11 @@ const DisplayPage = ({ aria-label="search" onChange={(_event, value: string) => { if (isPlugin) { - handlePluginSearch && - handlePluginSearch(value, dropdownValue.toLowerCase()); + handlePluginSearch?.(value, dropdownValue.toLowerCase()); } if (isCompute) { - handleComputeSearch && - handleComputeSearch(value, dropdownValue.toLowerCase()); + handleComputeSearch?.(value, dropdownValue.toLowerCase()); } }} /> diff --git a/src/components/PluginCatalog/PluginCatalog.tsx b/src/components/PluginCatalog/PluginCatalog.tsx index b3c6e6af8..8f17e9d8b 100644 --- a/src/components/PluginCatalog/PluginCatalog.tsx +++ b/src/components/PluginCatalog/PluginCatalog.tsx @@ -13,7 +13,7 @@ const PluginCatalog = () => { itemCount: 0, }); - const { page, perPage, search, searchType } = pageState; + const { page, perPage, search, searchType, itemCount } = pageState; const [selectedPlugin, setSelectedPlugin] = React.useState(); const onSetPage = (_event: any, page: number) => { @@ -77,6 +77,7 @@ const PluginCatalog = () => { itemCount: pluginList.totalCount, }; }); + return newPluginPayload; } } @@ -97,6 +98,8 @@ const PluginCatalog = () => { }); }; + console.log("Page State", pageState); + return ( <> { const dispatch = useDispatch(); + React.useEffect(() => { document.title = "Analysis Catalog"; dispatch( @@ -20,6 +21,7 @@ const CatalogPage = () => { }), ); }); + return ( diff --git a/src/components/Store/index.tsx b/src/components/Store/index.tsx new file mode 100644 index 000000000..51b5da936 --- /dev/null +++ b/src/components/Store/index.tsx @@ -0,0 +1,311 @@ +import WrapperConnect from "../Wrapper"; +import { useEffect, useState, Ref } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import Client, { Plugin } from "@fnndsc/chrisapi"; +import { SpinContainer } from "../Common"; +import { Alert, Spin, Typography, notification } from "antd"; +import { + Card, + Grid, + GridItem, + Button, + CardBody, + Split, + SplitItem, + PageSection, + Badge, + Select, + SelectOption, + MenuToggleElement, + MenuToggle, +} from "@patternfly/react-core"; +import "../SinglePlugin/singlePlugin.css"; +import { format } from "date-fns"; +import { setSidebarActive } from "../../store/ui/actions"; +import { useDispatch } from "react-redux"; +import { InfoIcon } from "../Common"; + +const { Paragraph } = Typography; + +const Store = () => { + const [api, contextHolder] = notification.useNotification(); + const dispatch = useDispatch(); + const [version, setVersion] = useState({}); + const [installingPluginId, setInstallingPluginId] = useState(null); + + useEffect(() => { + document.title = "Store Catalog"; + dispatch( + setSidebarActive({ + activeItem: "store", + }), + ); + }, [dispatch]); + + const fetchPlugins = async () => { + const url = import.meta.env.VITE_CHRIS_STORE_URL; + if (!url) { + throw new Error("No url found for a store"); + } + + const client = new Client(url); + + try { + const pluginMetaList = await client.getPluginMetas({ limit: 1000 }); + + const pluginMetas = pluginMetaList.getItems() || []; + + if (pluginMetas.length > 0) { + const newPluginPayload = await Promise.all( + pluginMetas.map(async (plugin) => { + const plugins = await plugin.getPlugins({ limit: 1000 }); + const pluginItems = plugins.getItems(); + let version = ""; + if (pluginItems && pluginItems.length > 0) { + version = pluginItems[0].data.version; + } + return { + data: { + ...plugin.data, + version, + plugins: pluginItems, + }, + }; + }), + ); + return { + pluginMetaList: newPluginPayload, + client: client, + }; + } + + return { + pluginMetaList: [], + client: client, + }; + } catch (error) { + throw error; + } + }; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ["storePlugins"], + queryFn: fetchPlugins, + }); + + const handleInstall = async (plugins: Plugin[], plugin: any) => { + if (!plugins || plugins.length === 0) { + throw new Error("No plugins available to install."); + } + const latestPlugin = plugins[0]; + const url = "http://localhost:8000/chris-admin/api/v1/"; + const credentials = btoa("chris:chris1234"); // Base64 encoding for Basic Auth + + const pluginData = { + compute_names: "host", + name: latestPlugin.data.name, + version: version[plugin.data.id] || latestPlugin.data.version, + plugin_store_url: latestPlugin.url, + }; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Authorization: `Basic ${credentials}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(pluginData), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + return data; + } catch (error) { + throw error; + } + }; + + const handleInstallMutation = useMutation({ + mutationFn: async ({ + plugins, + plugin, + }: { plugins: Plugin[]; plugin: any }) => + await handleInstall(plugins, plugin), + onMutate: ({ plugin }) => { + setInstallingPluginId(plugin.data.id); + }, + onSettled: () => { + setInstallingPluginId(null); + }, + }); + + useEffect(() => { + if (handleInstallMutation.isSuccess) { + api.success({ + message: "Plugin Successfully installed...", + }); + } + + if (handleInstallMutation.isError) { + api.error({ + message: "Unable to install this plugin...", + }); + } + }, [handleInstallMutation.isSuccess, handleInstallMutation.isError, api]); + + return ( + + {contextHolder} + + +

+ This is a global store from where you can install your plugins. +

+ + } + /> +
+ + {isLoading && } + {isError && } + {data && ( + + {data.pluginMetaList.map((plugin) => ( + + + + + +

+ {plugin.data.name} +

+
+ + {plugin.data.category} + +
+
{plugin.data.title}
+ +
+ {plugin.data.authors} +
+

+ {format( + new Date(plugin.data.modification_date), + "do MMMM, yyyy", + )} +

+

+ Version:{" "} + { + setVersion((prevVersion) => ({ + ...prevVersion, + [plugin.data.id]: selectedVersion, + })); + }} + currentVersion={ + version[plugin.data.id] || plugin.data.version + } + plugins={plugin.data.plugins} + /> +

+ + +
+
+
+ ))} +
+ )} +
+
+ ); +}; + +export default Store; + +const VersionSelect = ({ plugins, currentVersion, handlePluginVersion }) => { + const [isOpen, setIsOpen] = useState(false); + const onToggleClick = () => { + setIsOpen(!isOpen); + }; + + const onSelect = ( + _event: React.MouseEvent | undefined, + value: string | number | undefined, + ) => { + handlePluginVersion(value); + setIsOpen(false); + }; + + const toggle = (toggleRef: Ref) => ( + + {currentVersion} + + ); + + return ( + + ); +}; diff --git a/src/components/Wrapper/Sidebar.tsx b/src/components/Wrapper/Sidebar.tsx index f3319ba65..9b6f0ec27 100644 --- a/src/components/Wrapper/Sidebar.tsx +++ b/src/components/Wrapper/Sidebar.tsx @@ -89,6 +89,10 @@ const Sidebar: React.FC = ({ {renderLink("/dataset", "Volume View", "dataset")} + + + {renderLink("/store", "Store", "store")} + diff --git a/src/routes.tsx b/src/routes.tsx index f6f50066e..8e87681f6 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -21,6 +21,7 @@ import { import Signup from "./components/Signup"; import SinglePlugin from "./components/SinglePlugin"; import { useTypedSelector } from "./store/hooks"; +import Store from "./components/Store"; interface IState { selectData?: Series; @@ -156,6 +157,10 @@ export const MainRouter: React.FC = () => { path: "niivue/:plinstId", element: , }, + { + path: "store", + element: , + }, { path: "*", element: , diff --git a/tsconfig.json b/tsconfig.json index 28c51cf9f..a186f8588 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,11 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, +<<<<<<< HEAD "noImplicitAny":true, +======= + "noImplicitAny": false +>>>>>>> 180631e3 (feat: Explore the idea of a store from which a user can install plugins) }, "references": [{ "path": "./tsconfig.node.json" }] } From 85aab543dcf267502ebde6864dabf8742e085aee Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 12:52:38 -0400 Subject: [PATCH 2/8] rebase --- src/components/Pacs/components/SeriesCard.tsx | 4 ++++ src/components/PluginCatalog/PluginCatalog.tsx | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/Pacs/components/SeriesCard.tsx b/src/components/Pacs/components/SeriesCard.tsx index 674d6df9b..1628aa517 100644 --- a/src/components/Pacs/components/SeriesCard.tsx +++ b/src/components/Pacs/components/SeriesCard.tsx @@ -195,7 +195,11 @@ const SeriesCardCopy = ({ series }: { series: any }) => { }); } +<<<<<<< HEAD if (pushCount > 0 && pushCount === totalFilesCount && isFetching) { +======= + if (pushCount > 0 && isFetching) { +>>>>>>> a20afa3a (refactor: cleanup) // This means oxidicom is done pushing as the push count file is available // cancel polling setIsFetching(false); diff --git a/src/components/PluginCatalog/PluginCatalog.tsx b/src/components/PluginCatalog/PluginCatalog.tsx index 8f17e9d8b..e4875caa0 100644 --- a/src/components/PluginCatalog/PluginCatalog.tsx +++ b/src/components/PluginCatalog/PluginCatalog.tsx @@ -98,8 +98,6 @@ const PluginCatalog = () => { }); }; - console.log("Page State", pageState); - return ( <> Date: Thu, 13 Jun 2024 12:53:47 -0400 Subject: [PATCH 3/8] rebase --- src/components/Pacs/components/SeriesCard.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/Pacs/components/SeriesCard.tsx b/src/components/Pacs/components/SeriesCard.tsx index 1628aa517..674d6df9b 100644 --- a/src/components/Pacs/components/SeriesCard.tsx +++ b/src/components/Pacs/components/SeriesCard.tsx @@ -195,11 +195,7 @@ const SeriesCardCopy = ({ series }: { series: any }) => { }); } -<<<<<<< HEAD if (pushCount > 0 && pushCount === totalFilesCount && isFetching) { -======= - if (pushCount > 0 && isFetching) { ->>>>>>> a20afa3a (refactor: cleanup) // This means oxidicom is done pushing as the push count file is available // cancel polling setIsFetching(false); From 458a11b5199bc9df4871d2f676a4bf106040dd85 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 13:38:38 -0400 Subject: [PATCH 4/8] feat: rebase --- playwright.config.ts | 2 -- tsconfig.json | 4 ---- 2 files changed, 6 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index ad320df88..7f5252bb0 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,5 @@ import { defineConfig, devices, PlaywrightTestConfig } from "@playwright/test"; - const SAFARI_BROWSERS: PlaywrightTestConfig["projects"] = []; if (process.env.TEST_SAFARI?.toLowerCase().startsWith('y')) { @@ -65,7 +64,6 @@ export default defineConfig({ ...SAFARI_BROWSERS ], - webServer: { command: "env USE_BABEL_PLUGIN_ISTANBUL=y npm run dev:public", url: "http://localhost:25173", diff --git a/tsconfig.json b/tsconfig.json index a186f8588..28c51cf9f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,11 +19,7 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, -<<<<<<< HEAD "noImplicitAny":true, -======= - "noImplicitAny": false ->>>>>>> 180631e3 (feat: Explore the idea of a store from which a user can install plugins) }, "references": [{ "path": "./tsconfig.node.json" }] } From ce29d2f5d5f1627b2f6011ded76a308bf04f1f8c Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 14:18:45 -0400 Subject: [PATCH 5/8] feat: Update the code to download the correct version of the plugin --- src/components/SinglePlugin/index.tsx | 2 +- src/components/Store/index.tsx | 76 +++++++++++++++++---------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/components/SinglePlugin/index.tsx b/src/components/SinglePlugin/index.tsx index 6b8ea8104..c832159ba 100644 --- a/src/components/SinglePlugin/index.tsx +++ b/src/components/SinglePlugin/index.tsx @@ -102,7 +102,7 @@ const SinglePlugin = () => { const pluginInstances = isLoggedIn ? (( await plugin.getPluginInstances({ - limit: 20, + limit: 1000, }) ).getItems() as PluginInstance[]) : []; diff --git a/src/components/Store/index.tsx b/src/components/Store/index.tsx index 51b5da936..dd471349c 100644 --- a/src/components/Store/index.tsx +++ b/src/components/Store/index.tsx @@ -24,13 +24,16 @@ import { format } from "date-fns"; import { setSidebarActive } from "../../store/ui/actions"; import { useDispatch } from "react-redux"; import { InfoIcon } from "../Common"; +import { isEmpty } from "lodash"; const { Paragraph } = Typography; const Store = () => { const [api, contextHolder] = notification.useNotification(); const dispatch = useDispatch(); - const [version, setVersion] = useState({}); + const [version, setVersion] = useState<{ + [key: string]: any; + }>({}); const [installingPluginId, setInstallingPluginId] = useState(null); useEffect(() => { @@ -47,9 +50,7 @@ const Store = () => { if (!url) { throw new Error("No url found for a store"); } - const client = new Client(url); - try { const pluginMetaList = await client.getPluginMetas({ limit: 1000 }); @@ -84,6 +85,7 @@ const Store = () => { client: client, }; } catch (error) { + // biome-ignore lint/complexity/noUselessCatch: throw error; } }; @@ -93,19 +95,16 @@ const Store = () => { queryFn: fetchPlugins, }); - const handleInstall = async (plugins: Plugin[], plugin: any) => { - if (!plugins || plugins.length === 0) { - throw new Error("No plugins available to install."); - } - const latestPlugin = plugins[0]; + const handleInstall = async (selectedPlugin: Plugin) => { + console.log("SelectedPlugin", selectedPlugin); const url = "http://localhost:8000/chris-admin/api/v1/"; const credentials = btoa("chris:chris1234"); // Base64 encoding for Basic Auth const pluginData = { compute_names: "host", - name: latestPlugin.data.name, - version: version[plugin.data.id] || latestPlugin.data.version, - plugin_store_url: latestPlugin.url, + name: selectedPlugin.data.name, + version: selectedPlugin.data.version, + plugin_store_url: selectedPlugin.url, }; try { @@ -126,18 +125,16 @@ const Store = () => { return data; } catch (error) { + // biome-ignore lint/complexity/noUselessCatch: throw error; } }; const handleInstallMutation = useMutation({ - mutationFn: async ({ - plugins, - plugin, - }: { plugins: Plugin[]; plugin: any }) => - await handleInstall(plugins, plugin), - onMutate: ({ plugin }) => { - setInstallingPluginId(plugin.data.id); + mutationFn: async (selectedPlugin: any) => + await handleInstall(selectedPlugin), + onMutate: (selectedPlugin) => { + setInstallingPluginId(selectedPlugin.data.id); }, onSettled: () => { setInstallingPluginId(null); @@ -224,11 +221,10 @@ const Store = () => { > Version:{" "} { - setVersion((prevVersion) => ({ - ...prevVersion, + handlePluginVersion={(selectedVersion: any) => { + setVersion({ [plugin.data.id]: selectedVersion, - })); + }); }} currentVersion={ version[plugin.data.id] || plugin.data.version @@ -241,12 +237,26 @@ const Store = () => { style={{ marginTop: "1em", }} - onClick={() => - handleInstallMutation.mutate({ - plugins: plugin.data.plugins, - plugin, - }) - } + onClick={() => { + let selectedPlugin = undefined; + if (!isEmpty(version)) { + const findPlugin = plugin.data.plugins.find( + (pluginMeta: any) => { + return ( + pluginMeta.data.version === + version[plugin.data.id] + ); + }, + ); + if (findPlugin) { + selectedPlugin = findPlugin; + } + } else { + selectedPlugin = plugin.data.plugins[0]; + } + + handleInstallMutation.mutate(selectedPlugin); + }} icon={installingPluginId === plugin.data.id && } > Install @@ -264,7 +274,15 @@ const Store = () => { export default Store; -const VersionSelect = ({ plugins, currentVersion, handlePluginVersion }) => { +const VersionSelect = ({ + plugins, + currentVersion, + handlePluginVersion, +}: { + plugins: Plugin[]; + currentVersion: string; + handlePluginVersion: (value: string | number | undefined) => void; +}) => { const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { setIsOpen(!isOpen); From f25b24ede8ab4ba8a2a24faf0380d7cea31a23a4 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 15:05:57 -0400 Subject: [PATCH 6/8] feat: Implement a user modal for admin credentials --- src/components/Store/index.tsx | 130 ++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 27 deletions(-) diff --git a/src/components/Store/index.tsx b/src/components/Store/index.tsx index dd471349c..b1bd68229 100644 --- a/src/components/Store/index.tsx +++ b/src/components/Store/index.tsx @@ -18,6 +18,11 @@ import { SelectOption, MenuToggleElement, MenuToggle, + Modal, + Form, + FormGroup, + TextInput, + ActionGroup, } from "@patternfly/react-core"; import "../SinglePlugin/singlePlugin.css"; import { format } from "date-fns"; @@ -34,7 +39,15 @@ const Store = () => { const [version, setVersion] = useState<{ [key: string]: any; }>({}); - const [installingPluginId, setInstallingPluginId] = useState(null); + const [installingPlugin, setInstallingPlugin] = useState< + | { + data: any; + } + | undefined + >(undefined); + const [enterAdminCred, setEnterAdminCred] = useState(false); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); useEffect(() => { document.title = "Store Catalog"; @@ -96,9 +109,8 @@ const Store = () => { }); const handleInstall = async (selectedPlugin: Plugin) => { - console.log("SelectedPlugin", selectedPlugin); const url = "http://localhost:8000/chris-admin/api/v1/"; - const credentials = btoa("chris:chris1234"); // Base64 encoding for Basic Auth + const credentials = btoa(`${username}:${password}`); // Base64 encoding for Basic Auth const pluginData = { compute_names: "host", @@ -131,16 +143,38 @@ const Store = () => { }; const handleInstallMutation = useMutation({ - mutationFn: async (selectedPlugin: any) => + mutationFn: async (selectedPlugin: Plugin) => await handleInstall(selectedPlugin), - onMutate: (selectedPlugin) => { - setInstallingPluginId(selectedPlugin.data.id); - }, onSettled: () => { - setInstallingPluginId(null); + setInstallingPlugin(undefined); + setEnterAdminCred(false); }, }); + const handleSave = () => { + if (installingPlugin) { + let selectedPlugin: Plugin | undefined = undefined; + if (!isEmpty(version)) { + const findPlugin = installingPlugin.data.plugins.find( + (pluginMeta: any) => { + return ( + pluginMeta.data.version === version[installingPlugin.data.id] + ); + }, + ); + if (findPlugin) { + selectedPlugin = findPlugin; + } + } else { + selectedPlugin = installingPlugin.data.plugins[0]; + } + + if (selectedPlugin) { + handleInstallMutation.mutate(selectedPlugin); + } + } + }; + useEffect(() => { if (handleInstallMutation.isSuccess) { api.success({ @@ -158,6 +192,65 @@ const Store = () => { return ( {contextHolder} + setEnterAdminCred(!enterAdminCred)} + > +
+ + { + setUsername(value); + }} + /> + + + { + setPassword(value); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + handleSave(); + } + }} + /> + + + + + + {handleInstallMutation.isError && ( + + )} + +
+ { marginTop: "1em", }} onClick={() => { - let selectedPlugin = undefined; - if (!isEmpty(version)) { - const findPlugin = plugin.data.plugins.find( - (pluginMeta: any) => { - return ( - pluginMeta.data.version === - version[plugin.data.id] - ); - }, - ); - if (findPlugin) { - selectedPlugin = findPlugin; - } - } else { - selectedPlugin = plugin.data.plugins[0]; - } - - handleInstallMutation.mutate(selectedPlugin); + setEnterAdminCred(!enterAdminCred); + setInstallingPlugin(plugin); }} - icon={installingPluginId === plugin.data.id && } > Install From b93773a700364ba9ed7d0cd197ed22d66cabe942 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 15:28:41 -0400 Subject: [PATCH 7/8] feat: Only show the store if the .env config is present --- src/components/Wrapper/Sidebar.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Wrapper/Sidebar.tsx b/src/components/Wrapper/Sidebar.tsx index 9b6f0ec27..0d989191f 100644 --- a/src/components/Wrapper/Sidebar.tsx +++ b/src/components/Wrapper/Sidebar.tsx @@ -15,6 +15,7 @@ import { ApplicationState } from "../../store/root/applicationState"; import { IUiState } from "../../store/ui/types"; import { IUserState } from "../../store/user/types"; import { useTypedSelector } from "../../store/hooks"; +import { isEmpty } from "lodash"; type AllProps = IUiState & IUserState & ReduxProp; type ReduxProp = { @@ -90,9 +91,11 @@ const Sidebar: React.FC = ({ {renderLink("/dataset", "Volume View", "dataset")} - - {renderLink("/store", "Store", "store")} - + {!isEmpty(import.meta.env.VITE_CHRIS_STORE_URL) && ( + + {renderLink("/store", "Store", "store")} + + )} From eff60c13eeb8bec8de568ac4d9b259bf13eed5c6 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Thu, 13 Jun 2024 15:55:10 -0400 Subject: [PATCH 8/8] feat: Add a text input for the user to enter the url --- src/components/Store/index.tsx | 38 +++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/components/Store/index.tsx b/src/components/Store/index.tsx index b1bd68229..83a7383bb 100644 --- a/src/components/Store/index.tsx +++ b/src/components/Store/index.tsx @@ -48,6 +48,7 @@ const Store = () => { const [enterAdminCred, setEnterAdminCred] = useState(false); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); + const [url, setUrl] = useState(""); useEffect(() => { document.title = "Store Catalog"; @@ -109,9 +110,10 @@ const Store = () => { }); const handleInstall = async (selectedPlugin: Plugin) => { - const url = "http://localhost:8000/chris-admin/api/v1/"; - const credentials = btoa(`${username}:${password}`); // Base64 encoding for Basic Auth - + if (!url) { + throw new Error("Please provide a link to your chris-admin url"); + } + const credentials = btoa(`${username.trim()}:${password.trim()}`); // Base64 encoding for Basic Auth const pluginData = { compute_names: "host", name: selectedPlugin.data.name, @@ -137,6 +139,7 @@ const Store = () => { return data; } catch (error) { + console.log("Error", error); // biome-ignore lint/complexity/noUselessCatch: throw error; } @@ -145,9 +148,11 @@ const Store = () => { const handleInstallMutation = useMutation({ mutationFn: async (selectedPlugin: Plugin) => await handleInstall(selectedPlugin), - onSettled: () => { - setInstallingPlugin(undefined); - setEnterAdminCred(false); + onSettled: (error) => { + if (!isEmpty(error)) { + setInstallingPlugin(undefined); + setEnterAdminCred(false); + } }, }); @@ -196,10 +201,12 @@ const Store = () => { variant="small" isOpen={enterAdminCred} onClose={() => setEnterAdminCred(!enterAdminCred)} + aria-label="Enter admin credentials" >
{ { }} /> + + + { + setUrl(value); + }} + placeholder="eg: http://localhost:8000/chris-admin/api/v1/" + /> +