Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/candidate-9.2.x' into candidate-…
Browse files Browse the repository at this point in the history
…9.4.x

Signed-off-by: Jake Smith <[email protected]>
  • Loading branch information
jakesmith committed Apr 18, 2024
2 parents eac4d54 + 43895b5 commit cae6bce
Show file tree
Hide file tree
Showing 20 changed files with 198 additions and 122 deletions.
4 changes: 2 additions & 2 deletions esp/src/src-react/components/DataPatterns.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, mergeStyleSets, ScrollablePane, ScrollbarVisibility, Sticky, StickyPositionType } from "@fluentui/react";
import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, IDropdownOption, mergeStyleSets, ScrollablePane, ScrollbarVisibility, Sticky, StickyPositionType } from "@fluentui/react";
import nlsHPCC from "src/nlsHPCC";
import { DPWorkunit } from "src/DataPatterns/DPWorkunit";
import { Report } from "src/DataPatterns/Report";
Expand Down Expand Up @@ -87,7 +87,7 @@ export const DataPatterns: React.FunctionComponent<DataPatternsProps> = ({
className={dpStyles.inlineDropdown}
required={true}
selectedKey={targetCluster}
onChange={(ev, row) => {
onChange={(ev, row: IDropdownOption) => {
setTargetCluster(row.key as string);
}}
/>
Expand Down
2 changes: 1 addition & 1 deletion esp/src/src-react/components/Workunits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const FilterFields: Fields = {
"Wuid": { type: "string", label: nlsHPCC.WUID, placeholder: "W20200824-060035" },
"Owner": { type: "string", label: nlsHPCC.Owner, placeholder: nlsHPCC.jsmi },
"Jobname": { type: "string", label: nlsHPCC.JobName, placeholder: nlsHPCC.log_analysis_1 },
"Cluster": { type: "target-cluster", label: nlsHPCC.Cluster, placeholder: "" },
"Cluster": { type: "target-cluster", label: nlsHPCC.Cluster, placeholder: "", multiSelect: true },
"State": { type: "workunit-state", label: nlsHPCC.State, placeholder: "" },
"ECL": { type: "string", label: nlsHPCC.ECL, placeholder: nlsHPCC.dataset },
"LogicalFile": { type: "string", label: nlsHPCC.LogicalFile, placeholder: nlsHPCC.somefile },
Expand Down
6 changes: 3 additions & 3 deletions esp/src/src-react/components/forms/AddBinding.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { DefaultButton, PrimaryButton, TextField, } from "@fluentui/react";
import { DefaultButton, IDropdownOption, PrimaryButton, TextField, } from "@fluentui/react";
import { scopedLogger } from "@hpcc-js/util";
import { useForm, Controller } from "react-hook-form";
import { EsdlDefinitionsTextField, EsdlEspProcessesTextField } from "./Fields";
Expand Down Expand Up @@ -76,7 +76,7 @@ export const AddBindingForm: React.FunctionComponent<AddBindingFormProps> = ({
fieldState: { error }
}) => <EsdlEspProcessesTextField
key={fieldName}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
onChange(option.key);
}}
required={true}
Expand Down Expand Up @@ -108,7 +108,7 @@ export const AddBindingForm: React.FunctionComponent<AddBindingFormProps> = ({
fieldState: { error }
}) => <EsdlDefinitionsTextField
key={fieldName}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
onChange(option.key);
}}
required={true}
Expand Down
4 changes: 2 additions & 2 deletions esp/src/src-react/components/forms/AddPermission.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { DefaultButton, MessageBar, MessageBarType, PrimaryButton, TextField, } from "@fluentui/react";
import { DefaultButton, IDropdownOption, MessageBar, MessageBarType, PrimaryButton, TextField, } from "@fluentui/react";
import { scopedLogger } from "@hpcc-js/util";
import { useForm, Controller } from "react-hook-form";
import nlsHPCC from "src/nlsHPCC";
Expand Down Expand Up @@ -82,7 +82,7 @@ export const AddPermissionForm: React.FunctionComponent<AddPermissionFormProps>
required={true}
label={nlsHPCC.Type}
selectedKey={value}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
onChange(option.key);
}}
errorMessage={error && error?.message}
Expand Down
4 changes: 2 additions & 2 deletions esp/src/src-react/components/forms/CopyFile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
import { Checkbox, DefaultButton, IDropdownOption, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
import { useForm, Controller } from "react-hook-form";
import nlsHPCC from "src/nlsHPCC";
import * as FileSpray from "src/FileSpray";
Expand Down Expand Up @@ -130,7 +130,7 @@ export const CopyFile: React.FunctionComponent<CopyFileProps> = ({
required={true}
selectedKey={value}
placeholder={nlsHPCC.SelectValue}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
onChange(option.key);
}}
errorMessage={error && error.message}
Expand Down
6 changes: 3 additions & 3 deletions esp/src/src-react/components/forms/DesprayFile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
import { Checkbox, DefaultButton, IDropdownOption, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
import { useForm, Controller } from "react-hook-form";
import { FileSpray, FileSprayService } from "@hpcc-js/comms";
import { scopedLogger } from "@hpcc-js/util";
Expand Down Expand Up @@ -151,7 +151,7 @@ export const DesprayFile: React.FunctionComponent<DesprayFileProps> = ({
required={true}
selectedKey={value}
placeholder={nlsHPCC.SelectValue}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
setDropzone(option.key as string);
setDirectory(option["path"] as string);
if (option["path"].indexOf("\\") > -1) {
Expand Down Expand Up @@ -179,7 +179,7 @@ export const DesprayFile: React.FunctionComponent<DesprayFileProps> = ({
label={nlsHPCC.IPAddress}
selectedKey={value}
placeholder={nlsHPCC.SelectValue}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
setMachine(option.key as string);
setOs(option["OS"] as number);
onChange(option.key);
Expand Down
135 changes: 100 additions & 35 deletions esp/src/src-react/components/forms/Fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ interface AsyncDropdownProps {
selectedKey?: string;
required?: boolean;
disabled?: boolean;
multiSelect?: boolean;
errorMessage?: string;
onChange?: (event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number) => void;
onChange?: (event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption | IDropdownOption[], index?: number) => void;
placeholder?: string;
className?: string;
}
Expand All @@ -93,6 +94,7 @@ const AsyncDropdown: React.FunctionComponent<AsyncDropdownProps> = ({
selectedKey,
required = false,
disabled,
multiSelect = false,
errorMessage,
onChange,
placeholder,
Expand All @@ -101,43 +103,96 @@ const AsyncDropdown: React.FunctionComponent<AsyncDropdownProps> = ({

const selOptions = React.useMemo<IDropdownOption[]>(() => {
if (options !== undefined) {
return !required ? [{ key: "", text: "" }, ...options] : options;
return !required && !multiSelect ? [{ key: "", text: "" }, ...options] : options;
}
return [];
}, [options, required]);
}, [multiSelect, options, required]);
const [selectedItem, setSelectedItem] = React.useState<IDropdownOption>();
const [selectedIdx, setSelectedIdx] = React.useState<number>();

React.useEffect(() => {
let item;
if (selectedItem?.key) {
item = selOptions?.find(row => row.key === selectedItem?.key) ?? selOptions[0];
const [selectedItems, setSelectedItems] = React.useState<IDropdownOption[]>([]);

const changeSelectedItems = React.useCallback(() => {
let items = [...selectedItems];
if (selectedKey === "") return;
const keys = selectedKey.split("|");
items = keys.map(key => { return { key: key, text: key }; });
if (!items.length) return;
if (items.map(item => item.key).join("|") === selectedKey) {
// do nothing, unless
if (!selectedItems.length) {
setSelectedItems(items);
}
} else {
item = selOptions?.find(row => row.key === selectedKey) ?? selOptions[0];
setSelectedItems(items);
}
if (!item) return;
if (item.key === selectedKey) {
// do nothing, unless
if (!selectedItem) {
}, [selectedKey, selectedItems]);

React.useEffect(() => {
// only on mount, pre-populate selectedItems from url
if (multiSelect) {
changeSelectedItems();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

React.useEffect(() => {
if (multiSelect) {
if (!selectedItems.length) return;
changeSelectedItems();
} else {
let item;
if (selectedItem?.key) {
item = selOptions?.find(row => row.key === selectedItem?.key) ?? selOptions[0];
} else {
item = selOptions?.find(row => row.key === selectedKey) ?? selOptions[0];
}
if (!item) return;
if (item.key === selectedKey) {
// do nothing, unless
if (!selectedItem) {
setSelectedItem(item);
setSelectedIdx(selOptions.indexOf(item));
}
} else {
setSelectedItem(item);
setSelectedIdx(selOptions.indexOf(item));
}
} else {
setSelectedItem(item);
setSelectedIdx(selOptions.indexOf(item));
}
}, [selectedKey, selOptions, selectedItem]);
}, [changeSelectedItems, multiSelect, selectedKey, selOptions, selectedItem, selectedItems]);

React.useEffect(() => {
if (!selectedItem || selectedItem?.key === selectedKey) return;
if (selectedItem !== undefined) {
onChange(undefined, selectedItem, selectedIdx);
if (multiSelect) {
if (!selectedItems.length && selectedKey === "") return;
if (selectedItems.map(item => item.key).join("|") === selectedKey) return;
onChange(undefined, selectedItems, null);
} else {
if (!selectedItem || selectedItem?.key === selectedKey) return;
if (selectedItem !== undefined) {
onChange(undefined, selectedItem, selectedIdx);
}
}
}, [onChange, selectedItem, selectedIdx, selectedKey]);

return options === undefined ?
<DropdownBase label={label} dropdownWidth="auto" options={[]} placeholder={nlsHPCC.loadingMessage} disabled={true} /> :
<DropdownBase label={label} dropdownWidth="auto" options={selOptions} selectedKey={selectedItem?.key} onChange={(_, item: IDropdownOption) => setSelectedItem(item)} placeholder={placeholder} disabled={disabled} required={required} errorMessage={errorMessage} className={className} />;
}, [onChange, multiSelect, selectedItem, selectedIdx, selectedKey, selectedItems]);

if (multiSelect) {
return options === undefined ?
<DropdownBase label={label} multiSelect dropdownWidth="auto" options={[]} placeholder={nlsHPCC.loadingMessage} disabled={true} /> :
<DropdownBase label={label} multiSelect dropdownWidth="auto" options={selOptions} selectedKeys={selectedItems.map(item => item.key as string)} onChange={
(_, item: IDropdownOption) => {
if (item) {
let selected = selectedItems.filter(i => i.key !== item.key);
if (item.selected) {
selected = [...selectedItems, item];
}
setSelectedItems(selected);
}
}
} placeholder={placeholder} disabled={disabled} required={required} errorMessage={errorMessage} className={className} />;
} else {
return options === undefined ?
<DropdownBase label={label} dropdownWidth="auto" options={[]} placeholder={nlsHPCC.loadingMessage} disabled={true} /> :
<DropdownBase label={label} dropdownWidth="auto" options={selOptions} selectedKey={selectedItem?.key} onChange={(_, item: IDropdownOption) => setSelectedItem(item)} placeholder={placeholder} disabled={disabled} required={required} errorMessage={errorMessage} className={className} />;
}
};

interface DropdownMultiProps {
Expand Down Expand Up @@ -286,6 +341,7 @@ interface QueriesActiveStateField extends BaseField {

interface TargetClusterField extends BaseField {
type: "target-cluster";
multiSelect?: boolean;
value?: string;
}

Expand Down Expand Up @@ -992,7 +1048,9 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
text: state
};
})}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row) => {
onChange(fieldID, row.key);
}}
placeholder={field.placeholder}
/>
});
Expand Down Expand Up @@ -1101,8 +1159,15 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
label: field.label,
field: <TargetClusterTextField
key={fieldID}
multiSelect={field.multiSelect}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row) => {
if (field.multiSelect) {
onChange(fieldID, (row as IDropdownOption[]).map(i => i.key).join("|"));
} else {
onChange(fieldID, (row as IDropdownOption).key);
}
}}
placeholder={field.placeholder}
/>
});
Expand All @@ -1115,7 +1180,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
field: <TargetDropzoneTextField
key={fieldID}
selectedKey={field.value}
onChange={(ev, row) => {
onChange={(ev, row: IDropdownOption) => {
onChange(fieldID, row.key);
setDropzone(row.key as string);
}}
Expand All @@ -1131,7 +1196,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
field: <TargetServerTextLinkedField
key={fieldID}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
setSetDropzone={_ => setDropzone = _}
/>
Expand All @@ -1146,7 +1211,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
key={fieldID}
required={field.required}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1161,7 +1226,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
username={field.username}
required={field.required}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1176,7 +1241,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
groupname={field.groupname}
required={field.required}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1190,7 +1255,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
key={fieldID}
required={field.required}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1203,7 +1268,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
field: <TargetDfuSprayQueueTextField
key={fieldID}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1216,7 +1281,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
field: <EsdlEspProcessesTextField
key={fieldID}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand All @@ -1229,7 +1294,7 @@ export function createInputs(fields: Fields, onChange?: (id: string, newValue: a
field: <EsdlDefinitionsTextField
key={fieldID}
selectedKey={field.value}
onChange={(ev, row) => onChange(fieldID, row.key)}
onChange={(ev, row: IDropdownOption) => onChange(fieldID, row.key)}
placeholder={field.placeholder}
/>
});
Expand Down
4 changes: 2 additions & 2 deletions esp/src/src-react/components/forms/GroupAddUser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { DefaultButton, MessageBar, MessageBarType, PrimaryButton, } from "@fluentui/react";
import { DefaultButton, IDropdownOption, MessageBar, MessageBarType, PrimaryButton, } from "@fluentui/react";
import { scopedLogger } from "@hpcc-js/util";
import { useForm, Controller } from "react-hook-form";
import nlsHPCC from "src/nlsHPCC";
Expand Down Expand Up @@ -83,7 +83,7 @@ export const GroupAddUserForm: React.FunctionComponent<GroupAddUserProps> = ({
required={true}
label={nlsHPCC.Username}
selectedKey={value}
onChange={(evt, option) => {
onChange={(evt, option: IDropdownOption) => {
onChange(option.key);
}}
errorMessage={error && error?.message}
Expand Down
Loading

0 comments on commit cae6bce

Please sign in to comment.