import { useBoolean } from "@uifabric/react-hooks"; import { IDropdownOption, IImageProps, Image, Stack, Text } from "office-ui-fabric-react"; import React, { FunctionComponent, useState } from "react"; import AddPropertyIcon from "../../../../images/Add-property.svg"; import Explorer from "../../Explorer"; import StoredProcedure from "../../Tree/StoredProcedure"; import { GenericRightPaneComponent, GenericRightPaneProps, } from "../GenericRightPaneComponent/GenericRightPaneComponent"; import { InputParameter } from "./InputParameter"; interface ExecuteSprocParamsPaneProps { explorer: Explorer; storedProcedure: StoredProcedure; closePanel: () => void; } const imageProps: IImageProps = { width: 20, height: 30, }; interface UnwrappedExecuteSprocParam { key: string; text: string; } export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPaneProps> = ({ explorer, storedProcedure, closePanel, }: ExecuteSprocParamsPaneProps): JSX.Element => { const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false); const [paramKeyValues, setParamKeyValues] = useState<UnwrappedExecuteSprocParam[]>([{ key: "string", text: "" }]); const [partitionValue, setPartitionValue] = useState<string>(); // Defaulting to undefined here is important. It is not the same partition key as "" const [selectedKey, setSelectedKey] = React.useState<IDropdownOption>({ key: "string", text: "" }); const [formError, setFormError] = useState<string>(""); const [formErrorsDetails, setFormErrorsDetails] = useState<string>(""); const onPartitionKeyChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => { setSelectedKey(item); }; const genericPaneProps: GenericRightPaneProps = { container: explorer, formError: formError, formErrorDetail: formErrorsDetails, id: "executesprocparamspane", isExecuting: isLoading, title: "Input parameters", submitButtonText: "Execute", onClose: () => closePanel(), onSubmit: () => submit(), }; const validateUnwrappedParams = (): boolean => { const unwrappedParams: UnwrappedExecuteSprocParam[] = paramKeyValues; for (let i = 0; i < unwrappedParams.length; i++) { const { key: paramType, text: paramValue } = unwrappedParams[i]; if (paramType === "custom" && (paramValue === "" || paramValue === undefined)) { return false; } } return true; }; const setInvalidParamError = (invalidParam: string): void => { setFormError(`Invalid param specified: ${invalidParam}`); setFormErrorsDetails(`Invalid param specified: ${invalidParam} is not a valid literal value`); }; const submit = (): void => { const wrappedSprocParams: UnwrappedExecuteSprocParam[] = paramKeyValues; const { key: partitionKey } = selectedKey; if (partitionKey === "custom" && (partitionValue === "" || partitionValue === undefined)) { setInvalidParamError(partitionValue); return; } if (!validateUnwrappedParams()) { setInvalidParamError(""); return; } setLoadingTrue(); const sprocParams = wrappedSprocParams && wrappedSprocParams.map((sprocParam) => { if (sprocParam.key === "custom") { return JSON.parse(sprocParam.text); } return sprocParam.text; }); storedProcedure.execute(sprocParams, partitionKey === "custom" ? JSON.parse(partitionValue) : partitionValue); setLoadingFalse(); closePanel(); }; const deleteParamAtIndex = (indexToRemove: number): void => { const cloneParamKeyValue = [...paramKeyValues]; cloneParamKeyValue.splice(indexToRemove, 1); setParamKeyValues(cloneParamKeyValue); }; const addNewParamAtIndex = (indexToAdd: number): void => { const cloneParamKeyValue = [...paramKeyValues]; cloneParamKeyValue.splice(indexToAdd, 0, { key: "string", text: "" }); setParamKeyValues(cloneParamKeyValue); }; const paramValueChange = (value: string, indexOfInput: number): void => { const cloneParamKeyValue = [...paramKeyValues]; cloneParamKeyValue[indexOfInput].text = value; setParamKeyValues(cloneParamKeyValue); }; const paramKeyChange = ( _event: React.FormEvent<HTMLDivElement>, selectedParam: IDropdownOption, indexOfParam: number ): void => { const cloneParamKeyValue = [...paramKeyValues]; cloneParamKeyValue[indexOfParam].key = selectedParam.key.toString(); setParamKeyValues(cloneParamKeyValue); }; const addNewParamAtLastIndex = (): void => { const cloneParamKeyValue = [...paramKeyValues]; cloneParamKeyValue.splice(cloneParamKeyValue.length, 0, { key: "string", text: "" }); setParamKeyValues(cloneParamKeyValue); }; return ( <GenericRightPaneComponent {...genericPaneProps}> <div className="panelFormWrapper"> <div className="panelMainContent"> <InputParameter dropdownLabel="Key" inputParameterTitle="Partition key value" inputLabel="Value" isAddRemoveVisible={false} onParamValueChange={(_event, newInput?: string) => { setPartitionValue(newInput); }} onParamKeyChange={onPartitionKeyChange} paramValue={partitionValue} selectedKey={selectedKey.key} /> {paramKeyValues.map((paramKeyValue, index) => ( <InputParameter key={paramKeyValue && paramKeyValue.text + index} dropdownLabel={!index && "Key"} inputParameterTitle={!index && "Enter input parameters (if any)"} inputLabel={!index && "Param"} isAddRemoveVisible={true} onDeleteParamKeyPress={() => deleteParamAtIndex(index)} onAddNewParamKeyPress={() => addNewParamAtIndex(index + 1)} onParamValueChange={(event, newInput?: string) => { paramValueChange(newInput, index); }} onParamKeyChange={(event: React.FormEvent<HTMLDivElement>, selectedParam: IDropdownOption) => { paramKeyChange(event, selectedParam, index); }} paramValue={paramKeyValue && paramKeyValue.text} selectedKey={paramKeyValue && paramKeyValue.key} /> ))} <Stack horizontal onClick={addNewParamAtLastIndex}> <Image {...imageProps} src={AddPropertyIcon} alt="Add param" /> <Text className="addNewParamStyle">Add New Param</Text> </Stack> </div> </div> </GenericRightPaneComponent> ); };