瀏覽代碼

HPCC-26333 React Query Details Superfiles tab

Signed-off-by: Jeremy Clements <jeremy.clements@lexisnexisrisk.com>
Jeremy Clements 3 年之前
父節點
當前提交
69ad47b552

+ 3 - 3
esp/src/src-react/components/FileDetails.tsx

@@ -52,7 +52,7 @@ export const FileDetails: React.FunctionComponent<FileDetailsProps> = ({
     const [showDesprayFile, setShowDesprayFile] = React.useState(false);
     const [showReplicateFile, setShowReplicateFile] = React.useState(false);
 
-    const isDFUWorkunit = file?.Wuid[0] === "D";
+    const isDFUWorkunit = file?.Wuid?.length && file?.Wuid[0] === "D";
     const isProtected = file?.ProtectList?.DFUFileProtect?.length > 0 || false;
 
     React.useEffect(() => {
@@ -186,8 +186,8 @@ export const FileDetails: React.FunctionComponent<FileDetailsProps> = ({
                             "NumParts": { label: nlsHPCC.FileParts, type: "number", value: file?.NumParts, readonly: true },
                             "MinSkew": { label: nlsHPCC.MinSkew, type: "string", value: file?.Stat?.MinSkew, readonly: true },
                             "MaxSkew": { label: nlsHPCC.MaxSkew, type: "string", value: file?.Stat?.MaxSkew, readonly: true },
-                            "MinSkewPart": { label: nlsHPCC.MinSkewPart, type: "string", value: file?.Stat?.MinSkewPart === undefined ? "" : file?.Stat?.MinSkewPart.toString(), readonly: true },
-                            "MaxSkewPart": { label: nlsHPCC.MaxSkewPart, type: "string", value: file?.Stat?.MaxSkewPart === undefined ? "" : file?.Stat?.MaxSkewPart.toString(), readonly: true },
+                            "MinSkewPart": { label: nlsHPCC.MinSkewPart, type: "string", value: file?.Stat?.MinSkewPart === undefined ? "" : file?.Stat?.MinSkewPart?.toString(), readonly: true },
+                            "MaxSkewPart": { label: nlsHPCC.MaxSkewPart, type: "string", value: file?.Stat?.MaxSkewPart === undefined ? "" : file?.Stat?.MaxSkewPart?.toString(), readonly: true },
                         }} onChange={(id, value) => {
                             switch (id) {
                                 case "Description":

+ 3 - 2
esp/src/src-react/components/QueryDetails.tsx

@@ -13,6 +13,7 @@ import { QueryErrors } from "./QueryErrors";
 import { QueryLibrariesUsed } from "./QueryLibrariesUsed";
 import { QueryLogicalFiles } from "./QueryLogicalFiles";
 import { QuerySummaryStats } from "./QuerySummaryStats";
+import { QuerySuperFiles } from "./QuerySuperFiles";
 import { Resources } from "./Resources";
 import { TableGroup } from "./forms/Groups";
 
@@ -152,8 +153,8 @@ export const QueryDetails: React.FunctionComponent<QueryDetailsProps> = ({
             <PivotItem headerText={nlsHPCC.LogicalFiles} itemKey="logicalFiles" itemCount={query?.LogicalFiles?.Item?.length || 0} style={pivotItemStyle(size, 0)}>
                 <QueryLogicalFiles queryId={queryId} querySet={querySet} />
             </PivotItem>
-            <PivotItem headerText={nlsHPCC.SuperFiles} itemKey="superfiles" itemCount={0} style={pivotItemStyle(size, 0)}>
-                <DojoAdapter widgetClassID="QuerySetSuperFilesWidget" params={{ Id: queryId, QuerySetId: querySet }} />
+            <PivotItem headerText={nlsHPCC.SuperFiles} itemKey="superfiles" itemCount={query?.SuperFiles?.SuperFile.length || 0} style={pivotItemStyle(size, 0)}>
+                <QuerySuperFiles queryId={queryId} querySet={querySet} />
             </PivotItem>
             <PivotItem headerText={nlsHPCC.LibrariesUsed} itemKey="librariesUsed" itemCount={query?.LibrariesUsed?.Item?.length || 0} style={pivotItemStyle(size, 0)}>
                 <QueryLibrariesUsed queryId={queryId} querySet={querySet} />

+ 113 - 0
esp/src/src-react/components/QuerySuperFiles.tsx

@@ -0,0 +1,113 @@
+import * as React from "react";
+import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
+import { useConst } from "@fluentui/react-hooks";
+import { scopedLogger } from "@hpcc-js/util";
+import * as ESPQuery from "src/ESPQuery";
+import * as Observable from "dojo/store/Observable";
+import { Memory } from "src/Memory";
+import nlsHPCC from "src/nlsHPCC";
+import { HolyGrail } from "../layouts/HolyGrail";
+import { pushUrl } from "../util/history";
+import { ShortVerticalDivider } from "./Common";
+import { DojoGrid, selector } from "./DojoGrid";
+
+const logger = scopedLogger("src-react/components/QuerySuperFiles.tsx");
+
+const defaultUIState = {
+    hasSelection: false
+};
+
+interface QuerySuperFilesProps {
+    querySet?: string;
+    queryId?: string;
+}
+
+export const QuerySuperFiles: React.FunctionComponent<QuerySuperFilesProps> = ({
+    querySet,
+    queryId
+}) => {
+
+    const [query, setQuery] = React.useState<any>();
+    const [grid, setGrid] = React.useState<any>(undefined);
+    const [selection, setSelection] = React.useState([]);
+    const [uiState, setUIState] = React.useState({ ...defaultUIState });
+
+    //  Grid ---
+    const gridStore = useConst(new Observable(new Memory("__hpcc_id")));
+    const gridQuery = useConst({});
+    const gridSort = useConst([{ attribute: "__hpcc_id" }]);
+    const gridColumns = useConst({
+        col1: selector({ selectorType: "checkbox", width: 25 }),
+        File: {
+            label: nlsHPCC.File,
+            formatter: function (item, row) {
+                return `<a href="#/files/${querySet}/${item}">${item}</a>`;
+            }
+        },
+    });
+
+    const refreshTable = React.useCallback((clearSelection = false) => {
+        grid?.set("query", gridQuery);
+        if (clearSelection) {
+            grid?.clearSelection();
+        }
+    }, [grid, gridQuery]);
+
+    //  Command Bar  ---
+    const buttons = React.useMemo((): ICommandBarItemProps[] => [
+        {
+            key: "refresh", text: nlsHPCC.Refresh, iconProps: { iconName: "Refresh" },
+            onClick: () => refreshTable()
+        },
+        { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => <ShortVerticalDivider /> },
+        {
+            key: "open", text: nlsHPCC.Open, disabled: !uiState.hasSelection, iconProps: { iconName: "WindowEdit" },
+            onClick: () => {
+                if (selection.length === 1) {
+                    pushUrl(`/files/${querySet}/${selection[0].File}`);
+                } else {
+                    for (let i = selection.length - 1; i >= 0; --i) {
+                        window.open(`#/files/${selection[i].QuerySetId}/${selection[i].Id}`, "_blank");
+                    }
+                }
+            }
+        },
+    ], [querySet, refreshTable, selection, uiState.hasSelection]);
+
+    //  Selection  ---
+    React.useEffect(() => {
+        const state = { ...defaultUIState };
+
+        if (selection.length) {
+            state.hasSelection = true;
+        }
+
+        setUIState(state);
+    }, [selection]);
+
+    React.useEffect(() => {
+        setQuery(ESPQuery.Get(querySet, queryId));
+    }, [setQuery, queryId, querySet]);
+
+    React.useEffect(() => {
+        query?.getDetails()
+            .then(({ WUQueryDetailsResponse }) => {
+                const superFiles = query?.SuperFiles?.SuperFile;
+                if (superFiles) {
+                    gridStore.setData(superFiles.map((item, idx) => {
+                        return {
+                            __hpcc_id: idx,
+                            File: item.Name
+                        };
+                    }));
+                    refreshTable();
+                }
+            })
+            .catch(logger.error);
+    }, [gridStore, query, refreshTable]);
+
+    return <HolyGrail
+        header={<CommandBar items={buttons} overflowButtonProps={{}} />}
+        main={<DojoGrid store={gridStore} query={gridQuery} sort={gridSort} columns={gridColumns} setGrid={setGrid} setSelection={setSelection} />}
+    />;
+};

+ 1 - 2
esp/src/src-react/components/SuperFiles.tsx

@@ -76,9 +76,8 @@ export const SuperFiles: React.FunctionComponent<SuperFilesProps> = ({
     React.useEffect(() => {
         const state = { ...defaultUIState };
 
-        for (let i = 0; i < selection.length; ++i) {
+        if (selection.length) {
             state.hasSelection = true;
-            break;
         }
         setUIState(state);
     }, [selection]);