Files
oneuptime/Common/UI/Components/Workflow/ComponentValuePickerModal.tsx
Simon Larsen ebd14dd497 Refactor import paths in Workflow components to use relative paths from Types directory
- Updated import statements in ComponentSettingsModal, ComponentValuePickerModal, ComponentsModal, DocumentationViewer, RunForm, RunModal, Utils, VariableModal, Workflow, WorkflowStatus, Config, EntityFieldType, and various API utility files to reflect the new directory structure.
- Ensured all imports from "Common/Types" are now sourced from "../../../Types" to maintain consistency and improve module resolution.
2025-05-21 14:02:32 +01:00

198 lines
6.8 KiB
TypeScript

import ErrorMessage from "../ErrorMessage/ErrorMessage";
import Input from "../Input/Input";
import Modal, { ModalWidth } from "../Modal/Modal";
import Pill from "../Pill/Pill";
import { Black } from "../../../Types/BrandColors";
import { NodeDataProp, ReturnValue } from "../../../Types/Workflow/Component";
import React, {
FunctionComponent,
ReactElement,
useEffect,
useState,
} from "react";
export interface ComponentProps {
onClose: () => void;
onSave: (componentValueId: string) => void;
components: Array<NodeDataProp>;
}
const ComponentValuePickerModal: FunctionComponent<ComponentProps> = (
props: ComponentProps,
): ReactElement => {
const [selectedReturnValue, setSelectedReturnValue] =
useState<ReturnValue | null>(null);
const [selectedComponent, setSelectedComponent] =
useState<NodeDataProp | null>(null);
const [searchedComponents, setSearchedComponents] = useState<
Array<NodeDataProp>
>([]);
const [searchText, setSearchText] = useState<string>("");
useEffect(() => {
setSearchedComponents(searchReturnValues(props.components, searchText));
}, [props.components, searchText]);
type SearchReturnValuesFunction = (
components: Array<NodeDataProp>,
searchText: string,
) => Array<NodeDataProp>;
const searchReturnValues: SearchReturnValuesFunction = (
components: Array<NodeDataProp>,
searchText: string,
): Array<NodeDataProp> => {
if (!searchText) {
return components;
}
const searched: Array<NodeDataProp> = [];
for (const component of components) {
if (
component.metadata.title.includes(searchText) ||
component.metadata.description.includes(searchText)
) {
searched.push(component);
continue;
}
for (const returnVal of component.metadata.returnValues) {
if (
returnVal.name.includes(searchText) ||
returnVal.description.includes(searchText)
) {
searched.push(component);
break;
}
}
}
return searched;
};
return (
<Modal
modalWidth={ModalWidth.Large}
title={"Select return value from another component"}
description={
"Select a return value from the component this component is connected to."
}
onClose={props.onClose}
disableSubmitButton={!selectedReturnValue}
onSubmit={() => {
if (!selectedReturnValue) {
return props.onClose();
}
if (!selectedComponent) {
return props.onClose();
}
props.onSave(
`{{local.components.${selectedComponent.id}.returnValues.${selectedReturnValue.id}}}`,
);
}}
>
<div>
{props.components && props.components.length > 0 && (
<div className="p-2">
<Input
placeholder="Search..."
onChange={(value: string) => {
setSearchText(value);
}}
/>
</div>
)}
<div className="max-h-96 mt-5 mb-5 overflow-y-auto">
{props.components.length === 0 ? (
<ErrorMessage message={"No components in this workflow."} />
) : (
<></>
)}
{props.components.length > 0 &&
searchText &&
searchedComponents.length === 0 ? (
<ErrorMessage message={"No components match your search"} />
) : (
<></>
)}
{searchedComponents &&
searchedComponents.length > 0 &&
searchedComponents.map(
(component: NodeDataProp, i: number): ReactElement => {
return (
<div className="p-3 pl-1" key={`component-${i}`}>
<h2 className="text-base font-medium text-gray-500">
{component.metadata.title} ({component.id})
</h2>
<p className="text-sm font-medium text-gray-400">
{component.metadata.description}
</p>
{component.metadata.returnValues &&
component.metadata.returnValues.length === 0 && (
<ErrorMessage message="This component does not have any return values." />
)}
{component.metadata.returnValues &&
component.metadata.returnValues.map(
(returnValue: ReturnValue, i: number) => {
const isSelected: boolean = Boolean(
selectedComponent &&
component.id === selectedComponent.id &&
selectedReturnValue &&
selectedReturnValue.id === returnValue.id,
);
return (
<div
key={i}
onClick={() => {
setSelectedComponent(component);
setSelectedReturnValue(returnValue);
}}
className={`cursor-pointer mt-2 mb-2 relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-6 py-5 shadow-sm focus-within:ring-2 focus-within:ring-pink-500 focus-within:ring-offset-2 hover:border-gray-400 ${
isSelected ? "ring ring-indigo-500" : ""
}`}
>
<div className="min-w-0 flex-1 flex justify-between">
<div className="focus:outline-none">
<span
className="absolute inset-0"
aria-hidden="true"
></span>
<p className="text-sm font-medium text-gray-900">
{returnValue.name}{" "}
<span className="text-gray-500 font-normal">
(ID: {returnValue.id})
</span>
</p>
<p className="truncate text-sm text-gray-500">
{returnValue.description}
</p>
</div>
<div>
<Pill color={Black} text={returnValue.type} />
</div>
</div>
</div>
);
},
)}
</div>
);
},
)}
</div>
</div>
</Modal>
);
};
export default ComponentValuePickerModal;