소스 검색

HPCC-26362 React MessageBox

Common up Modal code.

Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
Gordon Smith 3 년 전
부모
커밋
fd698186ce
38개의 변경된 파일1972개의 추가작업 그리고 2514개의 파일을 삭제
  1. 1 1
      esp/src/src-react/components/DFUWorkunitDetails.tsx
  2. 1 1
      esp/src/src-react/components/Frame.tsx
  3. 1 1
      esp/src/src-react/components/Metrics.tsx
  4. 26 41
      esp/src/src-react/components/MetricsOptions.tsx
  5. 1 1
      esp/src/src-react/components/PackageMapDetails.tsx
  6. 1 1
      esp/src/src-react/components/PackageMapPartDetails.tsx
  7. 2 2
      esp/src/src-react/components/PackageMapParts.tsx
  8. 1 1
      esp/src/src-react/components/PackageMaps.tsx
  9. 1 1
      esp/src/src-react/components/QueryDetails.tsx
  10. 1 1
      esp/src/src-react/components/QueryErrors.tsx
  11. 1 1
      esp/src/src-react/components/QueryLogicalFiles.tsx
  12. 1 1
      esp/src/src-react/components/Title.tsx
  13. 1 1
      esp/src/src-react/components/WorkunitDetails.tsx
  14. 1 1
      esp/src/src-react/components/Workunits.tsx
  15. 101 132
      esp/src/src-react/components/forms/AddPackageMap.tsx
  16. 109 144
      esp/src/src-react/components/forms/AddPackageMapPart.tsx
  17. 122 148
      esp/src/src-react/components/forms/CopyFile.tsx
  18. 130 156
      esp/src/src-react/components/forms/DesprayFile.tsx
  19. 21 106
      esp/src/src-react/components/forms/Filter.tsx
  20. 97 134
      esp/src/src-react/components/forms/PublishQuery.tsx
  21. 32 68
      esp/src/src-react/components/forms/RenameFile.tsx
  22. 67 103
      esp/src/src-react/components/forms/ReplicateFile.tsx
  23. 72 109
      esp/src/src-react/components/forms/SlaveLogs.tsx
  24. 179 216
      esp/src/src-react/components/forms/ZAPDialog.tsx
  25. 43 80
      esp/src/src-react/components/forms/landing-zone/AddFileForm.tsx
  26. 112 137
      esp/src/src-react/components/forms/landing-zone/BlobImportForm.tsx
  27. 172 197
      esp/src/src-react/components/forms/landing-zone/DelimitedImportForm.tsx
  28. 93 116
      esp/src/src-react/components/forms/landing-zone/FileListForm.tsx
  29. 113 138
      esp/src/src-react/components/forms/landing-zone/FixedImportForm.tsx
  30. 138 163
      esp/src/src-react/components/forms/landing-zone/JsonImportForm.tsx
  31. 119 144
      esp/src/src-react/components/forms/landing-zone/VariableImportForm.tsx
  32. 138 163
      esp/src/src-react/components/forms/landing-zone/XmlImportForm.tsx
  33. 1 1
      esp/src/src-react/hooks/file.ts
  34. 1 1
      esp/src/src-react/hooks/logging.ts
  35. 1 1
      esp/src/src-react/hooks/workunit.ts
  36. 1 1
      esp/src/src-react/index.tsx
  37. 69 0
      esp/src/src-react/layouts/MessageBox.tsx
  38. 1 1
      esp/src/src-react/util/history.ts

+ 1 - 1
esp/src/src-react/components/DFUWorkunitDetails.tsx

@@ -12,7 +12,7 @@ import { ShortVerticalDivider } from "./Common";
 import { TableGroup } from "./forms/Groups";
 import { XMLSourceEditor } from "./SourceEditor";
 
-const logger = scopedLogger("src-react/components/DFUWorkunitDetails.tsx");
+const logger = scopedLogger("../components/DFUWorkunitDetails.tsx");
 
 interface DFUWorkunitDetailsProps {
     wuid: string;

+ 1 - 1
esp/src/src-react/components/Frame.tsx

@@ -9,7 +9,7 @@ import { darkTheme, lightTheme } from "../themes";
 import { DevTitle } from "./Title";
 import { MainNavigation, SubNavigation } from "./Menu";
 
-const logger = scopedLogger("src-react/components/Frame.tsx");
+const logger = scopedLogger("../components/Frame.tsx");
 
 interface DevFrameProps {
 }

+ 1 - 1
esp/src/src-react/components/Metrics.tsx

@@ -48,7 +48,7 @@ export const Metrics: React.FunctionComponent<MetricsProps> = ({
             onClick: () => {
                 setShowMetricOptions(true);
             }
-        },
+        }
     ], []);
 
     const rightButtons = React.useMemo((): ICommandBarItemProps[] => [

+ 26 - 41
esp/src/src-react/components/MetricsOptions.tsx

@@ -1,13 +1,8 @@
 import * as React from "react";
-import { IDragOptions, ContextualMenu, DialogType, Dialog, DialogFooter, DefaultButton, PrimaryButton, Checkbox, Pivot, PivotItem, TextField } from "@fluentui/react";
+import { DefaultButton, PrimaryButton, Checkbox, Pivot, PivotItem, TextField } from "@fluentui/react";
 import nlsHPCC from "src/nlsHPCC";
 import { useMetricMeta, useMetricsOptions } from "../hooks/metrics";
-
-const dragOptions: IDragOptions = {
-    moveMenuItemText: "Move",
-    closeMenuItemText: "Close",
-    menu: ContextualMenu,
-};
+import { MessageBox } from "../layouts/MessageBox";
 
 interface MetricsOptionsProps {
     show: boolean;
@@ -28,17 +23,29 @@ export const MetricsOptions: React.FunctionComponent<MetricsOptionsProps> = ({
 
     const allChecked = scopeTypes.length === options.scopeTypes.length;
 
-    return <Dialog
-        hidden={!show}
-        onDismiss={closeOptions}
-        dialogContentProps={{
-            type: DialogType.close,
-            title: nlsHPCC.Options,
-        }}
-        modalProps={{
-            isBlocking: false,
-            dragOptions,
-        }}>
+    return <MessageBox title={nlsHPCC.Options} show={show} setShow={setShow}
+        footer={<>
+            <PrimaryButton
+                text={nlsHPCC.OK}
+                onClick={() => {
+                    save();
+                    closeOptions();
+                }}
+            />
+            <DefaultButton
+                text={nlsHPCC.Cancel}
+                onClick={() => {
+                    reset();
+                    closeOptions();
+                }}
+            />
+            <DefaultButton
+                text={nlsHPCC.Defaults}
+                onClick={() => {
+                    reset(true);
+                }}
+            />
+        </>} >
         <Pivot>
             <PivotItem headerText={nlsHPCC.Metrics}>
                 <Checkbox key="all" label={nlsHPCC.All} checked={allChecked} onChange={(ev, checked) => {
@@ -86,27 +93,5 @@ export const MetricsOptions: React.FunctionComponent<MetricsOptionsProps> = ({
             <PivotItem headerText={nlsHPCC.Layout}>
             </PivotItem>
         </Pivot>
-        <DialogFooter>
-            <PrimaryButton
-                text={nlsHPCC.OK}
-                onClick={() => {
-                    save();
-                    closeOptions();
-                }}
-            />
-            <DefaultButton
-                text={nlsHPCC.Cancel}
-                onClick={() => {
-                    reset();
-                    closeOptions();
-                }}
-            />
-            <DefaultButton
-                text={nlsHPCC.Defaults}
-                onClick={() => {
-                    reset(true);
-                }}
-            />
-        </DialogFooter>
-    </Dialog>;
+    </MessageBox>;
 };

+ 1 - 1
esp/src/src-react/components/PackageMapDetails.tsx

@@ -10,7 +10,7 @@ import { PackageMapParts } from "./PackageMapParts";
 import { TableGroup } from "./forms/Groups";
 import { XMLSourceEditor } from "./SourceEditor";
 
-const logger = scopedLogger("src-react/components/PackageMapDetails.tsx");
+const logger = scopedLogger("../components/PackageMapDetails.tsx");
 
 interface PackageMapDetailsProps {
     name: string;

+ 1 - 1
esp/src/src-react/components/PackageMapPartDetails.tsx

@@ -3,7 +3,7 @@ import { scopedLogger } from "@hpcc-js/util";
 import * as WsPackageMaps from "src/WsPackageMaps";
 import { XMLSourceEditor } from "./SourceEditor";
 
-const logger = scopedLogger("src-react/components/PackageMapPartDetails.tsx");
+const logger = scopedLogger("../components/PackageMapPartDetails.tsx");
 
 interface PackageMapPartDetailsProps {
     name: string;

+ 2 - 2
esp/src/src-react/components/PackageMapParts.tsx

@@ -12,9 +12,9 @@ import { pushUrl } from "../util/history";
 import { ShortVerticalDivider } from "./Common";
 import { AddPackageMapPart } from "./forms/AddPackageMapPart";
 import { DojoGrid, selector } from "./DojoGrid";
-import { HolyGrail } from "src-react/layouts/HolyGrail";
+import { HolyGrail } from "../layouts/HolyGrail";
 
-const logger = scopedLogger("src-react/components/PackageMapParts.tsx");
+const logger = scopedLogger("../components/PackageMapParts.tsx");
 
 const defaultUIState = {
     hasSelection: false

+ 1 - 1
esp/src/src-react/components/PackageMaps.tsx

@@ -17,7 +17,7 @@ import { HolyGrail } from "../layouts/HolyGrail";
 import { ReflexContainer, ReflexElement, ReflexSplitter } from "../layouts/react-reflex";
 import { TextSourceEditor, XMLSourceEditor } from "./SourceEditor";
 
-const logger = scopedLogger("src-react/components/PackageMaps.tsx");
+const logger = scopedLogger("../components/PackageMaps.tsx");
 
 const FilterFields: Fields = {
     "Target": { type: "dropdown", label: nlsHPCC.Target, options: [], value: "*" },

+ 1 - 1
esp/src/src-react/components/QueryDetails.tsx

@@ -15,7 +15,7 @@ import { QueryLogicalFiles } from "./QueryLogicalFiles";
 import { Resources } from "./Resources";
 import { TableGroup } from "./forms/Groups";
 
-const logger = scopedLogger("src-react/components/QueryDetails.tsx");
+const logger = scopedLogger("../components/QueryDetails.tsx");
 
 interface QueryDetailsProps {
     querySet: string;

+ 1 - 1
esp/src/src-react/components/QueryErrors.tsx

@@ -9,7 +9,7 @@ import nlsHPCC from "src/nlsHPCC";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { DojoGrid } from "./DojoGrid";
 
-const logger = scopedLogger("src-react/components/QueryErrors.tsx");
+const logger = scopedLogger("../components/QueryErrors.tsx");
 
 interface QueryErrorsProps {
     querySet?: string;

+ 1 - 1
esp/src/src-react/components/QueryLogicalFiles.tsx

@@ -11,7 +11,7 @@ import { pushUrl } from "../util/history";
 import { DojoGrid, selector } from "./DojoGrid";
 import { ShortVerticalDivider } from "./Common";
 
-const logger = scopedLogger("src-react/components/QueryLogicalFiles.tsx");
+const logger = scopedLogger("../components/QueryLogicalFiles.tsx");
 
 const defaultUIState = {
     hasSelection: false

+ 1 - 1
esp/src/src-react/components/Title.tsx

@@ -4,7 +4,7 @@ import { About } from "./About";
 import { useBoolean } from "@fluentui/react-hooks";
 
 import nlsHPCC from "src/nlsHPCC";
-import { useECLWatchLogger } from "src-react/hooks/logging";
+import { useECLWatchLogger } from "../hooks/logging";
 
 const collapseMenuIcon: IIconProps = { iconName: "CollapseMenu" };
 

+ 1 - 1
esp/src/src-react/components/WorkunitDetails.tsx

@@ -27,7 +27,7 @@ import { Workflows } from "./Workflows";
 import { Metrics } from "./Metrics";
 import { WorkunitPersona } from "./controls/StateIcon";
 
-const logger = scopedLogger("src-react/components/WorkunitDetails.tsx");
+const logger = scopedLogger("../components/WorkunitDetails.tsx");
 
 interface WorkunitDetailsProps {
     wuid: string;

+ 1 - 1
esp/src/src-react/components/Workunits.tsx

@@ -14,7 +14,7 @@ import { createCopyDownloadSelection, ShortVerticalDivider } from "./Common";
 import { DojoGrid, selector } from "./DojoGrid";
 import { scopedLogger } from "@hpcc-js/util";
 
-const logger = scopedLogger("src-react/components/Workunits.tsx");
+const logger = scopedLogger("../components/Workunits.tsx");
 
 const FilterFields: Fields = {
     "Type": { type: "checkbox", label: nlsHPCC.ArchivedOnly },

+ 101 - 132
esp/src/src-react/components/forms/AddPackageMap.tsx

@@ -1,13 +1,13 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, IDropdownOption, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, IDropdownOption, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import { scopedLogger } from "@hpcc-js/util";
 import * as WsPackageMaps from "src/WsPackageMaps";
 import nlsHPCC from "src/nlsHPCC";
+import { MessageBox } from "../../layouts/MessageBox";
 import * as FormStyles from "./landing-zone/styles";
 
-const logger = scopedLogger("src-react/components/forms/AddPackageMap.tsx");
+const logger = scopedLogger("../components/forms/AddPackageMap.tsx");
 
 interface AddPackageMapValues {
     Info: string;
@@ -78,144 +78,113 @@ export const AddPackageMap: React.FunctionComponent<AddPackageMapProps> = ({
         )();
     }, [closeForm, handleSubmit, refreshTable, reset]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 620,
-            }
-        }
-    );
-
     React.useEffect(() => {
         reset({ ...defaultValues, Target: "*", Process: "*" });
     }, [reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.AddProcessMap}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.AddProcessMap} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="Info"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.PackageContent}
+                        value={value}
+                        multiline={true}
+                        rows={16}
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="Info"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.PackageContent}
-                            value={value}
-                            multiline={true}
-                            rows={16}
-                            errorMessage={error && error?.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="PackageMap"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.ID}
-                            value={value}
-                            errorMessage={error && error?.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="Target"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
-                            key={fieldName}
-                            label={nlsHPCC.Target}
-                            options={targets}
-                            selectedKey={value}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                        />}
-                />
+            <Controller
+                control={control} name="PackageMap"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.ID}
+                        value={value}
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="Target"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <Dropdown
+                        key={fieldName}
+                        label={nlsHPCC.Target}
+                        options={targets}
+                        selectedKey={value}
+                        onChange={(evt, option) => {
+                            onChange(option.key);
+                        }}
+                    />}
+            />
+            <Controller
+                control={control} name="Process"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <Dropdown
+                        key={fieldName}
+                        label={nlsHPCC.ProcessFilter}
+                        options={processes}
+                        selectedKey={value}
+                        onChange={(evt, option) => {
+                            onChange(option.key);
+                        }}
+                    />}
+            />
+            <Controller
+                control={control} name="DaliIp"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        label={nlsHPCC.RemoteDaliIP}
+                        value={value}
+                    />}
+            />
+            <div style={{ paddingTop: "15px" }}>
                 <Controller
-                    control={control} name="Process"
+                    control={control} name="Activate"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
-                            key={fieldName}
-                            label={nlsHPCC.ProcessFilter}
-                            options={processes}
-                            selectedKey={value}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                        />}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Activate} />}
                 />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="DaliIp"
+                    control={control} name="OverWrite"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.RemoteDaliIP}
-                            value={value}
-                        />}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
                 />
-                <div style={{ paddingTop: "15px" }}>
-                    <Controller
-                        control={control} name="Activate"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Activate} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="OverWrite"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
-                    />
-                </div>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </div>
+        </Stack>
+        <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
+            <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
+        </Stack>
+    </MessageBox>;
 };

+ 109 - 144
esp/src/src-react/components/forms/AddPackageMapPart.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import { scopedLogger } from "@hpcc-js/util";
 import * as WsPackageMaps from "src/WsPackageMaps";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./landing-zone/styles";
+import { MessageBox } from "../../layouts/MessageBox";
 
-const logger = scopedLogger("src-react/components/forms/AddPackageMapPart.tsx");
+const logger = scopedLogger("../components/forms/AddPackageMapPart.tsx");
 
 interface AddPackageMapPartValues {
     PartName: string;
@@ -84,157 +83,123 @@ export const AddPackageMapPart: React.FunctionComponent<AddPackageMapPartProps>
         )();
     }, [closeForm, handleSubmit, packageMap, refreshTable, reset, store, target]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 620,
-            }
-        }
-    );
-
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.AddProcessMap}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.AddProcessMap} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="PartName"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        placeholder={nlsHPCC.PartName}
+                        required={true}
+                        label={nlsHPCC.PartName}
+                        value={value}
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="Content"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.Content}
+                        value={value}
+                        multiline={true}
+                        rows={16}
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="DaliIp"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        placeholder={nlsHPCC.DaliIP}
+                        label={nlsHPCC.DaliIP}
+                        value={value}
+                    />}
+            />
+            <Controller
+                control={control} name="SourceProcess"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        placeholder={nlsHPCC.SourceProcess}
+                        label={nlsHPCC.SourceProcess}
+                        value={value}
+                    />}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
+            <div style={{ paddingTop: "15px" }}>
+                <Controller
+                    control={control} name="DeletePrevious"
+                    render={({
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DeletePrevious} />}
+                />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
+                <Controller
+                    control={control} name="AllowForeignFiles"
+                    render={({
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AllowForeignFiles} />}
+                />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="PartName"
+                    control={control} name="PreloadAllPackages"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            placeholder={nlsHPCC.PartName}
-                            required={true}
-                            label={nlsHPCC.PartName}
-                            value={value}
-                            errorMessage={error && error?.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreloadAllPackages} />}
                 />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="Content"
+                    control={control} name="UpdateSuperFiles"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.Content}
-                            value={value}
-                            multiline={true}
-                            rows={16}
-                            errorMessage={error && error?.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateSuperFiles} />}
                 />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="DaliIp"
+                    control={control} name="UpdateCloneFrom"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            placeholder={nlsHPCC.DaliIP}
-                            label={nlsHPCC.DaliIP}
-                            value={value}
-                        />}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateCloneFrom} />}
                 />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="SourceProcess"
+                    control={control} name="AppendCluster"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            placeholder={nlsHPCC.SourceProcess}
-                            label={nlsHPCC.SourceProcess}
-                            value={value}
-                        />}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AppendCluster} />}
                 />
-                <div style={{ paddingTop: "15px" }}>
-                    <Controller
-                        control={control} name="DeletePrevious"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DeletePrevious} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="AllowForeignFiles"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AllowForeignFiles} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="PreloadAllPackages"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreloadAllPackages} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="UpdateSuperFiles"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateSuperFiles} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="UpdateCloneFrom"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateCloneFrom} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="AppendCluster"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AppendCluster} />}
-                    />
-                </div>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </div>
+        </Stack>
+    </MessageBox>;
 };

+ 122 - 148
esp/src/src-react/components/forms/CopyFile.tsx

@@ -1,13 +1,13 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import { useFile } from "../../hooks/file";
 import * as FileSpray from "src/FileSpray";
+import { useFile } from "../../hooks/file";
+import { MessageBox } from "../../layouts/MessageBox";
+import { pushUrl } from "../../util/history";
 import { TargetGroupTextField } from "./Fields";
 import * as FormStyles from "./landing-zone/styles";
-import { pushUrl } from "../../util/history";
 
 interface CopyFileFormValues {
     destGroup: string;
@@ -73,14 +73,6 @@ export const CopyFile: React.FunctionComponent<CopyFileProps> = ({
         )();
     }, [closeForm, handleSubmit, logicalFile]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -95,142 +87,124 @@ export const CopyFile: React.FunctionComponent<CopyFileProps> = ({
         reset(newValues);
     }, [file, logicalFile, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.Copy}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.Copy} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Copy} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
+                        key={fieldName}
+                        label={nlsHPCC.Group}
+                        required={true}
+                        selectedKey={value}
+                        placeholder={nlsHPCC.SelectValue}
+                        onChange={(evt, option) => {
+                            onChange(option.key);
+                        }}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
-                            key={fieldName}
-                            label={nlsHPCC.Group}
-                            required={true}
-                            selectedKey={value}
-                            placeholder={nlsHPCC.SelectValue}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
+            <Controller
+                control={control} name="destLogicalName"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.TargetName}
+                        value={value}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody>
+                    <tr>
+                        <td><Controller
+                            control={control} name="overwrite"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                        /></td>
+                        <td><Controller
+                            control={control} name="replicate"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                        /></td>
+                    </tr>
+                    <tr>
+                        <td><Controller
+                            control={control} name="nosplit"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
+                        /></td>
+                        <td><Controller
+                            control={control} name="compress"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
+                        /></td>
+                    </tr>
+                    <tr>
+                        <td><Controller
+                            control={control} name="Wrap"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Wrap} />}
+                        /></td>
+                        <td><Controller
+                            control={control} name="superCopy"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.RetainSuperfileStructure} />}
+                        /></td>
+                    </tr>
+                    <tr>
+                        <td><Controller
+                            control={control} name="preserveCompression"
+                            render={({
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreserveCompression} />}
+                        /></td>
+                        <td><Controller
+                            control={control} name="ExpireDays" defaultValue={""}
+                            render={({
+                                field: { onChange, name: fieldName, value },
+                                fieldState: { error }
+                            }) => <TextField
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error.message}
+                                />}
+                            rules={{
+                                min: {
+                                    value: 1,
+                                    message: `${nlsHPCC.ValidationErrorNumberLess} 1`
+                                }
                             }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="destLogicalName"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.TargetName}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody>
-                        <tr>
-                            <td><Controller
-                                control={control} name="overwrite"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
-                            /></td>
-                            <td><Controller
-                                control={control} name="replicate"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
-                            /></td>
-                        </tr>
-                        <tr>
-                            <td><Controller
-                                control={control} name="nosplit"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
-                            /></td>
-                            <td><Controller
-                                control={control} name="compress"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
-                            /></td>
-                        </tr>
-                        <tr>
-                            <td><Controller
-                                control={control} name="Wrap"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Wrap} />}
-                            /></td>
-                            <td><Controller
-                                control={control} name="superCopy"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.RetainSuperfileStructure} />}
-                            /></td>
-                        </tr>
-                        <tr>
-                            <td><Controller
-                                control={control} name="preserveCompression"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreserveCompression} />}
-                            /></td>
-                            <td><Controller
-                                control={control} name="ExpireDays" defaultValue={""}
-                                render={({
-                                    field: { onChange, name: fieldName, value },
-                                    fieldState: { error }
-                                }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        label={nlsHPCC.ExpireDays}
-                                        value={value}
-                                        errorMessage={error && error.message}
-                                    />}
-                                rules={{
-                                    min: {
-                                        value: 1,
-                                        message: `${nlsHPCC.ValidationErrorNumberLess} 1`
-                                    }
-                                }}
-                            /></td>
-                        </tr>
-                    </tbody>
-                </table>
-            </Stack>
-
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Copy} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+                        /></td>
+                    </tr>
+                </tbody>
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 130 - 156
esp/src/src-react/components/forms/DesprayFile.tsx

@@ -1,13 +1,13 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import { useFile } from "../../hooks/file";
 import * as FileSpray from "src/FileSpray";
+import { useFile } from "../../hooks/file";
+import { MessageBox } from "../../layouts/MessageBox";
+import { pushUrl } from "../../util/history";
 import { TargetDropzoneTextField, TargetFolderTextField, TargetServerTextField } from "./Fields";
 import * as FormStyles from "./landing-zone/styles";
-import { pushUrl } from "../../util/history";
 
 interface DesprayFileFormValues {
     destGroup: string;
@@ -77,14 +77,6 @@ export const DesprayFile: React.FunctionComponent<DesprayFileProps> = ({
         )();
     }, [closeForm, handleSubmit, logicalFile, pathSep]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -99,153 +91,135 @@ export const DesprayFile: React.FunctionComponent<DesprayFileProps> = ({
         reset(newValues);
     }, [file?.Filename, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.Despray}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.Despray} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Despray} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDropzoneTextField
+                        key={fieldName}
+                        label={nlsHPCC.DropZone}
+                        required={true}
+                        selectedKey={value}
+                        placeholder={nlsHPCC.SelectValue}
+                        onChange={(evt, option) => {
+                            setDirectory(option["path"] as string);
+                            if (option["path"].indexOf("\\") > -1) {
+                                setPathSep("\\");
+                            }
+                            onChange(option.key);
+                        }}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.DropZone}`
+                }}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDropzoneTextField
-                            key={fieldName}
-                            label={nlsHPCC.DropZone}
-                            required={true}
-                            selectedKey={value}
-                            placeholder={nlsHPCC.SelectValue}
-                            onChange={(evt, option) => {
-                                setDirectory(option["path"] as string);
-                                if (option["path"].indexOf("\\") > -1) {
-                                    setPathSep("\\");
-                                }
-                                onChange(option.key);
-                            }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.DropZone}`
-                    }}
-                />
-                <Controller
-                    control={control} name="destIP"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetServerTextField
-                            key={fieldName}
-                            required={true}
-                            label={nlsHPCC.IPAddress}
-                            selectedKey={value}
-                            placeholder={nlsHPCC.SelectValue}
-                            onChange={(evt, option) => {
-                                setMachine(option.key as string);
-                                setOs(option["OS"] as number);
-                                onChange(option.key);
-                            }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="destPath"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetFolderTextField
-                            key={fieldName}
-                            label={nlsHPCC.Path}
-                            pathSepChar={pathSep}
-                            machineAddress={machine}
-                            machineDirectory={directory}
-                            machineOS={os}
-                            required={true}
-                            placeholder={nlsHPCC.SelectValue}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired,
-                    }}
-                />
-                <Controller
-                    control={control} name="targetName"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.TargetName}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="splitprefix"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.SplitPrefix}
-                            value={value}
-                        />}
-                />
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field: { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
-                        /></td>
+            <Controller
+                control={control} name="destIP"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetServerTextField
+                        key={fieldName}
+                        required={true}
+                        label={nlsHPCC.IPAddress}
+                        selectedKey={value}
+                        placeholder={nlsHPCC.SelectValue}
+                        onChange={(evt, option) => {
+                            setMachine(option.key as string);
+                            setOs(option["OS"] as number);
+                            onChange(option.key);
+                        }}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="destPath"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetFolderTextField
+                        key={fieldName}
+                        label={nlsHPCC.Path}
+                        pathSepChar={pathSep}
+                        machineAddress={machine}
+                        machineDirectory={directory}
+                        machineOS={os}
+                        required={true}
+                        placeholder={nlsHPCC.SelectValue}
+                        onChange={(evt, option) => {
+                            onChange(option.key);
+                        }}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired,
+                }}
+            />
+            <Controller
+                control={control} name="targetName"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.TargetName}
+                        value={value}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="splitprefix"
+                render={({
+                    field: { onChange, name: fieldName, value }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        label={nlsHPCC.SplitPrefix}
+                        value={value}
+                    />}
+            />
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="SingleConnection"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UseSingleConnection} />}
+                    /></td>
+                </tr>
+                    <tr>
                         <td><Controller
-                            control={control} name="SingleConnection"
+                            control={control} name="wrap"
                             render={({
                                 field: { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UseSingleConnection} />}
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreserveParts} />}
                         /></td>
-                    </tr>
-                        <tr>
-                            <td><Controller
-                                control={control} name="wrap"
-                                render={({
-                                    field: { onChange, name: fieldName, value }
-                                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.PreserveParts} />}
-                            /></td>
-                        </tr></tbody>
-                </table>
-            </Stack>
-
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Despray} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+                    </tr></tbody>
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 21 - 106
esp/src/src-react/components/forms/Filter.tsx

@@ -1,7 +1,7 @@
 import * as React from "react";
-import { getTheme, mergeStyleSets, FontWeights, IDragOptions, IIconProps, ContextualMenu, DefaultButton, PrimaryButton, IconButton, IStackStyles, Modal, Stack } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { DefaultButton, PrimaryButton, Stack } from "@fluentui/react";
 import nlsHPCC from "src/nlsHPCC";
+import { MessageBox } from "../../layouts/MessageBox";
 import { Fields, Values } from "./Fields";
 import { TableForm } from "./Forms";
 
@@ -25,109 +25,24 @@ export const Filter: React.FunctionComponent<FilterProps> = ({
 
     const closeFilter = () => setShowFilter(false);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: "Move",
-        closeMenuItemText: "Close",
-        menu: ContextualMenu,
-    };
-
-    const theme = getTheme();
-
-    const contentStyles = mergeStyleSets({
-        container: {
-            display: "flex",
-            flexFlow: "column nowrap",
-            alignItems: "stretch",
-        },
-        header: [
-            {
-                flex: "1 1 auto",
-                borderTop: `4px solid ${theme.palette.themePrimary}`,
-                display: "flex",
-                alignItems: "center",
-                fontWeight: FontWeights.semibold,
-                padding: "12px 12px 14px 24px",
-            },
-        ],
-        body: {
-            flex: "4 4 auto",
-            padding: "0 24px 24px 24px",
-            overflowY: "hidden",
-            selectors: {
-                p: { margin: "14px 0" },
-                "p:first-child": { marginTop: 0 },
-                "p:last-child": { marginBottom: 0 },
-            },
-        },
-    });
-
-    const cancelIcon: IIconProps = { iconName: "Cancel" };
-    const iconButtonStyles = {
-        root: {
-            marginLeft: "auto",
-            marginTop: "4px",
-            marginRight: "2px",
-        },
-    };
-    const buttonStackStyles: IStackStyles = {
-        root: {
-            height: "56px",
-        },
-    };
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showFilter}
-        onDismiss={closeFilter}
-        isBlocking={false}
-        containerClassName={contentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={contentStyles.header}>
-            <span id={titleId}>Filter</span>
-            <IconButton
-                styles={iconButtonStyles}
-                iconProps={cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeFilter}
+    return <MessageBox title={nlsHPCC.Filter} show={showFilter} setShow={closeFilter}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Apply} onClick={() => { setDoSubmit(true); closeFilter(); }} />
+            <DefaultButton text={nlsHPCC.Clear} onClick={() => { setDoReset(true); }} />
+        </>}>
+        <Stack>
+            <TableForm
+                fields={filterFields}
+                doSubmit={doSubmit}
+                doReset={doReset}
+                onSubmit={fields => {
+                    setDoSubmit(false);
+                    onApply(fields);
+                }}
+                onReset={() => {
+                    setDoReset(false);
+                }}
             />
-        </div>
-        <div className={contentStyles.body}>
-            <Stack>
-                <TableForm
-                    fields={filterFields}
-                    doSubmit={doSubmit}
-                    doReset={doReset}
-                    onSubmit={fields => {
-                        setDoSubmit(false);
-                        onApply(fields);
-                    }}
-                    onReset={() => {
-                        setDoReset(false);
-                    }}
-                />
-            </Stack>
-            <Stack
-                horizontal
-                horizontalAlign="space-between"
-                verticalAlign="end"
-                styles={buttonStackStyles}
-            >
-                <DefaultButton
-                    text={nlsHPCC.Clear}
-                    onClick={() => {
-                        setDoReset(true);
-                    }}
-                />
-                <PrimaryButton
-                    text={nlsHPCC.Apply}
-                    onClick={() => {
-                        setDoSubmit(true);
-                        closeFilter();
-                    }}
-                />
-            </Stack>
-        </div>
-    </Modal>;
+        </Stack>
+    </MessageBox>;
 };

+ 97 - 134
esp/src/src-react/components/forms/PublishQuery.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, PrimaryButton, TextField, } from "@fluentui/react";
 import { scopedLogger } from "@hpcc-js/util";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./landing-zone/styles";
+import { MessageBox } from "../../layouts/MessageBox";
 import { useWorkunit } from "../../hooks/workunit";
 
-const logger = scopedLogger("src-react/components/forms/PublishQuery.tsx");
+const logger = scopedLogger("../components/forms/PublishQuery.tsx");
 
 interface PublishFormValues {
     jobName: string;
@@ -64,143 +63,107 @@ export const PublishQueryForm: React.FunctionComponent<PublishFormProps> = ({
         )();
     }, [closeForm, handleSubmit, reset, workunit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 440,
-            }
-        }
-    );
-
     React.useEffect(() => {
         if (workunit) {
             reset({ ...defaultValues, jobName: workunit?.Jobname });
         }
     }, [reset, workunit]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.Publish}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox show={showForm} setShow={closeForm} title={nlsHPCC.Publish}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Publish} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Controller
+            control={control} name="jobName"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    required={true}
+                    label={nlsHPCC.JobName}
+                    value={value}
+                    errorMessage={error && error?.message}
+                />}
+            rules={{
+                required: nlsHPCC.ValidationErrorRequired
+            }}
+        />
+        <Controller
+            control={control} name="remoteDali"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.RemoteDali}
+                    value={value}
+                    errorMessage={error && error?.message}
+                />}
+        />
+        <Controller
+            control={control} name="sourceProcess"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.SourceProcess}
+                    value={value}
+                    errorMessage={error && error?.message}
+                />}
+        />
+        <Controller
+            control={control} name="comment"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.Comment}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="priority"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <Dropdown
+                    key={fieldName}
+                    label={nlsHPCC.Priority}
+                    options={[
+                        { key: "", text: nlsHPCC.None },
+                        { key: "SLA", text: nlsHPCC.SLA },
+                        { key: "Low", text: nlsHPCC.Low },
+                        { key: "High", text: nlsHPCC.High },
+                    ]}
+                    selectedKey={value}
+                    onChange={(evt, option) => {
+                        onChange(option.key);
+                    }}
+                />}
+        />
+        <div style={{ paddingTop: "15px" }}>
+            <Controller
+                control={control} name="allowForeignFiles"
+                render={({
+                    field: { onChange, name: fieldName, value }
+                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AllowForeignFiles} />}
             />
         </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="jobName"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.JobName}
-                            value={value}
-                            errorMessage={error && error?.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="remoteDali"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.RemoteDali}
-                            value={value}
-                            errorMessage={error && error?.message}
-                        />}
-                />
-                <Controller
-                    control={control} name="sourceProcess"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.SourceProcess}
-                            value={value}
-                            errorMessage={error && error?.message}
-                        />}
-                />
-                <Controller
-                    control={control} name="comment"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.Comment}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="priority"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
-                            key={fieldName}
-                            label={nlsHPCC.Priority}
-                            options={[
-                                { key: "", text: nlsHPCC.None },
-                                { key: "SLA", text: nlsHPCC.SLA },
-                                { key: "Low", text: nlsHPCC.Low },
-                                { key: "High", text: nlsHPCC.High },
-                            ]}
-                            selectedKey={value}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                        />}
-                />
-                <div style={{ paddingTop: "15px" }}>
-                    <Controller
-                        control={control} name="allowForeignFiles"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.AllowForeignFiles} />}
-                    />
-                </div>
-                <div style={{ paddingTop: "10px" }}>
-                    <Controller
-                        control={control} name="updateSuperFiles"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateSuperFiles} />}
-                    />
-                </div>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Publish} onClick={handleSubmit(onSubmit)} />
-            </Stack>
+        <div style={{ paddingTop: "10px" }}>
+            <Controller
+                control={control} name="updateSuperFiles"
+                render={({
+                    field: { onChange, name: fieldName, value }
+                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.UpdateSuperFiles} />}
+            />
         </div>
-    </Modal>;
+    </MessageBox>;
 };

+ 32 - 68
esp/src/src-react/components/forms/RenameFile.tsx

@@ -1,11 +1,10 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import { useFile } from "../../hooks/file";
 import * as FileSpray from "src/FileSpray";
-import * as FormStyles from "./landing-zone/styles";
+import { useFile } from "../../hooks/file";
+import { MessageBox } from "../../layouts/MessageBox";
 import { pushUrl } from "../../util/history";
 
 interface RenameFileFormValues {
@@ -56,77 +55,42 @@ export const RenameFile: React.FunctionComponent<RenameFileProps> = ({
         )();
     }, [closeForm, cluster, handleSubmit, logicalFile]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 440,
-            }
-        }
-    );
-
     React.useEffect(() => {
         const newValues = { ...defaultValues, dstname: logicalFile };
         reset(newValues);
     }, [file, logicalFile, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.Rename}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.Rename} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Rename} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="dstname"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.TargetName}
+                        value={value}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
+            <div style={{ paddingTop: "15px" }}>
                 <Controller
-                    control={control} name="dstname"
+                    control={control} name="overwrite"
                     render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.TargetName}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
+                        field: { onChange, name: fieldName, value }
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
                 />
-                <div style={{ paddingTop: "15px" }}>
-                    <Controller
-                        control={control} name="overwrite"
-                        render={({
-                            field: { onChange, name: fieldName, value }
-                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
-                    />
-                </div>
-            </Stack>
-
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Rename} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </div>
+        </Stack>
+    </MessageBox>;
 };

+ 67 - 103
esp/src/src-react/components/forms/ReplicateFile.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { DefaultButton, PrimaryButton, Stack, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import { useFile } from "../../hooks/file";
 import * as FileSpray from "src/FileSpray";
-import { TargetGroupTextField } from "./Fields";
-import * as FormStyles from "./landing-zone/styles";
+import { useFile } from "../../hooks/file";
+import { MessageBox } from "../../layouts/MessageBox";
 import { pushUrl } from "../../util/history";
+import { TargetGroupTextField } from "./Fields";
 
 interface ReplicateFileFormValues {
     sourceLogicalName: string;
@@ -58,108 +57,73 @@ export const ReplicateFile: React.FunctionComponent<ReplicateFileProps> = ({
         )();
     }, [closeForm, handleSubmit, logicalFile]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 440,
-            }
-        }
-    );
-
     React.useEffect(() => {
         const newValues = { ...defaultValues, sourceLogicalName: logicalFile };
         reset(newValues);
     }, [file, logicalFile, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.Rename}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
+    return <MessageBox title={nlsHPCC.Rename} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Replicate} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="sourceLogicalName"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        required={true}
+                        label={nlsHPCC.SourceLogicalFile}
+                        value={value}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
             />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="sourceLogicalName"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            required={true}
-                            label={nlsHPCC.SourceLogicalFile}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="replicateOffset"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.ReplicateOffset}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        pattern: {
-                            value: /^[0-9]+$/i,
-                            message: nlsHPCC.ValidationErrorEnterNumber
-                        }
-                    }}
-                />
-                <Controller
-                    control={control} name="cluster"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
-                            key={fieldName}
-                            label={nlsHPCC.Cluster}
-                            required={true}
-                            selectedKey={value}
-                            placeholder={nlsHPCC.SelectValue}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Cluster}`
-                    }}
-                />
-            </Stack>
-
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Replicate} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            <Controller
+                control={control} name="replicateOffset"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
+                        name={fieldName}
+                        onChange={onChange}
+                        label={nlsHPCC.ReplicateOffset}
+                        value={value}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^[0-9]+$/i,
+                        message: nlsHPCC.ValidationErrorEnterNumber
+                    }
+                }}
+            />
+            <Controller
+                control={control} name="cluster"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
+                        key={fieldName}
+                        label={nlsHPCC.Cluster}
+                        required={true}
+                        selectedKey={value}
+                        placeholder={nlsHPCC.SelectValue}
+                        onChange={(evt, option) => {
+                            onChange(option.key);
+                        }}
+                        errorMessage={error && error.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Cluster}`
+                }}
+            />
+        </Stack>
+    </MessageBox>;
 };

+ 72 - 109
esp/src/src-react/components/forms/SlaveLogs.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { DefaultButton, Dropdown, PrimaryButton, TextField, } from "@fluentui/react";
 import { scopedLogger } from "@hpcc-js/util";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./landing-zone/styles";
 import { useWorkunit } from "../../hooks/workunit";
+import { MessageBox } from "../../layouts/MessageBox";
 
-const logger = scopedLogger("src-react/components/forms/SlaveLogs.tsx");
+const logger = scopedLogger("../components/forms/SlaveLogs.tsx");
 
 interface SlaveLogsValues {
     ThorProcess: string;
@@ -60,23 +59,6 @@ export const SlaveLogs: React.FunctionComponent<SlaveLogsProps> = ({
         )();
     }, [closeForm, clusterGroup, handleSubmit, reset, thorLogDate, wuid]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 440,
-            }
-        }
-    );
-
     React.useEffect(() => {
         if (!workunit?.ThorLogList) return;
         setThorProcesses(workunit?.ThorLogList?.ThorLogInfo.map(process => {
@@ -87,94 +69,75 @@ export const SlaveLogs: React.FunctionComponent<SlaveLogsProps> = ({
         setClusterGroup(workunit?.ThorLogList?.ThorLogInfo[0].ProcessName);
     }, [workunit]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.SlaveLogs}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="ThorProcess"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
-                            key={fieldName}
-                            label={nlsHPCC.ThorProcess}
-                            options={thorProcesses}
-                            required={true}
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
+    return <MessageBox title={nlsHPCC.SlaveLogs} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Download} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Controller
+            control={control} name="ThorProcess"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <Dropdown
+                    key={fieldName}
+                    label={nlsHPCC.ThorProcess}
+                    options={thorProcesses}
+                    required={true}
+                    onChange={(evt, option) => {
+                        onChange(option.key);
                     }}
-                />
-                <Controller
-                    control={control} name="SlaveNumber"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.SlaveNumber}
-                            value={value}
-                            errorMessage={error && error.message}
-                        />}
-                    rules={{
-                        pattern: {
-                            value: /^[1-9]+$/i,
-                            message: nlsHPCC.ValidationErrorEnterNumber
-                        },
-                        min: {
-                            value: 1,
-                            message: `${nlsHPCC.ValidationErrorNumberLess} 1`
-                        },
-                        max: {
-                            value: maxThorSlaves,
-                            message: `${nlsHPCC.ValidationErrorNumberGreater} ${maxThorSlaves}`
-                        }
+                    errorMessage={error && error.message}
+                />}
+            rules={{
+                required: nlsHPCC.ValidationErrorRequired
+            }}
+        />
+        <Controller
+            control={control} name="SlaveNumber"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.SlaveNumber}
+                    value={value}
+                    errorMessage={error && error.message}
+                />}
+            rules={{
+                pattern: {
+                    value: /^[1-9]+$/i,
+                    message: nlsHPCC.ValidationErrorEnterNumber
+                },
+                min: {
+                    value: 1,
+                    message: `${nlsHPCC.ValidationErrorNumberLess} 1`
+                },
+                max: {
+                    value: maxThorSlaves,
+                    message: `${nlsHPCC.ValidationErrorNumberGreater} ${maxThorSlaves}`
+                }
+            }}
+        />
+        <Controller
+            control={control} name="FileFormat"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <Dropdown
+                    key={fieldName}
+                    label={nlsHPCC.File}
+                    options={[
+                        { key: "1", text: nlsHPCC.OriginalFile },
+                        { key: "2", text: nlsHPCC.Zip },
+                        { key: "3", text: nlsHPCC.GZip },
+                    ]}
+                    defaultSelectedKey="1"
+                    onChange={(evt, option) => {
+                        onChange(option.key);
                     }}
-                />
-                <Controller
-                    control={control} name="FileFormat"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
-                            key={fieldName}
-                            label={nlsHPCC.File}
-                            options={[
-                                { key: "1", text: nlsHPCC.OriginalFile },
-                                { key: "2", text: nlsHPCC.Zip },
-                                { key: "3", text: nlsHPCC.GZip },
-                            ]}
-                            defaultSelectedKey="1"
-                            onChange={(evt, option) => {
-                                onChange(option.key);
-                            }}
-                        />}
-                />
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Download} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+                />}
+        />
+    </MessageBox>;
 };

+ 179 - 216
esp/src/src-react/components/forms/ZAPDialog.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, PrimaryButton, TextField, } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import { scopedLogger } from "@hpcc-js/util";
 import * as WsWorkunits from "src/WsWorkunits";
-import * as FormStyles from "./landing-zone/styles";
+import { MessageBox } from "../../layouts/MessageBox";
 import nlsHPCC from "src/nlsHPCC";
 
-const logger = scopedLogger("src-react/components/forms/ZAPDialog.tsx");
+const logger = scopedLogger("../components/forms/ZAPDialog.tsx");
 
 interface ZAPDialogValues {
     ZAPFileName: string;
@@ -109,23 +108,6 @@ export const ZAPDialog: React.FunctionComponent<ZAPDialogProps> = ({
         )();
     }, [closeForm, handleSubmit, reset]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: 440,
-            }
-        }
-    );
-
     React.useEffect(() => {
         WsWorkunits.WUGetZAPInfo({ request: { WUID: wuid } }).then(response => {
             setEmailDisabled(response?.WUGetZAPInfoResponse?.EmailTo === null);
@@ -139,212 +121,193 @@ export const ZAPDialog: React.FunctionComponent<ZAPDialogProps> = ({
         }).catch(logger.error);
     }, [wuid, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.ZippedAnalysisPackage}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="ZAPFileName"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.FileName}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="Wuid"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.WUID}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="BuildVersion"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.ESPBuildVersion}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="ESPIPAddress"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.ESPNetworkAddress}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="ThorIPAddress"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.ThorNetworkAddress}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="ProblemDescription"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.Description}
-                            multiline={true}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="WhatChanged"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.History}
-                            multiline={true}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="WhereSlow"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.Timings}
-                            multiline={true}
-                            value={value}
-                        />}
-                />
-                <Controller
-                    control={control} name="Password"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.PasswordOpenZAP}
-                            value={value}
-                            type="password"
-                            canRevealPassword={true}
-                            revealPasswordAriaLabel={nlsHPCC.ShowPassword}
-                        />}
-                />
-                <div style={{ padding: "15px 0 7px 0" }}>
-                    <div>
-                        <Controller
-                            control={control} name="IncludeThorSlaveLog"
-                            render={({
-                                field: { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.IncludeSlaveLogs} />}
-                        />
-                    </div>
-                    <div style={{ paddingTop: "10px" }}>
-                        <Controller
-                            control={control} name="SendEmail"
-                            render={({
-                                field: { onChange, name: fieldName, value }
-                            }) => <Checkbox
-                                    name={fieldName}
-                                    checked={value}
-                                    onChange={onChange}
-                                    label={nlsHPCC.SendEmail}
-                                    disabled={emailDisabled}
-                                />}
-                        />
-                    </div>
-
-                </div>
-                <Controller
-                    control={control} name="EmailTo"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.EmailTo}
-                            value={value}
-                            placeholder={nlsHPCC.SeeConfigurationManager}
-                            disabled={emailDisabled}
-                        />}
-                />
-                <Controller
-                    control={control} name="EmailFrom"
-                    render={({
-                        field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.EmailFrom}
-                            value={value}
-                            placeholder={nlsHPCC.SeeConfigurationManager}
-                            disabled={emailDisabled}
-                        />}
-                />
+    return <MessageBox title={nlsHPCC.ZippedAnalysisPackage} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Controller
+            control={control} name="ZAPFileName"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.FileName}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="Wuid"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.WUID}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="BuildVersion"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.ESPBuildVersion}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="ESPIPAddress"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.ESPNetworkAddress}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="ThorIPAddress"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.ThorNetworkAddress}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="ProblemDescription"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.Description}
+                    multiline={true}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="WhatChanged"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.History}
+                    multiline={true}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="WhereSlow"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.Timings}
+                    multiline={true}
+                    value={value}
+                />}
+        />
+        <Controller
+            control={control} name="Password"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.PasswordOpenZAP}
+                    value={value}
+                    type="password"
+                    canRevealPassword={true}
+                    revealPasswordAriaLabel={nlsHPCC.ShowPassword}
+                />}
+        />
+        <div style={{ padding: "15px 0 7px 0" }}>
+            <div>
                 <Controller
-                    control={control} name="EmailSubject"
+                    control={control} name="IncludeThorSlaveLog"
                     render={({
                         field: { onChange, name: fieldName, value }
-                    }) => <TextField
-                            name={fieldName}
-                            onChange={onChange}
-                            label={nlsHPCC.EmailSubject}
-                            value={value}
-                            disabled={emailDisabled}
-                        />}
+                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.IncludeSlaveLogs} />}
                 />
+            </div>
+            <div style={{ paddingTop: "10px" }}>
                 <Controller
-                    control={control} name="EmailBody"
+                    control={control} name="SendEmail"
                     render={({
                         field: { onChange, name: fieldName, value }
-                    }) => <TextField
+                    }) => <Checkbox
                             name={fieldName}
+                            checked={value}
                             onChange={onChange}
-                            label={nlsHPCC.EmailBody}
-                            multiline={true}
-                            value={value}
+                            label={nlsHPCC.SendEmail}
                             disabled={emailDisabled}
                         />}
                 />
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Submit} onClick={handleSubmit(onSubmit)} />
-            </Stack>
+            </div>
+
         </div>
-    </Modal>;
+        <Controller
+            control={control} name="EmailTo"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.EmailTo}
+                    value={value}
+                    placeholder={nlsHPCC.SeeConfigurationManager}
+                    disabled={emailDisabled}
+                />}
+        />
+        <Controller
+            control={control} name="EmailFrom"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.EmailFrom}
+                    value={value}
+                    placeholder={nlsHPCC.SeeConfigurationManager}
+                    disabled={emailDisabled}
+                />}
+        />
+        <Controller
+            control={control} name="EmailSubject"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.EmailSubject}
+                    value={value}
+                    disabled={emailDisabled}
+                />}
+        />
+        <Controller
+            control={control} name="EmailBody"
+            render={({
+                field: { onChange, name: fieldName, value }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.EmailBody}
+                    multiline={true}
+                    value={value}
+                    disabled={emailDisabled}
+                />}
+        />
+    </MessageBox>;
 };

+ 43 - 80
esp/src/src-react/components/forms/landing-zone/AddFileForm.tsx

@@ -1,9 +1,8 @@
 import * as React from "react";
-import { ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { DefaultButton, PrimaryButton, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 
 interface AddFileFormValues {
     NetAddress: string;
@@ -67,81 +66,45 @@ export const AddFileForm: React.FunctionComponent<AddFileFormProps> = ({
         )();
     }, [closeForm, handleSubmit, refreshGrid, reset, store]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
-    const componentStyles = mergeStyleSets(
-        FormStyles.componentStyles,
-        {
-            container: {
-                minWidth: formMinWidth ? formMinWidth : 300,
-            }
-        }
-    );
-
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{nlsHPCC.AddFile}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="NetAddress"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                        name={fieldName}
-                        onChange={onChange}
-                        label={nlsHPCC.IP}
-                        required={true}
-                        value={value}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="fullPath"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
-                        name={fieldName}
-                        onChange={onChange}
-                        label={nlsHPCC.Path}
-                        required={true}
-                        value={value}
-                        placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Add} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+    return <MessageBox title={nlsHPCC.AddFile} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Add} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Controller
+            control={control} name="NetAddress"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.IP}
+                    required={true}
+                    value={value}
+                    errorMessage={error && error?.message}
+                />}
+            rules={{
+                required: nlsHPCC.ValidationErrorRequired
+            }}
+        />
+        <Controller
+            control={control} name="fullPath"
+            render={({
+                field: { onChange, name: fieldName, value },
+                fieldState: { error }
+            }) => <TextField
+                    name={fieldName}
+                    onChange={onChange}
+                    label={nlsHPCC.Path}
+                    required={true}
+                    value={value}
+                    placeholder={nlsHPCC.NamePrefixPlaceholder}
+                    errorMessage={error && error?.message}
+                />}
+            rules={{
+                required: nlsHPCC.ValidationErrorRequired
+            }}
+        />
+    </MessageBox>;
 };

+ 112 - 137
esp/src/src-react/components/forms/landing-zone/BlobImportForm.tsx

@@ -1,10 +1,10 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
+import { MessageBox } from "../../../layouts/MessageBox";
 import * as FormStyles from "./styles";
 import { pushUrl } from "../../../util/history";
 
@@ -91,14 +91,6 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -123,31 +115,18 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.Blob}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={`${nlsHPCC.Import} ${nlsHPCC.Blob}`} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -157,18 +136,18 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -178,42 +157,42 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="destLogicalName"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="destLogicalName"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.TargetNamePlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.SourcePath}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.SourcePath}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td>
                                 <Controller
@@ -222,11 +201,11 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            errorMessage={error && error?.message}
+                                        />}
                                     rules={{
                                         required: nlsHPCC.ValidationErrorTargetNameRequired,
                                         pattern: {
@@ -238,68 +217,68 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <Controller
-                    control={control} name="prefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <Controller
+                control={control} name="prefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         value={value}
                         label={nlsHPCC.BlobPrefix}
                         placeholder={nlsHPCC.PrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                />
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                        errorMessage={error && error?.message}
+                    />}
+            />
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -309,12 +288,12 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -325,15 +304,11 @@ export const BlobImportForm: React.FunctionComponent<BlobImportFormProps> = ({
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 172 - 197
esp/src/src-react/components/forms/landing-zone/DelimitedImportForm.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 import { pushUrl } from "../../../util/history";
+import * as FormStyles from "./styles";
 
 interface DelimitedImportFormValues {
     destGroup: string;
@@ -93,9 +93,9 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                     request["sourceIP"] = file.SourceIP;
                     request["sourcePath"] = file.SourceFile;
                     request["destLogicalName"] = data.namePrefix + ((
-                            data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
-                            file.TargetName && file.TargetName.substr(0, 2) !== "::"
-                        ) ? "::" : "") + file.TargetName;
+                        data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
+                        file.TargetName && file.TargetName.substr(0, 2) !== "::"
+                    ) ? "::" : "") + file.TargetName;
                     FileSpray.SprayVariable({
                         request: request
                     }).then((response) => {
@@ -111,14 +111,6 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -143,31 +135,18 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.Delimited}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={nlsHPCC.Import} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -177,18 +156,18 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -198,42 +177,42 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="namePrefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="namePrefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.TargetName}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.TargetName}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td>
                                 <Controller
@@ -242,11 +221,11 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            errorMessage={error && error?.message}
+                                        />}
                                     rules={{
                                         required: nlsHPCC.ValidationErrorTargetNameRequired,
                                         pattern: {
@@ -259,19 +238,19 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <table><tbody>
-                    <tr>
-                        <td><Controller
-                            control={control} name="sourceFormat"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <Dropdown
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <table><tbody>
+                <tr>
+                    <td><Controller
+                        control={control} name="sourceFormat"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <Dropdown
                                 key="sourceFormat"
                                 label={nlsHPCC.Format}
                                 options={[
@@ -289,130 +268,130 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                                 onChange={(evt, option) => {
                                     onChange(option.key);
                                 }}
-                                errorMessage={ error && error?.message }
-                            /> }
-                            rules={{
-                                required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
-                            }}
-                        /></td>
-                        <td><Controller
-                            control={control} name="sourceMaxRecordSize"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                        rules={{
+                            required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
+                        }}
+                    /></td>
+                    <td><Controller
+                        control={control} name="sourceMaxRecordSize"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.MaxRecordLength}
                                 value={value}
                                 placeholder="8192"
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                    </tr>
-                    <tr>
-                        <td><Controller
-                            control={control} name="sourceCsvQuote"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                </tr>
+                <tr>
+                    <td><Controller
+                        control={control} name="sourceCsvQuote"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.Quote}
                                 value={value}
                                 placeholder="'"
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="sourceCsvEscape"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="sourceCsvEscape"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.Escape}
                                 value={value}
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                    </tr>
-                    <tr>
-                        <td><Controller
-                            control={control} name="sourceCsvSeparate" defaultValue="\\,"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                </tr>
+                <tr>
+                    <td><Controller
+                        control={control} name="sourceCsvSeparate" defaultValue="\\,"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.Separators}
                                 value={value}
                                 placeholder={nlsHPCC.NamePrefixPlaceholder}
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="sourceCsvTerminate" defaultValue="\\n,\\r\\n"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="sourceCsvTerminate" defaultValue="\\n,\\r\\n"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.LineTerminators}
                                 value={value}
                                 placeholder="\\n,\\r\\n"
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                    </tr>
-                </tbody></table>
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                </tr>
+            </tbody></table>
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -422,12 +401,12 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -438,15 +417,11 @@ export const DelimitedImportForm: React.FunctionComponent<DelimitedImportFormPro
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 93 - 116
esp/src/src-react/components/forms/landing-zone/FileListForm.tsx

@@ -1,10 +1,10 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, keyframes, mergeStyleSets, Modal, PrimaryButton, Stack } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, keyframes, mergeStyleSets, PrimaryButton, Stack } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import { TargetDropzoneTextField, TargetFolderTextField, TargetServerTextField } from "../Fields";
 import * as FileSpray from "src/FileSpray";
 import nlsHPCC from "src/nlsHPCC";
+import { MessageBox } from "../../../layouts/MessageBox";
 import * as FormStyles from "./styles";
 import { ProgressRingDotsIcon } from "@fluentui/react-icons-mdl2";
 
@@ -71,20 +71,20 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
                 method: "POST",
                 body: formData,
             })
-            .then(response => response.json())
-            .then(response => {
-                setSubmitDisabled(false);
-                const DFUActionResult = response?.UploadFilesResponse?.UploadFileResults?.DFUActionResult;
-                if (DFUActionResult.filter(result => result.Result !== "Success").length > 0) {
-                    console.log("upload failed");
-                } else {
-                    closeForm();
-                    if (typeof onSubmit === "function") {
-                        onSubmit();
+                .then(response => response.json())
+                .then(response => {
+                    setSubmitDisabled(false);
+                    const DFUActionResult = response?.UploadFilesResponse?.UploadFileResults?.DFUActionResult;
+                    if (DFUActionResult.filter(result => result.Result !== "Success").length > 0) {
+                        console.log("upload failed");
+                    } else {
+                        closeForm();
+                        if (typeof onSubmit === "function") {
+                            onSubmit();
+                        }
+                        reset(defaultValues);
                     }
-                    reset(defaultValues);
-                }
-            });
+                });
         };
 
         handleSubmit(
@@ -98,7 +98,7 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
                             Netaddr: machine,
                             Path: data.path
                         }
-                    }).then(({FileListResponse}) => {
+                    }).then(({ FileListResponse }) => {
                         let fileName = "";
                         FileListResponse?.files?.PhysicalFileStruct.forEach(file => {
                             if (fileNames.indexOf(file.name) > -1) {
@@ -121,14 +121,6 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
         )();
     }, [closeForm, handleSubmit, machine, onSubmit, os, reset, selection]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const progressIconSpin = keyframes({
         "0%": {
             transform: "rotate(0deg)"
@@ -158,31 +150,25 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
 
     let setDropzone = React.useCallback((dropzone: string) => { }, []);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.FileUploader}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="dropzone"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDropzoneTextField
+    return <MessageBox title={nlsHPCC.FileUploader} show={showForm} setShow={closeForm}
+        footer={<>
+            {submitDisabled &&
+                <span className={componentStyles.progressMessage}>
+                    {nlsHPCC.Uploading}... <ProgressRingDotsIcon className={componentStyles.progressIcon} />
+                </span>
+            }
+            <PrimaryButton text={nlsHPCC.Upload} onClick={handleSubmit(doSubmit)} disabled={submitDisabled} />
+            {submitDisabled &&
+                <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+            }
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="dropzone"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDropzoneTextField
                         key="dropzone"
                         label={nlsHPCC.LandingZone}
                         required={true}
@@ -195,18 +181,18 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
                             setDropzone(option.key as string);
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="machines"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetServerTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="machines"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetServerTextField
                         key="machines"
                         label={nlsHPCC.Machines}
                         required={true}
@@ -217,18 +203,18 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
                             onChange(option.key);
                         }}
                         setSetDropzone={_ => setDropzone = _}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired
-                    }}
-                />
-                <Controller
-                    control={control} name="path"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetFolderTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired
+                }}
+            />
+            <Controller
+                control={control} name="path"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetFolderTextField
                         key="path"
                         label={nlsHPCC.Folder}
                         pathSepChar={pathSep}
@@ -240,53 +226,44 @@ export const FileListForm: React.FunctionComponent<FileListFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: nlsHPCC.ValidationErrorRequired,
-                        pattern: {
-                            value: /^(\/[a-z0-9]*)+$/i,
-                            message: nlsHPCC.ValidationErrorTargetNameRequired
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>#</th>
-                            <th>{nlsHPCC.Type}</th>
-                            <th>{nlsHPCC.FileName}</th>
-                            <th>{nlsHPCC.Size}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: nlsHPCC.ValidationErrorRequired,
+                    pattern: {
+                        value: /^(\/[a-z0-9]*)+$/i,
+                        message: nlsHPCC.ValidationErrorTargetNameRequired
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>#</th>
+                        <th>{nlsHPCC.Type}</th>
+                        <th>{nlsHPCC.FileName}</th>
+                        <th>{nlsHPCC.Size}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td>{idx + 1}</td>
                             <td>{file["name"].substr(file["name"].lastIndexOf(".") + 1).toUpperCase()}</td>
                             <td>{file["name"]}</td>
                             <td>{`${(parseInt(file["size"], 10) / 1024).toFixed(2)} kb`}</td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-                <Controller
-                    control={control} name="overwrite"
-                    render={({
-                        field : { onChange, name: fieldName, value }
-                    }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                />
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                { submitDisabled &&
-                <span className={componentStyles.progressMessage}>
-                    {nlsHPCC.Uploading}... <ProgressRingDotsIcon className={componentStyles.progressIcon} />
-                </span>
-                }
-                <PrimaryButton text={nlsHPCC.Upload} onClick={handleSubmit(doSubmit)} disabled={submitDisabled}/>
-            </Stack>
-        </div>
-    </Modal>;
+                    })}
+                </tbody>
+            </table>
+            <Controller
+                control={control} name="overwrite"
+                render={({
+                    field: { onChange, name: fieldName, value }
+                }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+            />
+        </Stack>
+    </MessageBox>;
 };

+ 113 - 138
esp/src/src-react/components/forms/landing-zone/FixedImportForm.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 import { pushUrl } from "../../../util/history";
+import * as FormStyles from "./styles";
 
 interface FixedImportFormValues {
     destGroup: string;
@@ -77,9 +77,9 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                     request["sourcePath"] = file.SourceFile;
                     request["sourceRecordSize"] = file.RecordSize;
                     request["destLogicalName"] = data.namePrefix + ((
-                            data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
-                            file.TargetName && file.TargetName.substr(0, 2) !== "::"
-                        ) ? "::" : "") + file.TargetName;
+                        data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
+                        file.TargetName && file.TargetName.substr(0, 2) !== "::"
+                    ) ? "::" : "") + file.TargetName;
                     FileSpray.SprayFixed({
                         request: request
                     }).then((response) => {
@@ -95,14 +95,6 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -128,31 +120,18 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.Fixed} ${nlsHPCC.Length}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={nlsHPCC.Import} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -162,18 +141,18 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -183,43 +162,43 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="namePrefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="namePrefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.TargetName}</th>
-                            <th>{nlsHPCC.RecordLength}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.TargetName}</th>
+                        <th>{nlsHPCC.RecordLength}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td><Controller
                                 control={control} name={`selectedFiles.${idx}.TargetName` as const}
@@ -227,12 +206,12 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                                     field: { onChange, name: fieldName, value },
                                     fieldState: { error }
                                 }) => <TextField
-                                    name={fieldName}
-                                    onChange={onChange}
-                                    required
-                                    value={value}
-                                    errorMessage={ error && error?.message }
-                                /> }
+                                        name={fieldName}
+                                        onChange={onChange}
+                                        required
+                                        value={value}
+                                        errorMessage={error && error?.message}
+                                    />}
                                 rules={{
                                     required: nlsHPCC.ValidationErrorTargetNameRequired,
                                     pattern: {
@@ -248,12 +227,12 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        placeholder={nlsHPCC.RequiredForFixedSpray}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            placeholder={nlsHPCC.RequiredForFixedSpray}
+                                            errorMessage={error && error?.message}
+                                        />}
                                     rules={{
                                         required: nlsHPCC.ValidationErrorRecordSizeRequired,
                                         pattern: {
@@ -266,52 +245,52 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -321,12 +300,12 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -337,15 +316,11 @@ export const FixedImportForm: React.FunctionComponent<FixedImportFormProps> = ({
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 138 - 163
esp/src/src-react/components/forms/landing-zone/JsonImportForm.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 import { pushUrl } from "../../../util/history";
+import * as FormStyles from "./styles";
 
 interface JsonImportFormValues {
     destGroup: string;
@@ -80,9 +80,9 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                     request["sourcePath"] = file.SourceFile;
                     request["isJSON"] = true;
                     request["destLogicalName"] = data.namePrefix + ((
-                            data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
-                            file.TargetName && file.TargetName.substr(0, 2) !== "::"
-                        ) ? "::" : "") + file.TargetName;
+                        data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
+                        file.TargetName && file.TargetName.substr(0, 2) !== "::"
+                    ) ? "::" : "") + file.TargetName;
                     request["sourceRowTag"] = file.TargetRowPath;
                     FileSpray.SprayVariable({
                         request: request
@@ -99,14 +99,6 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -132,31 +124,18 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.JSON}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={nlsHPCC.Import} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -166,18 +145,18 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -187,43 +166,43 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="namePrefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="namePrefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.TargetName}</th>
-                            <th>{nlsHPCC.RowPath}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.TargetName}</th>
+                        <th>{nlsHPCC.RowPath}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td><Controller
                                 control={control} name={`selectedFiles.${idx}.TargetName` as const}
@@ -231,11 +210,11 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                                     field: { onChange, name: fieldName, value },
                                     fieldState: { error }
                                 }) => <TextField
-                                    name={fieldName}
-                                    onChange={onChange}
-                                    value={value}
-                                    errorMessage={ error && error?.message }
-                                /> }
+                                        name={fieldName}
+                                        onChange={onChange}
+                                        value={value}
+                                        errorMessage={error && error?.message}
+                                    />}
                                 rules={{
                                     required: nlsHPCC.ValidationErrorTargetNameRequired,
                                     pattern: {
@@ -251,29 +230,29 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            errorMessage={error && error?.message}
+                                        />}
                                 />
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceFile` as const} value={file["fullPath"]} />
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <table><tbody>
-                    <tr>
-                        <td><Controller
-                            control={control} name="sourceFormat"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <Dropdown
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <table><tbody>
+                <tr>
+                    <td><Controller
+                        control={control} name="sourceFormat"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <Dropdown
                                 key="sourceFormat"
                                 label={nlsHPCC.Format}
                                 options={[
@@ -291,71 +270,71 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                                 onChange={(evt, option) => {
                                     onChange(option.key);
                                 }}
-                                errorMessage={ error && error?.message }
-                            /> }
-                            rules={{
-                                required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
-                            }}
-                        /></td>
-                        <td><Controller
-                            control={control} name="sourceMaxRecordSize"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                        rules={{
+                            required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
+                        }}
+                    /></td>
+                    <td><Controller
+                        control={control} name="sourceMaxRecordSize"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.MaxRecordLength}
                                 value={value}
                                 placeholder="8192"
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                    </tr>
-                </tbody></table>
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                </tr>
+            </tbody></table>
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -365,12 +344,12 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -381,15 +360,11 @@ export const JsonImportForm: React.FunctionComponent<JsonImportFormProps> = ({
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 119 - 144
esp/src/src-react/components/forms/landing-zone/VariableImportForm.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 import { pushUrl } from "../../../util/history";
+import * as FormStyles from "./styles";
 
 interface VariableImportFormValues {
     destGroup: string;
@@ -76,9 +76,9 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                     request["sourceIP"] = file.SourceIP;
                     request["sourcePath"] = file.SourceFile;
                     request["destLogicalName"] = data.namePrefix + ((
-                            data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
-                            file.TargetName && file.TargetName.substr(0, 2) !== "::"
-                        ) ? "::" : "") + file.TargetName;
+                        data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
+                        file.TargetName && file.TargetName.substr(0, 2) !== "::"
+                    ) ? "::" : "") + file.TargetName;
                     FileSpray.SprayFixed({
                         request: request
                     }).then((response) => {
@@ -94,14 +94,6 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -126,31 +118,18 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.Variable}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={nlsHPCC.Import} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -160,18 +139,18 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -181,42 +160,42 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="namePrefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="namePrefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.TargetName}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.TargetName}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td>
                                 <Controller
@@ -225,11 +204,11 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            errorMessage={error && error?.message}
+                                        />}
                                     rules={{
                                         required: nlsHPCC.ValidationErrorTargetNameRequired,
                                         pattern: {
@@ -242,17 +221,17 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <Controller
-                    control={control} name="sourceFormat"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <Dropdown
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <Controller
+                control={control} name="sourceFormat"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <Dropdown
                         key="sourceFormat"
                         label={nlsHPCC.Format}
                         options={[
@@ -265,55 +244,55 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -323,12 +302,12 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -339,15 +318,11 @@ export const VariableImportForm: React.FunctionComponent<VariableImportFormProps
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 138 - 163
esp/src/src-react/components/forms/landing-zone/XmlImportForm.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
-import { Checkbox, ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField } from "@fluentui/react";
-import { useId } from "@fluentui/react-hooks";
+import { Checkbox, DefaultButton, Dropdown, mergeStyleSets, PrimaryButton, Stack, TextField } from "@fluentui/react";
 import { useForm, Controller } from "react-hook-form";
 import * as FileSpray from "src/FileSpray";
 import { TargetDfuSprayQueueTextField, TargetGroupTextField } from "../Fields";
 import nlsHPCC from "src/nlsHPCC";
-import * as FormStyles from "./styles";
+import { MessageBox } from "../../../layouts/MessageBox";
 import { pushUrl } from "../../../util/history";
+import * as FormStyles from "./styles";
 
 interface XmlImportFormValues {
     destGroup: string;
@@ -79,9 +79,9 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                     request["sourceIP"] = file.SourceIP;
                     request["sourcePath"] = file.SourceFile;
                     request["destLogicalName"] = data.namePrefix + ((
-                            data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
-                            file.TargetName && file.TargetName.substr(0, 2) !== "::"
-                        ) ? "::" : "") + file.TargetName;
+                        data.namePrefix && data.namePrefix.substr(-2) !== "::" &&
+                        file.TargetName && file.TargetName.substr(0, 2) !== "::"
+                    ) ? "::" : "") + file.TargetName;
                     request["sourceRowTag"] = file.TargetRowTag;
                     FileSpray.SprayVariable({
                         request: request
@@ -98,14 +98,6 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
         )();
     }, [handleSubmit]);
 
-    const titleId = useId("title");
-
-    const dragOptions: IDragOptions = {
-        moveMenuItemText: nlsHPCC.Move,
-        closeMenuItemText: nlsHPCC.Close,
-        menu: ContextualMenu,
-    };
-
     const componentStyles = mergeStyleSets(
         FormStyles.componentStyles,
         {
@@ -131,31 +123,18 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
         }
     }, [selection, reset]);
 
-    return <Modal
-        titleAriaId={titleId}
-        isOpen={showForm}
-        onDismiss={closeForm}
-        isBlocking={false}
-        containerClassName={componentStyles.container}
-        dragOptions={dragOptions}
-    >
-        <div className={componentStyles.header}>
-            <span id={titleId}>{`${nlsHPCC.Import} ${nlsHPCC.XML}`}</span>
-            <IconButton
-                styles={FormStyles.iconButtonStyles}
-                iconProps={FormStyles.cancelIcon}
-                ariaLabel={nlsHPCC.CloseModal}
-                onClick={closeForm}
-            />
-        </div>
-        <div className={componentStyles.body}>
-            <Stack>
-                <Controller
-                    control={control} name="destGroup"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetGroupTextField
+    return <MessageBox title={nlsHPCC.Import} show={showForm} setShow={closeForm}
+        footer={<>
+            <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
+            <DefaultButton text={nlsHPCC.Cancel} onClick={() => closeForm()} />
+        </>}>
+        <Stack>
+            <Controller
+                control={control} name="destGroup"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetGroupTextField
                         key="destGroup"
                         label={nlsHPCC.Group}
                         required={true}
@@ -165,18 +144,18 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
-                    }}
-                />
-                <Controller
-                    control={control} name="DFUServerQueue"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TargetDfuSprayQueueTextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Group}`
+                }}
+            />
+            <Controller
+                control={control} name="DFUServerQueue"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TargetDfuSprayQueueTextField
                         key="DFUServerQueue"
                         label={nlsHPCC.Queue}
                         required={true}
@@ -186,42 +165,42 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                         onChange={(evt, option) => {
                             onChange(option.key);
                         }}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
-                    }}
-                />
-                <Controller
-                    control={control} name="namePrefix"
-                    render={({
-                        field: { onChange, name: fieldName, value },
-                        fieldState: { error }
-                    }) => <TextField
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    required: `${nlsHPCC.SelectA} ${nlsHPCC.Queue}`
+                }}
+            />
+            <Controller
+                control={control} name="namePrefix"
+                render={({
+                    field: { onChange, name: fieldName, value },
+                    fieldState: { error }
+                }) => <TextField
                         name={fieldName}
                         onChange={onChange}
                         label={nlsHPCC.TargetScope}
                         value={value}
                         placeholder={nlsHPCC.NamePrefixPlaceholder}
-                        errorMessage={ error && error?.message }
-                    /> }
-                    rules={{
-                        pattern: {
-                            value: /^([a-z0-9]+(::)?)+$/i,
-                            message: nlsHPCC.ValidationErrorNamePrefix
-                        }
-                    }}
-                />
-            </Stack>
-            <Stack>
-                <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
-                    <thead>
-                        <tr>
-                            <th>{nlsHPCC.TargetName}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                    { selection && selection.map((file, idx) => {
+                        errorMessage={error && error?.message}
+                    />}
+                rules={{
+                    pattern: {
+                        value: /^([a-z0-9]+(::)?)+$/i,
+                        message: nlsHPCC.ValidationErrorNamePrefix
+                    }
+                }}
+            />
+        </Stack>
+        <Stack>
+            <table className={`${componentStyles.twoColumnTable} ${componentStyles.selectionTable}`}>
+                <thead>
+                    <tr>
+                        <th>{nlsHPCC.TargetName}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {selection && selection.map((file, idx) => {
                         return <tr key={`File-${idx}`}>
                             <td><Controller
                                 control={control} name={`selectedFiles.${idx}.TargetName` as const}
@@ -229,11 +208,11 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                                     field: { onChange, name: fieldName, value },
                                     fieldState: { error }
                                 }) => <TextField
-                                    name={fieldName}
-                                    onChange={onChange}
-                                    value={value}
-                                    errorMessage={ error && error?.message }
-                                /> }
+                                        name={fieldName}
+                                        onChange={onChange}
+                                        value={value}
+                                        errorMessage={error && error?.message}
+                                    />}
                                 rules={{
                                     required: nlsHPCC.ValidationErrorTargetNameRequired,
                                     pattern: {
@@ -249,30 +228,30 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                                         field: { onChange, name: fieldName, value },
                                         fieldState: { error }
                                     }) => <TextField
-                                        name={fieldName}
-                                        onChange={onChange}
-                                        value={value}
-                                        placeholder={nlsHPCC.RequiredForFixedSpray}
-                                        errorMessage={ error && error?.message }
-                                    /> }
+                                            name={fieldName}
+                                            onChange={onChange}
+                                            value={value}
+                                            placeholder={nlsHPCC.RequiredForFixedSpray}
+                                            errorMessage={error && error?.message}
+                                        />}
                                 />
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceFile` as const} value={file["fullPath"]} />
                                 <input type="hidden" name={`selectedFiles.${idx}.SourceIP` as const} value={file["NetAddress"]} />
                             </td>
                         </tr>;
-                    }) }
-                    </tbody>
-                </table>
-            </Stack>
-            <Stack>
-                <table><tbody>
-                    <tr>
-                        <td><Controller
-                            control={control} name="sourceFormat"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <Dropdown
+                    })}
+                </tbody>
+            </table>
+        </Stack>
+        <Stack>
+            <table><tbody>
+                <tr>
+                    <td><Controller
+                        control={control} name="sourceFormat"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <Dropdown
                                 key="sourceFormat"
                                 label={nlsHPCC.Format}
                                 options={[
@@ -290,71 +269,71 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                                 onChange={(evt, option) => {
                                     onChange(option.key);
                                 }}
-                                errorMessage={ error && error?.message }
-                            /> }
-                            rules={{
-                                required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
-                            }}
-                        /></td>
-                        <td><Controller
-                            control={control} name="sourceMaxRecordSize"
-                            render={({
-                                field: { onChange, name: fieldName, value },
-                                fieldState: { error }
-                            }) => <TextField
+                                errorMessage={error && error?.message}
+                            />}
+                        rules={{
+                            required: `${nlsHPCC.SelectA} ${nlsHPCC.Format}`
+                        }}
+                    /></td>
+                    <td><Controller
+                        control={control} name="sourceMaxRecordSize"
+                        render={({
+                            field: { onChange, name: fieldName, value },
+                            fieldState: { error }
+                        }) => <TextField
                                 name={fieldName}
                                 onChange={onChange}
                                 label={nlsHPCC.MaxRecordLength}
                                 value={value}
                                 placeholder="8192"
-                                errorMessage={ error && error?.message }
-                            /> }
-                        /></td>
-                    </tr>
-                </tbody></table>
-            </Stack>
-            <Stack>
-                <table className={componentStyles.twoColumnTable}>
-                    <tbody><tr>
-                        <td><Controller
-                            control={control} name="overwrite"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} /> }
-                        /></td>
-                        <td><Controller
-                            control={control} name="replicate"
-                            render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} /> }
-                        /></td>
-                    </tr>
+                                errorMessage={error && error?.message}
+                            />}
+                    /></td>
+                </tr>
+            </tbody></table>
+        </Stack>
+        <Stack>
+            <table className={componentStyles.twoColumnTable}>
+                <tbody><tr>
+                    <td><Controller
+                        control={control} name="overwrite"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Overwrite} />}
+                    /></td>
+                    <td><Controller
+                        control={control} name="replicate"
+                        render={({
+                            field: { onChange, name: fieldName, value }
+                        }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Replicate} />}
+                    /></td>
+                </tr>
                     <tr>
                         <td><Controller
                             control={control} name="nosplit"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoSplit} />}
                         /></td>
                         <td><Controller
                             control={control} name="noCommon"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.NoCommon} />}
                         /></td>
                     </tr>
                     <tr>
                         <td><Controller
                             control={control} name="compress"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.Compress} />}
                         /></td>
                         <td><Controller
                             control={control} name="failIfNoSourceFile"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.FailIfNoSourceFile} />}
                         /></td>
                     </tr>
                     <tr>
@@ -364,12 +343,12 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                                 field: { onChange, name: fieldName, value },
                                 fieldState: { error }
                             }) => <TextField
-                                name={fieldName}
-                                onChange={onChange}
-                                label={nlsHPCC.ExpireDays}
-                                value={value}
-                                errorMessage={ error && error?.message }
-                            />}
+                                    name={fieldName}
+                                    onChange={onChange}
+                                    label={nlsHPCC.ExpireDays}
+                                    value={value}
+                                    errorMessage={error && error?.message}
+                                />}
                             rules={{
                                 min: {
                                     value: 1,
@@ -380,15 +359,11 @@ export const XmlImportForm: React.FunctionComponent<XmlImportFormProps> = ({
                         <td><Controller
                             control={control} name="delayedReplication"
                             render={({
-                                field : { onChange, name: fieldName, value }
-                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} /> }
+                                field: { onChange, name: fieldName, value }
+                            }) => <Checkbox name={fieldName} checked={value} onChange={onChange} label={nlsHPCC.DelayedReplication} disabled={true} />}
                         /></td>
                     </tr></tbody>
-                </table>
-            </Stack>
-            <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
-                <PrimaryButton text={nlsHPCC.Import} onClick={handleSubmit(onSubmit)} />
-            </Stack>
-        </div>
-    </Modal>;
+            </table>
+        </Stack>
+    </MessageBox>;
 };

+ 1 - 1
esp/src/src-react/hooks/file.ts

@@ -4,7 +4,7 @@ import { scopedLogger } from "@hpcc-js/util";
 import * as WsDfu from "src/WsDfu";
 import { useCounter } from "./workunit";
 
-const logger = scopedLogger("src-react/hooks/file.ts");
+const logger = scopedLogger("../hooks/file.ts");
 
 export function useFile(cluster: string, name: string): [LogicalFile, number, () => void] {
 

+ 1 - 1
esp/src/src-react/hooks/logging.ts

@@ -3,7 +3,7 @@ import { useConst } from "@fluentui/react-hooks";
 import { ESPExceptions, isExceptions } from "@hpcc-js/comms";
 import { Observable, Level, logger as utilLogger, scopedLogger, Writer, CallbackFunction } from "@hpcc-js/util";
 
-const logger = scopedLogger("src-react/util/logging.ts");
+const logger = scopedLogger("../util/logging.ts");
 
 let g_logger: ECLWatchLogger;
 

+ 1 - 1
esp/src/src-react/hooks/workunit.ts

@@ -5,7 +5,7 @@ import { scopedLogger } from "@hpcc-js/util";
 import nlsHPCC from "src/nlsHPCC";
 import * as Utility from "src/Utility";
 
-const logger = scopedLogger("src-react/hooks/workunit.ts");
+const logger = scopedLogger("../hooks/workunit.ts");
 
 export function useCounter(): [number, () => void] {
 

+ 1 - 1
esp/src/src-react/index.tsx

@@ -13,7 +13,7 @@ import "src-react-css/index.css";
 ECLWatchLogger.init();
 initializeIcons();
 
-const logger = scopedLogger("src-react/index.tsx");
+const logger = scopedLogger("../index.tsx");
 
 declare const dojoConfig: any;
 

+ 69 - 0
esp/src/src-react/layouts/MessageBox.tsx

@@ -0,0 +1,69 @@
+import * as React from "react";
+import { mergeStyleSets, IDragOptions, IIconProps, ContextualMenu, IconButton, Modal, Stack, useTheme, IStackTokens } from "@fluentui/react";
+import nlsHPCC from "src/nlsHPCC";
+
+const headerTokens: IStackTokens = {
+    childrenGap: 8,
+    padding: "0px 12px 0px 12px"
+};
+
+const footerTokens: IStackTokens = {
+    childrenGap: 8,
+    padding: "12px 12px 12px 12px"
+};
+
+const dragOptions: IDragOptions = {
+    moveMenuItemText: nlsHPCC.Move,
+    closeMenuItemText: nlsHPCC.Close,
+    menu: ContextualMenu,
+};
+
+const cancelIcon: IIconProps = { iconName: "Cancel" };
+
+const iconButtonStyles = {
+    root: {
+        marginLeft: "auto",
+        marginTop: "4px",
+        marginRight: "2px",
+    },
+};
+
+interface MessageBoxProps {
+    title: string;
+    show: boolean;
+    setShow: (_: boolean) => void;
+    footer?: React.ReactNode;
+    children?: React.ReactNode;
+}
+
+export const MessageBox: React.FunctionComponent<MessageBoxProps> = ({
+    title,
+    show,
+    setShow,
+    footer,
+    children
+}) => {
+
+    const theme = useTheme();
+    const contentStyles = React.useMemo(() => mergeStyleSets({
+        container: { overflowY: "hidden" },
+        header: { borderTop: `4px solid ${theme.palette.themePrimary}` },
+        body: { padding: "12px 24px 12px 24px", overflowY: "hidden" },
+    }), [theme.palette.themePrimary]);
+
+    const close = React.useCallback(() => setShow(false), [setShow]);
+
+    return <Modal isOpen={show} onDismiss={close} dragOptions={dragOptions}
+        isBlocking={false} containerClassName={contentStyles.container}>
+        <Stack tokens={headerTokens} horizontal horizontalAlign="space-between" verticalAlign="center" styles={{ root: contentStyles.header }}>
+            <h2>{title}</h2>
+            <IconButton iconProps={cancelIcon} ariaLabel={nlsHPCC.CloseModal} onClick={close} styles={iconButtonStyles} />
+        </Stack>
+        <div className={contentStyles.body}>
+            {children}
+        </div>
+        <Stack tokens={footerTokens} horizontal horizontalAlign="end">
+            {footer}
+        </Stack>
+    </Modal>;
+};

+ 1 - 1
esp/src/src-react/util/history.ts

@@ -3,7 +3,7 @@ import { parse, ParsedQuery, stringify } from "query-string";
 import { hashSum, scopedLogger } from "@hpcc-js/util";
 import { userKeyValStore } from "src/KeyValStore";
 
-const logger = scopedLogger("src-react/util/history.ts");
+const logger = scopedLogger("../util/history.ts");
 
 let g_router: UniversalRouter;