Skip to content

Commit

Permalink
feat: Create a common clipboard copy component
Browse files Browse the repository at this point in the history
  • Loading branch information
PintoGideon committed Jun 14, 2024
1 parent af4e33f commit 6dc7f78
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 103 deletions.
118 changes: 52 additions & 66 deletions src/components/AddNode/GuidedConfig.tsx
Original file line number Diff line number Diff line change
@@ -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 = [
{
Expand Down Expand Up @@ -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(
{
Expand All @@ -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);
Expand All @@ -295,47 +296,37 @@ 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: "",
};
} else if (paramsDropdownFetched) {
const flag = paramsDropdownFetched[param_name];
dropdownInput[v4()] = {
value,
value: type === "string" ? quote(value) : value,
flag,
type,
placeholder: "",
Expand Down Expand Up @@ -363,11 +354,11 @@ const CheckboxComponent = () => {

return (
<Checkbox
isChecked={showPreviousRun ? true : false}
isChecked={showPreviousRun ?? false}
id="fill-parameters"
label="Fill the form using a latest run of this plugin"
onChange={(_event, checked) => {
if (checked === true) {
if (checked) {
handleCheckboxChange();
} else {
dispatch({
Expand Down Expand Up @@ -496,7 +487,8 @@ const EditorValue = ({
<div style={{ width: "100%" }} className="autogenerated__text">
<Grid hasGutter={true}>
<GridItem span={12}>
<ClipboardCopy
<ClipboardCopyFixed
value={editorValue}
onChange={(_event, text?: string | number) => {
if (text) {
dispatch({
Expand All @@ -507,11 +499,7 @@ const EditorValue = ({
});
}
}}
hoverTip="Copy"
clickTip="copied"
>
{editorValue}
</ClipboardCopy>
/>
</GridItem>
<GridItem span={2}>
<Tooltip
Expand Down Expand Up @@ -578,7 +566,7 @@ const AdvancedConfiguration = () => {

const onFocus = () => {
const element = document.getElementById("memory-limit");
element && element.focus();
element?.focus();
};

const onSelect = () => {
Expand Down Expand Up @@ -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",
}}
Expand All @@ -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,
Expand Down
44 changes: 44 additions & 0 deletions src/components/Common/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 (
<ClipboardCopy
isReadOnly
hoverTip="Copy"
clickTip="Copied"
onCopy={(event) => handleCopy(event, value)}
onChange={onChange}
>
{value}
</ClipboardCopy>
);
};
42 changes: 5 additions & 37 deletions src/components/SinglePlugin/PluginCatalogComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
Tabs,
TabTitleText,
Tab,
ClipboardCopy,
CodeBlock,
CodeBlockCode,
Dropdown,
Expand All @@ -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,
Expand Down Expand Up @@ -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 (
<div className="plugin-body-side-col">
<div className="plugin-body-detail-section">
Expand All @@ -454,21 +432,11 @@ export const HeaderSidebar = ({
install this plugin.
</p>

<ClipboardCopy
isReadOnly
hoverTip="Copy"
clickTip="Copied"
onCopy={(event) =>
handleCopy(
event,
parameterPayload?.url
? parameterPayload.url
: "Fetching the url...",
)
<ClipboardCopyFixed
value={
parameterPayload?.url ? parameterPayload.url : "Fetching the url..."
}
>
{parameterPayload?.url ? parameterPayload.url : "Fetching the url..."}
</ClipboardCopy>
/>
</div>
<div className="plugin-body-detail-section">
<h4>Repository</h4>
Expand Down

0 comments on commit 6dc7f78

Please sign in to comment.