mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
- 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.
198 lines
6.8 KiB
TypeScript
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;
|