diff --git a/src/components/AddNode/GuidedConfig.tsx b/src/components/AddNode/GuidedConfig.tsx index 22d3a8fde..f9337218b 100644 --- a/src/components/AddNode/GuidedConfig.tsx +++ b/src/components/AddNode/GuidedConfig.tsx @@ -1,41 +1,41 @@ -import React, { useEffect, useContext, useState } from "react"; +import { PluginInstanceParameter } from "@fnndsc/chrisapi"; +import type { Plugin, PluginParameter } from "@fnndsc/chrisapi"; import { - ClipboardCopy, - Dropdown, - MenuToggle, - DropdownItem, + Button, Card, CardBody, Checkbox, - Grid, - GridItem, - Tooltip, + ClipboardCopy, + Dropdown, + DropdownItem, + DropdownList, Form, FormGroup, - TextInput, - DropdownList, - Button, + Grid, + GridItem, HelperText, HelperTextItem, - SelectList, + MenuToggle, Select, + SelectList, SelectOption, + TextInput, + Tooltip, } from "@patternfly/react-core"; - -import { PluginInstance, PluginInstanceParameter } from "@fnndsc/chrisapi"; -import SimpleDropdown from "./SimpleDropdown"; -import RequiredParam from "./RequiredParam"; -import ComputeEnvironments from "./ComputeEnvironment"; -import { ErrorAlert } from "../Common"; +import React, { useEffect, useContext, useState } from "react"; +import { useDispatch } from "react-redux"; +import { quote } from "shlex"; import { v4 } from "uuid"; -import { handleGetTokens, unpackParametersIntoString } from "./utils"; -import type { Plugin, PluginParameter } from "@fnndsc/chrisapi"; -import { AddNodeContext } from "./context"; -import { Types, InputIndex } from "./types"; +import { fetchResource } from "../../api/common"; import { useTypedSelector } from "../../store/hooks"; -import { useDispatch } from "react-redux"; import { getParams } from "../../store/plugin/actions"; -import { fetchResource } from "../../api/common"; +import { ClipboardCopyFixed, ErrorAlert } from "../Common"; +import ComputeEnvironments from "./ComputeEnvironment"; +import RequiredParam from "./RequiredParam"; +import SimpleDropdown from "./SimpleDropdown"; +import { AddNodeContext } from "./context"; +import { InputIndex, Types } from "./types"; +import { handleGetTokens, unpackParametersIntoString } from "./utils"; const advancedConfigList = [ { @@ -275,6 +275,7 @@ const CheckboxComponent = () => { const params = useTypedSelector((state) => state.plugin.parameters); const { state, dispatch } = useContext(AddNodeContext); const { showPreviousRun, selectedPluginFromMeta } = state; + const handleCheckboxChange = async () => { const pluginInstanceList = await selectedPluginFromMeta?.getPluginInstances( { @@ -285,7 +286,7 @@ const CheckboxComponent = () => { const pluginInstances = pluginInstanceList?.getItems(); if (pluginInstances && pluginInstances.length > 0) { - const pluginInstance: PluginInstance = pluginInstances[0]; + const pluginInstance = pluginInstances[0]; const paramsToFn = { limit: 10, offset: 0 }; const fn = pluginInstance.getParameters; const boundFn = fn.bind(pluginInstance); @@ -295,39 +296,29 @@ const CheckboxComponent = () => { const requiredInput: { [id: string]: InputIndex } = {}; const dropdownInput: { [id: string]: InputIndex } = {}; - const paramsRequiredFetched: - | { - [key: string]: [number, string]; - } - | undefined = - params && - params["required"].reduce((acc, param) => { - return { - ...acc, - [param.data.name]: [param.data.id, param.data.flag], - }; - }, {}); - - const paramsDropdownFetched: - | { - [key: string]: string; - } - | undefined = - params && - params["dropdown"].reduce((acc, param) => { - return { - ...acc, - [param.data.name]: param.data.flag, - }; - }, {}); + const paramsRequiredFetched = params?.required.reduce( + (acc, param) => ({ + ...acc, + [param.data.name]: [param.data.id, param.data.flag], + }), + {}, + ); + + const paramsDropdownFetched = params?.dropdown.reduce( + (acc, param) => ({ + ...acc, + [param.data.name]: param.data.flag, + }), + {}, + ); for (let i = 0; i < pluginParameters.length; i++) { - const parameter: PluginInstanceParameter = pluginParameters[i]; + const parameter = pluginParameters[i]; const { param_name, type, value } = parameter.data; if (paramsRequiredFetched && paramsRequiredFetched[param_name]) { const [id, flag] = paramsRequiredFetched[param_name]; requiredInput[id] = { - value, + value: type === "string" ? quote(value) : value, flag, type, placeholder: "", @@ -335,7 +326,7 @@ const CheckboxComponent = () => { } else if (paramsDropdownFetched) { const flag = paramsDropdownFetched[param_name]; dropdownInput[v4()] = { - value, + value: type === "string" ? quote(value) : value, flag, type, placeholder: "", @@ -363,11 +354,11 @@ const CheckboxComponent = () => { return ( { - if (checked === true) { + if (checked) { handleCheckboxChange(); } else { dispatch({ @@ -496,7 +487,8 @@ const EditorValue = ({
- { if (text) { dispatch({ @@ -507,11 +499,7 @@ const EditorValue = ({ }); } }} - hoverTip="Copy" - clickTip="copied" - > - {editorValue} - + /> { const onFocus = () => { const element = document.getElementById("memory-limit"); - element && element.focus(); + element?.focus(); }; const onSelect = () => { @@ -615,7 +603,7 @@ const AdvancedConfiguration = () => { event.preventDefault(); }} isHorizontal - aria-invalid={errors && errors[config.name] ? "true" : "false"} + aria-invalid={errors?.[config.name] ? "true" : "false"} style={{ marginBottom: "0.5em", }} @@ -625,9 +613,7 @@ const AdvancedConfiguration = () => { type="text" aria-label="advanced configuration" value={advancedConfig[config.name]} - validated={ - errors && errors[config.name] ? "error" : "default" - } + validated={errors?.[config.name] ? "error" : "default"} onChange={(_event, value: string) => { dispatch({ type: Types.AdvancedConfiguration, diff --git a/src/components/Common/index.tsx b/src/components/Common/index.tsx index adc755fca..99d79496c 100644 --- a/src/components/Common/index.tsx +++ b/src/components/Common/index.tsx @@ -14,6 +14,7 @@ import { Hint, MenuToggle, TextInput, + ClipboardCopy, } from "@patternfly/react-core"; import { CubesIcon, SearchIcon } from "../Icons"; import { Alert, Popover, Spin, Typography } from "antd"; @@ -306,3 +307,46 @@ export const ErrorAlert = ({ /> ); }; + +export const ClipboardCopyFixed = ({ + value, + onChange, +}: { + value: string; + onChange?: (_event: any, text?: string | number) => void; +}) => { + const handleCopy = async (_event: any, text: string) => { + if (!text) { + console.warn("No text provided to copy."); + return; + } + + if (navigator.clipboard) { + try { + await navigator.clipboard.writeText(text.toString()); + } catch (error) { + alert("Failed to copy text to clipboard. Please try again."); + } + } else { + console.warn( + "Clipboard API not found. This copy function will not work. This is likely because you're using an", + "unsupported browser or you're not using HTTPS.", + ); + alert( + "Clipboard API is not supported in your browser. Please use a supported browser or enable HTTPS.", + ); + } + }; + + return ( + handleCopy(event, value)} + onChange={onChange} + > + {value} + + ); +}; diff --git a/src/components/SinglePlugin/PluginCatalogComponents.tsx b/src/components/SinglePlugin/PluginCatalogComponents.tsx index cd658e77e..4f6781a6f 100644 --- a/src/components/SinglePlugin/PluginCatalogComponents.tsx +++ b/src/components/SinglePlugin/PluginCatalogComponents.tsx @@ -8,7 +8,6 @@ import { Tabs, TabTitleText, Tab, - ClipboardCopy, CodeBlock, CodeBlockCode, Dropdown, @@ -29,6 +28,7 @@ import { PluginMeta, Plugin, PluginInstance } from "@fnndsc/chrisapi"; import { useNavigate } from "react-router"; import PluginImg from "../../assets/brainy-pointer.png"; import { Link } from "react-router-dom"; +import { ClipboardCopyFixed } from "../Common"; export const HeaderComponent = ({ currentPluginMeta, @@ -424,28 +424,6 @@ export const HeaderSidebar = ({ currentPluginMeta: PluginMeta; removeEmail: (authors: string[]) => string[]; }) => { - const handleCopy = async (_event: any, text: string) => { - if (!text) { - console.warn("No text provided to copy."); - return; - } - - if (navigator.clipboard) { - try { - await navigator.clipboard.writeText(text.toString()); - } catch (error) { - alert("Failed to copy text to clipboard. Please try again."); - } - } else { - console.warn( - "Clipboard API not found. This copy function will not work. This is likely because you're using an", - "unsupported browser or you're not using HTTPS.", - ); - alert( - "Clipboard API is not supported in your browser. Please use a supported browser or enable HTTPS.", - ); - } - }; return (
@@ -454,21 +432,11 @@ export const HeaderSidebar = ({ install this plugin.

- - handleCopy( - event, - parameterPayload?.url - ? parameterPayload.url - : "Fetching the url...", - ) + - {parameterPayload?.url ? parameterPayload.url : "Fetching the url..."} - + />

Repository