From 826b8322f78e96124768c9ebdde5925e4c379e20 Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Thu, 7 Sep 2023 15:09:35 +0100 Subject: [PATCH] HPCC-30230 Sorting grid resets columns widths Remove additional flickering Signed-off-by: Gordon Smith --- .../src-react/components/DESDLDefinitions.tsx | 30 ++- esp/src/src-react/components/DFUWorkunits.tsx | 7 +- .../src-react/components/EventScheduler.tsx | 4 +- esp/src/src-react/components/FileBlooms.tsx | 30 ++- .../src-react/components/FileDetailsGraph.tsx | 34 ++- esp/src/src-react/components/FileHistory.tsx | 30 ++- esp/src/src-react/components/FileParts.tsx | 38 +-- esp/src/src-react/components/Files.tsx | 7 +- esp/src/src-react/components/GroupMembers.tsx | 4 +- esp/src/src-react/components/Groups.tsx | 4 +- esp/src/src-react/components/Helpers.tsx | 40 +-- esp/src/src-react/components/InfoGrid.tsx | 49 ++-- esp/src/src-react/components/LogViewer.tsx | 37 +-- esp/src/src-react/components/Logs.tsx | 4 +- esp/src/src-react/components/Monitoring.tsx | 57 +++-- .../src-react/components/PackageMapParts.tsx | 37 +-- esp/src/src-react/components/PackageMaps.tsx | 42 ++-- esp/src/src-react/components/Pods.tsx | 29 ++- esp/src/src-react/components/ProtectedBy.tsx | 31 ++- esp/src/src-react/components/Queries.tsx | 4 +- esp/src/src-react/components/QueryErrors.tsx | 30 ++- esp/src/src-react/components/QueryGraphs.tsx | 34 ++- .../components/QueryLibrariesUsed.tsx | 30 ++- .../components/QueryLogicalFiles.tsx | 36 ++- .../components/QuerySummaryStats.tsx | 30 ++- .../src-react/components/QuerySuperFiles.tsx | 36 ++- esp/src/src-react/components/Resources.tsx | 36 ++- esp/src/src-react/components/Results.tsx | 46 ++-- esp/src/src-react/components/Scopes.tsx | 49 ++-- esp/src/src-react/components/Search.tsx | 38 +-- esp/src/src-react/components/Services.tsx | 31 ++- esp/src/src-react/components/SourceFiles.tsx | 42 ++-- esp/src/src-react/components/SubFiles.tsx | 61 ++--- esp/src/src-react/components/SuperFiles.tsx | 36 ++- esp/src/src-react/components/UserGroups.tsx | 37 ++- esp/src/src-react/components/Users.tsx | 4 +- esp/src/src-react/components/Variables.tsx | 32 ++- esp/src/src-react/components/Workflows.tsx | 40 +-- esp/src/src-react/components/Workunits.tsx | 13 +- .../src-react/components/XrefDirectories.tsx | 48 ++-- esp/src/src-react/components/XrefErrors.tsx | 50 ++-- .../src-react/components/XrefFoundFiles.tsx | 35 ++- .../src-react/components/XrefLostFiles.tsx | 33 ++- .../src-react/components/XrefOrphanFiles.tsx | 32 ++- esp/src/src-react/components/Xrefs.tsx | 37 ++- .../src-react/components/controls/Grid.tsx | 146 ++++++++++- esp/src/src-react/hooks/grid.tsx | 233 +----------------- 47 files changed, 1010 insertions(+), 783 deletions(-) diff --git a/esp/src/src-react/components/DESDLDefinitions.tsx b/esp/src/src-react/components/DESDLDefinitions.tsx index a12424326c8..f9e6414869a 100644 --- a/esp/src/src-react/components/DESDLDefinitions.tsx +++ b/esp/src/src-react/components/DESDLDefinitions.tsx @@ -4,9 +4,9 @@ import { scopedLogger } from "@hpcc-js/util"; import nlsHPCC from "src/nlsHPCC"; import * as WsESDLConfig from "src/WsESDLConfig"; import { useConfirm } from "../hooks/confirm"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; import { ReflexContainer, ReflexElement, ReflexSplitter } from "../layouts/react-reflex"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; import { selector } from "./DojoGrid"; import { XMLSourceEditor } from "./SourceEditor"; @@ -28,22 +28,22 @@ export const DESDLDefinitions: React.FunctionComponent = ( const [showAddBinding, setShowAddBinding] = React.useState(false); const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort: { attribute: "Name", descending: false }, - filename: "esdlDefinitions", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: selector({ width: 30, selectorType: "radio", unhidable: true }), Name: { label: nlsHPCC.Process, width: 140 }, PublishBy: { label: nlsHPCC.PublishedBy, width: 140 }, CreatedTime: { label: nlsHPCC.CreatedTime, width: 140 }, LastEditBy: { label: nlsHPCC.LastEditedBy, width: 140 }, LastEditTime: { label: nlsHPCC.LastEditTime, width: 140 } - } - }); + }; + }, []); // Selection --- React.useEffect(() => { @@ -125,6 +125,8 @@ export const DESDLDefinitions: React.FunctionComponent = ( }, ], [refreshData, setShowDeleteConfirm, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "esdlDefinitions"); + React.useEffect(() => { refreshData(); }, [refreshData]); @@ -135,7 +137,15 @@ export const DESDLDefinitions: React.FunctionComponent = ( main={ - + diff --git a/esp/src/src-react/components/DFUWorkunits.tsx b/esp/src/src-react/components/DFUWorkunits.tsx index ce4a7097d28..94401b8541b 100644 --- a/esp/src/src-react/components/DFUWorkunits.tsx +++ b/esp/src/src-react/components/DFUWorkunits.tsx @@ -10,7 +10,7 @@ import { useConfirm } from "../hooks/confirm"; import { useMyAccount } from "../hooks/user"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushParams } from "../util/history"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { Filter } from "./forms/Filter"; import { Fields } from "./forms/Fields"; import { ShortVerticalDivider } from "./Common"; @@ -90,7 +90,7 @@ export const DFUWorkunits: React.FunctionComponent = ({ return formatQuery(filter); }, [filter]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { col1: selector({ width: 27, @@ -135,9 +135,6 @@ export const DFUWorkunits: React.FunctionComponent = ({ StateMessage: { label: nlsHPCC.State, width: 70 }, PCTDone: { label: nlsHPCC.PctComplete, width: 80, sortable: true, - formatter: (value, row) => { - return Utility.valueCleanUp(row.PercentDone); - } }, TimeStarted: { label: nlsHPCC.TimeStarted, width: 100, sortable: true }, TimeStopped: { label: nlsHPCC.TimeStopped, width: 100, sortable: true }, diff --git a/esp/src/src-react/components/EventScheduler.tsx b/esp/src/src-react/components/EventScheduler.tsx index 9195c4bf68e..4321b9b6301 100644 --- a/esp/src/src-react/components/EventScheduler.tsx +++ b/esp/src/src-react/components/EventScheduler.tsx @@ -7,7 +7,7 @@ import nlsHPCC from "src/nlsHPCC"; import * as WsWorkunits from "src/WsWorkunits"; import { useConfirm } from "../hooks/confirm"; import { HolyGrail } from "../layouts/HolyGrail"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { pushParams } from "../util/history"; import { Fields } from "./forms/Fields"; import { Filter } from "./forms/Filter"; @@ -70,7 +70,7 @@ export const EventScheduler: React.FunctionComponent = ({ return store ? store : CreateEventScheduleStore({}); }, [store]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { col1: { width: 16, diff --git a/esp/src/src-react/components/FileBlooms.tsx b/esp/src/src-react/components/FileBlooms.tsx index 5708a8cce56..f72bcaf37f4 100644 --- a/esp/src/src-react/components/FileBlooms.tsx +++ b/esp/src/src-react/components/FileBlooms.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import { CommandBar, ICommandBarItemProps } from "@fluentui/react"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { useFile } from "../hooks/file"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; interface FileBloomsProps { cluster?: string; @@ -22,19 +22,19 @@ export const FileBlooms: React.FunctionComponent = ({ const [file, , , refreshData] = useFile(cluster, logicalFile); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "FieldNames", - sort, - filename: "fileBlooms", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { FieldNames: { label: nlsHPCC.FieldNames, sortable: true, width: 320 }, Limit: { label: nlsHPCC.Limit, sortable: true, width: 180 }, Probability: { label: nlsHPCC.Probability, sortable: true, width: 180 }, - } - }); + }; + }, []); React.useEffect(() => { const fileBlooms = file?.Blooms?.DFUFileBloom; @@ -56,10 +56,20 @@ export const FileBlooms: React.FunctionComponent = ({ }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "fileBlooms"); + return } main={ - + } />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/FileDetailsGraph.tsx b/esp/src/src-react/components/FileDetailsGraph.tsx index 4bce6680412..e568fd9a1dd 100644 --- a/esp/src/src-react/components/FileDetailsGraph.tsx +++ b/esp/src/src-react/components/FileDetailsGraph.tsx @@ -3,9 +3,9 @@ import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Image, Link } import * as Utility from "src/Utility"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { useFile } from "../hooks/file"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; function getStateImageName(row) { @@ -40,30 +40,30 @@ export const FileDetailsGraph: React.FunctionComponent = const [file, , , refreshData] = useFile(cluster, logicalFile); const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - sort, - primaryID: "Name", - filename: "graphs", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: { width: 27, selectorType: "checkbox" }, Name: { label: nlsHPCC.Name, sortable: true, - formatter: React.useCallback(function (Name, row) { + formatter: (Name, row) => { return <>   {Name} ; - }, []) + } } - } - }); + }; + }, []); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -106,10 +106,20 @@ export const FileDetailsGraph: React.FunctionComponent = })); }, [file?.Graphs?.ECLGraph, file?.Wuid]); + const copyButtons = useCopyButtons(columns, selection, "graphs"); + return } main={ - + } />; }; diff --git a/esp/src/src-react/components/FileHistory.tsx b/esp/src/src-react/components/FileHistory.tsx index b8c7e0d5e1f..6bce7f58c78 100644 --- a/esp/src/src-react/components/FileHistory.tsx +++ b/esp/src/src-react/components/FileHistory.tsx @@ -4,8 +4,8 @@ import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; import { useConfirm } from "../hooks/confirm"; import { useFileHistory } from "../hooks/file"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; interface FileHistoryProps { @@ -25,13 +25,13 @@ export const FileHistory: React.FunctionComponent = ({ // Grid --- const [history, eraseHistory, refreshData] = useFileHistory(cluster, logicalFile); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "filehistory", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Name: { label: nlsHPCC.Name, sortable: false }, IP: { label: nlsHPCC.IP, sortable: false }, Operation: { label: nlsHPCC.Operation, sortable: false }, @@ -39,8 +39,8 @@ export const FileHistory: React.FunctionComponent = ({ Path: { label: nlsHPCC.Path, sortable: false }, Timestamp: { label: nlsHPCC.TimeStamp, sortable: false }, Workunit: { label: nlsHPCC.Workunit, sortable: false } - } - }); + }; + }, []); const [DeleteConfirm, setShowDeleteConfirm] = useConfirm({ title: nlsHPCC.EraseHistory, @@ -65,11 +65,21 @@ export const FileHistory: React.FunctionComponent = ({ }, ], [history?.length, refreshData, setShowDeleteConfirm]); + const copyButtons = useCopyButtons(columns, selection, "filehistory"); + return } main={ <> - + } diff --git a/esp/src/src-react/components/FileParts.tsx b/esp/src/src-react/components/FileParts.tsx index 21928adc6d1..6cde024778f 100644 --- a/esp/src/src-react/components/FileParts.tsx +++ b/esp/src/src-react/components/FileParts.tsx @@ -3,9 +3,9 @@ import { ICommandBarItemProps, CommandBar } from "@fluentui/react"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; import * as Utility from "src/Utility"; -import { useFluentGrid } from "../hooks/grid"; import { useFile } from "../hooks/file"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; interface FilePartsProps { cluster?: string; @@ -23,32 +23,32 @@ export const FileParts: React.FunctionComponent = ({ const [file, , , refreshData] = useFile(cluster, logicalFile); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "Id", - sort, - filename: "fileParts", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Id: { label: nlsHPCC.Part, sortable: true, width: 80 }, Copy: { label: nlsHPCC.Copy, sortable: true, width: 80 }, Ip: { label: nlsHPCC.IP, sortable: true, width: 80 }, Cluster: { label: nlsHPCC.Cluster, sortable: true, width: 280 }, PartsizeInt64: { label: nlsHPCC.Size, sortable: true, width: 120, - formatter: React.useCallback(function (value, row) { + formatter: (value, row) => { return Utility.safeFormatNum(value); - }, []), + } }, CompressedSize: { label: nlsHPCC.CompressedSize, sortable: true, width: 120, - formatter: React.useCallback(function (value, row) { + formatter: (value, row) => { return Utility.safeFormatNum(value); - }, []) + } }, - } - }); + }; + }, []); React.useEffect(() => { const fileParts = file?.fileParts() ?? []; @@ -72,10 +72,20 @@ export const FileParts: React.FunctionComponent = ({ } ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "fileParts"); + return } main={ - + } />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/Files.tsx b/esp/src/src-react/components/Files.tsx index 81315898f1d..907327039a6 100644 --- a/esp/src/src-react/components/Files.tsx +++ b/esp/src/src-react/components/Files.tsx @@ -11,7 +11,7 @@ import { useConfirm } from "../hooks/confirm"; import { useMyAccount } from "../hooks/user"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushParams } from "../util/history"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { AddToSuperfile } from "./forms/AddToSuperfile"; import { CopyFile } from "./forms/CopyFile"; import { DesprayFile } from "./forms/DesprayFile"; @@ -125,7 +125,7 @@ export const Files: React.FunctionComponent = ({ return formatQuery(filter); }, [filter]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { col1: { width: 16, @@ -191,9 +191,6 @@ export const Files: React.FunctionComponent = ({ }, Parts: { label: nlsHPCC.Parts, width: 40, - formatter: (value, row) => { - return Utility.valueCleanUp(value); - }, }, MinSkew: { label: nlsHPCC.MinSkew, width: 60, formatter: (value, row) => value ? `${Utility.formatDecimal(value / 100)}%` : "" diff --git a/esp/src/src-react/components/GroupMembers.tsx b/esp/src/src-react/components/GroupMembers.tsx index 731d679b561..5830ceb9dfe 100644 --- a/esp/src/src-react/components/GroupMembers.tsx +++ b/esp/src/src-react/components/GroupMembers.tsx @@ -9,7 +9,7 @@ import { useConfirm } from "../hooks/confirm"; import { useBuildInfo } from "../hooks/platform"; import { pushUrl } from "../util/history"; import { HolyGrail } from "../layouts/HolyGrail"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { GroupAddUserForm } from "./forms/GroupAddUser"; import { QuerySortItem } from "src/store/Store"; @@ -55,7 +55,7 @@ export const GroupMembers: React.FunctionComponent = ({ return store ? store : CreateGroupMemberStore(); }, [store]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { username: { label: nlsHPCC.UserName, diff --git a/esp/src/src-react/components/Groups.tsx b/esp/src/src-react/components/Groups.tsx index 9168fca6bf6..3bca83f8067 100644 --- a/esp/src/src-react/components/Groups.tsx +++ b/esp/src/src-react/components/Groups.tsx @@ -8,7 +8,7 @@ import { GroupStore, CreateGroupStore } from "src/ws_access"; import { ShortVerticalDivider } from "./Common"; import { useConfirm } from "../hooks/confirm"; import { useBuildInfo } from "../hooks/platform"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { AddGroupForm } from "./forms/AddGroup"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushUrl } from "../util/history"; @@ -51,7 +51,7 @@ export const Groups: React.FunctionComponent = ({ return store ? store : CreateGroupStore(); }, [store]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { check: { width: 27, label: " ", selectorType: "checkbox" }, name: { diff --git a/esp/src/src-react/components/Helpers.tsx b/esp/src/src-react/components/Helpers.tsx index 1e686d13819..7e391bc9223 100644 --- a/esp/src/src-react/components/Helpers.tsx +++ b/esp/src/src-react/components/Helpers.tsx @@ -1,11 +1,9 @@ import * as React from "react"; import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Link, ScrollablePane, Sticky } from "@fluentui/react"; -import * as domClass from "dojo/dom-class"; import * as ESPRequest from "src/ESPRequest"; -import * as Utility from "src/Utility"; import nlsHPCC from "src/nlsHPCC"; -import { useFluentGrid } from "../hooks/grid"; import { HelperRow, useWorkunitHelpers } from "../hooks/workunit"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; function canShowContent(type: string) { @@ -118,13 +116,14 @@ export const Helpers: React.FunctionComponent = ({ const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [helpers, refreshData] = useWorkunitHelpers(wuid); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "id", - filename: "helpers", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { sel: { width: 27, selectorType: "checkbox" @@ -132,14 +131,14 @@ export const Helpers: React.FunctionComponent = ({ Type: { label: nlsHPCC.Type, width: 160, - formatter: React.useCallback(function (Type, row) { + formatter: (Type, row) => { const target = getTarget(row.id, row); if (target) { const linkText = Type.replace("Slave", "Worker") + (row?.Description ? " (" + row.Description + ")" : ""); return {linkText}; } return Type; - }, []) + } }, Description: { label: nlsHPCC.Description @@ -147,13 +146,10 @@ export const Helpers: React.FunctionComponent = ({ FileSize: { label: nlsHPCC.FileSize, width: 90, - renderCell: React.useCallback(function (object, value, node, options) { - domClass.add(node, "justify-right"); - node.innerText = Utility.valueCleanUp(value); - }, []), + justify: "right" } - } - }); + }; + }, []); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -208,6 +204,8 @@ export const Helpers: React.FunctionComponent = ({ ], [refreshData, selection, uiState.canShowContent, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "helpers"); + // Selection --- React.useEffect(() => { const state = { ...defaultUIState }; @@ -229,6 +227,14 @@ export const Helpers: React.FunctionComponent = ({ - + ; }; diff --git a/esp/src/src-react/components/InfoGrid.tsx b/esp/src/src-react/components/InfoGrid.tsx index 96b0ddc8020..65d763cb4da 100644 --- a/esp/src/src-react/components/InfoGrid.tsx +++ b/esp/src/src-react/components/InfoGrid.tsx @@ -1,9 +1,8 @@ import * as React from "react"; import { Checkbox, CommandBar, ICommandBarItemProps, Link } from "@fluentui/react"; -import * as domClass from "dojo/dom-class"; import nlsHPCC from "src/nlsHPCC"; -import { useFluentGrid } from "../hooks/grid"; import { useWorkunitExceptions } from "../hooks/workunit"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { HolyGrail } from "../layouts/HolyGrail"; function extractGraphInfo(msg) { @@ -36,6 +35,10 @@ export const InfoGrid: React.FunctionComponent = ({ const [filterCounts, setFilterCounts] = React.useState({}); const [exceptions] = useWorkunitExceptions(wuid); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -46,34 +49,28 @@ export const InfoGrid: React.FunctionComponent = ({ ], [filterCounts.error, filterCounts.info, filterCounts.other, filterCounts.warning]); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "id", - filename: "errorwarnings", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Severity: { label: nlsHPCC.Severity, field: "", width: 72, sortable: false, - renderCell: React.useCallback(function (object, value, node, options) { + className: (value, row) => { switch (value) { case "Error": - domClass.add(node, "ErrorCell"); - break; + return "ErrorCell"; case "Alert": - domClass.add(node, "AlertCell"); - break; + return "AlertCell"; case "Warning": - domClass.add(node, "WarningCell"); - break; + return "WarningCell"; } - node.innerText = value; - }, []) + return ""; + } }, Source: { label: nlsHPCC.Source, field: "", width: 144, sortable: false }, Code: { label: nlsHPCC.Code, field: "", width: 45, sortable: false }, Message: { label: nlsHPCC.Message, field: "", sortable: false, - formatter: React.useCallback(function (Message, idx) { + formatter: (Message, idx) => { const info = extractGraphInfo(Message); if (info.graphID && info.subgraphID) { let txt = `Graph ${info.graphID}[${info.subgraphID}]`; @@ -83,13 +80,15 @@ export const InfoGrid: React.FunctionComponent = ({ return <>{info?.prefix}{txt}{info?.message}; } return Message; - }, [wuid]) + } }, Column: { label: nlsHPCC.Col, field: "", width: 36, sortable: false }, LineNo: { label: nlsHPCC.Line, field: "", width: 36, sortable: false }, FileName: { label: nlsHPCC.FileName, field: "", width: 360, sortable: false } - } - }); + }; + }, [wuid]); + + const copyButtons = useCopyButtons(columns, selection, "errorwarnings"); React.useEffect(() => { const filterCounts = { @@ -153,7 +152,15 @@ export const InfoGrid: React.FunctionComponent = ({ return } main={ - + } />; }; diff --git a/esp/src/src-react/components/LogViewer.tsx b/esp/src/src-react/components/LogViewer.tsx index 88c6c912a78..127ac38c5aa 100644 --- a/esp/src/src-react/components/LogViewer.tsx +++ b/esp/src/src-react/components/LogViewer.tsx @@ -1,11 +1,11 @@ import * as React from "react"; import { Checkbox, CommandBar, ICommandBarItemProps } from "@fluentui/react"; +import { Level } from "@hpcc-js/util"; +import { logColor } from "src/Utility"; import nlsHPCC from "src/nlsHPCC"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; import { useECLWatchLogger } from "../hooks/logging"; -import { Level } from "@hpcc-js/util"; -import { logColor } from "src/Utility"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; interface LogViewerProps { } @@ -20,6 +20,10 @@ export const LogViewer: React.FunctionComponent = ({ const [filterCounts, setFilterCounts] = React.useState({}); const [log, lastUpdate] = useECLWatchLogger(); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -30,26 +34,25 @@ export const LogViewer: React.FunctionComponent = ({ ], [filterCounts.error, filterCounts.info, filterCounts.other, filterCounts.warning]); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "dateTime", - filename: "errorwarnings", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { dateTime: { label: nlsHPCC.Time, width: 160, sortable: false }, level: { label: nlsHPCC.Severity, width: 112, sortable: false, - formatter: React.useCallback(level => { + formatter: level => { const colors = logColor(level); const styles = { backgroundColor: colors.background, padding: "2px 6px", color: colors.foreground }; return {Level[level].toUpperCase()}; - }, []) + } }, id: { label: nlsHPCC.Source, width: 212, sortable: false }, message: { label: nlsHPCC.Message, sortable: false } - } - }); + }; + }, []); + + const copyButtons = useCopyButtons(columns, selection, "errorwarnings"); React.useEffect(() => { const filterCounts = { @@ -98,7 +101,13 @@ export const LogViewer: React.FunctionComponent = ({ return } main={ - - } + } />; }; diff --git a/esp/src/src-react/components/Logs.tsx b/esp/src/src-react/components/Logs.tsx index ef60514ad05..f404080986c 100644 --- a/esp/src/src-react/components/Logs.tsx +++ b/esp/src/src-react/components/Logs.tsx @@ -8,7 +8,7 @@ import nlsHPCC from "src/nlsHPCC"; import { logColor } from "src/Utility"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushParams } from "../util/history"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { Filter } from "./forms/Filter"; import { Fields } from "./forms/Fields"; import { ShortVerticalDivider } from "./Common"; @@ -113,7 +113,7 @@ export const Logs: React.FunctionComponent = ({ return formatQuery(filter); }, [filter, now, wuid]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { timestamp: { label: nlsHPCC.TimeStamp, width: 140, sortable: false, }, message: { label: nlsHPCC.Message, sortable: false, }, diff --git a/esp/src/src-react/components/Monitoring.tsx b/esp/src/src-react/components/Monitoring.tsx index 832fb1b9b08..09495e61115 100644 --- a/esp/src/src-react/components/Monitoring.tsx +++ b/esp/src/src-react/components/Monitoring.tsx @@ -2,11 +2,11 @@ import * as React from "react"; import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Image, Link } from "@fluentui/react"; import { MachineService } from "@hpcc-js/comms"; import { ShortVerticalDivider } from "./Common"; -import { tree } from "./DojoGrid"; -import { useFluentGrid } from "../hooks/grid"; -import { HolyGrail } from "../layouts/HolyGrail"; import * as Utility from "src/Utility"; import nlsHPCC from "src/nlsHPCC"; +import { tree } from "./DojoGrid"; +import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; function getStatusImageName(row) { switch (row.Status) { @@ -36,53 +36,50 @@ export const Monitoring: React.FunctionComponent = ({ const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort: { attribute: "Name", "descending": false }, - filename: "monitoring", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { StatusID: { label: "", width: 0, sortable: false, hidden: true }, ComponentType: tree({ label: "Name", sortable: true, width: 200, - formatter: function (Name, row) { + formatter: (Name, row) => { return ; } }), StatusDetails: { label: "Details", sortable: false }, URL: { label: "URL", width: 200, sortable: false, - formatter: React.useCallback(function (Name, row) { + formatter: (Name, row) => { if (Name) { return {Name}; } else { return ""; } - }, []) + } }, EndPoint: { label: "IP", sortable: true, width: 140 }, TimeReportedStr: { label: "Time Reported", width: 140, sortable: true }, Status: { label: nlsHPCC.Severity, width: 130, sortable: false, - formatter: React.useCallback(function (object, value, node, options) { + className: (value, row) => { switch (value) { case "Error": - node.classList.add("ErrorCell"); - break; + return "ErrorCell"; + case "Alert": + return "AlertCell"; case "Warning": - node.classList.add("WarningCell"); - break; - case "Normal": - node.classList.add("NormalCell"); - break; + return "WarningCell"; } - node.innerText = value; - }, []) + return ""; + } } - } - }); + }; + }, []); const refreshData = React.useCallback(() => { machine.GetComponentStatus({ @@ -127,6 +124,8 @@ export const Monitoring: React.FunctionComponent = ({ } ], [refreshData, selection, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "monitoring"); + // Selection --- React.useEffect(() => { const state = { ...defaultUIState }; @@ -137,7 +136,15 @@ export const Monitoring: React.FunctionComponent = ({ return } main={ - + } />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/PackageMapParts.tsx b/esp/src/src-react/components/PackageMapParts.tsx index 111d712b261..45a6dfaf52a 100644 --- a/esp/src/src-react/components/PackageMapParts.tsx +++ b/esp/src/src-react/components/PackageMapParts.tsx @@ -6,12 +6,12 @@ import * as parser from "dojox/xml/parser"; import * as WsPackageMaps from "src/WsPackageMaps"; import nlsHPCC from "src/nlsHPCC"; import { useConfirm } from "../hooks/confirm"; -import { useFluentGrid } from "../hooks/grid"; import { pushUrl } from "../util/history"; +import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; import { AddPackageMapPart } from "./forms/AddPackageMapPart"; import { selector } from "./DojoGrid"; -import { HolyGrail } from "../layouts/HolyGrail"; const logger = scopedLogger("../components/PackageMapParts.tsx"); @@ -31,23 +31,23 @@ export const PackageMapParts: React.FunctionComponent = ({ const [showAddPartForm, setShowAddPartForm] = React.useState(false); const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "Part", - sort: { attribute: "Part", descending: false }, - filename: "packageMapParts", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: selector({ width: 27, selectorType: "checkbox" }), Part: { label: nlsHPCC.Parts, - formatter: React.useCallback(function (part, row) { + formatter: (part, row) => { return {part}; - }, [name]) + } }, - } - }); + }; + }, [name]); const refreshData = React.useCallback(() => { WsPackageMaps.getPackageMapById({ packageMap: name }) @@ -122,6 +122,8 @@ export const PackageMapParts: React.FunctionComponent = ({ }, ], [name, refreshData, selection, setShowDeleteConfirm, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "packageMapParts"); + React.useEffect(() => { WsPackageMaps.PackageMapQuery({}) .then(({ ListPackagesResponse }) => { @@ -147,8 +149,15 @@ export const PackageMapParts: React.FunctionComponent = ({ } main={ - - } + } /> } = ({ const [activeMapValidationResult, setActiveMapValidationResult] = React.useState(nlsHPCC.ValidateResultHere); const [contentsXml, setContentsXml] = React.useState(""); const [contentsValidationResult, setContentsValidationResult] = React.useState(nlsHPCC.ValidateResultHere); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); const changeActiveMapTarget = React.useCallback((evt, option) => { setActiveMapTarget(option.key.toString()); @@ -184,36 +188,32 @@ export const PackageMaps: React.FunctionComponent = ({ const [data, setData] = React.useState([]); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "Id", - sort: { attribute: "Id", descending: true }, - filename: "packageMaps", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: selector({ width: 27, selectorType: "checkbox" }), Id: { label: nlsHPCC.PackageMap, - formatter: React.useCallback(function (Id, row) { + formatter: (Id, row) => { return {Id}; - }, []) + } }, Target: { label: nlsHPCC.Target }, Process: { label: nlsHPCC.ProcessFilter }, Active: { label: nlsHPCC.Active, - formatter: React.useCallback(function (active) { + formatter: (active) => { if (active === true) { return "A"; } return ""; - }, []) + } }, Description: { label: nlsHPCC.Description } - } - }); + }; + }, []); const refreshData = React.useCallback(() => { packageService.ListPackages({ @@ -338,6 +338,8 @@ export const PackageMaps: React.FunctionComponent = ({ }, ], [hasFilter, refreshData, selection, setShowDeleteConfirm, store, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "packageMaps"); + // Filter --- const filterFields: Fields = {}; for (const field in FilterFields) { @@ -416,7 +418,15 @@ export const PackageMaps: React.FunctionComponent = ({ } - main={} + main={} /> diff --git a/esp/src/src-react/components/Pods.tsx b/esp/src/src-react/components/Pods.tsx index 3d69afffdc9..69d369bb94d 100644 --- a/esp/src/src-react/components/Pods.tsx +++ b/esp/src/src-react/components/Pods.tsx @@ -4,7 +4,7 @@ import { SizeMe } from "react-sizeme"; import nlsHPCC from "src/nlsHPCC"; import { HolyGrail } from "../layouts/HolyGrail"; import { usePods } from "../hooks/cloud"; -import { useFluentGrid } from "../hooks/grid"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; import { JSONSourceEditor } from "./SourceEditor"; @@ -21,13 +21,14 @@ export const PodsJSON: React.FunctionComponent = ({ export const Pods: React.FunctionComponent = ({ }) => { const [pods, refreshData] = usePods(); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data: pods, - primaryID: "name", - filename: "pods", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { name: { label: nlsHPCC.Name, width: 300 }, container: { label: nlsHPCC.Container, width: 120 }, port: { label: nlsHPCC.Port, width: 64 }, @@ -35,8 +36,8 @@ export const Pods: React.FunctionComponent = ({ status: { label: nlsHPCC.Status, width: 90 }, restarts: { label: nlsHPCC.Restarts, width: 64 }, age: { label: nlsHPCC.Age, width: 90 } - } - }); + }; + }, []); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -47,13 +48,23 @@ export const Pods: React.FunctionComponent = ({ { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "pods"); + return } main={ {({ size }) =>
- +
}
diff --git a/esp/src/src-react/components/ProtectedBy.tsx b/esp/src/src-react/components/ProtectedBy.tsx index 6a432070a02..9d92fef5d73 100644 --- a/esp/src/src-react/components/ProtectedBy.tsx +++ b/esp/src/src-react/components/ProtectedBy.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import { CommandBar, ICommandBarItemProps } from "@fluentui/react"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { useFile } from "../hooks/file"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; interface ProtectedByProps { cluster: string; @@ -22,18 +22,18 @@ export const ProtectedBy: React.FunctionComponent = ({ const [file, , , refreshData] = useFile(cluster, logicalFile); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "Owner", - sort, - filename: "protectedBy", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Owner: { label: nlsHPCC.Owner, width: 320 }, Modified: { label: nlsHPCC.Modified, width: 320 }, - } - }); + }; + }, []); React.useEffect(() => { const results = file?.ProtectList?.DFUFileProtect; @@ -56,10 +56,19 @@ export const ProtectedBy: React.FunctionComponent = ({ }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "protectedBy"); + return } main={ - - } + } />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/Queries.tsx b/esp/src/src-react/components/Queries.tsx index 38ccc364f4a..c3421a928b5 100644 --- a/esp/src/src-react/components/Queries.tsx +++ b/esp/src/src-react/components/Queries.tsx @@ -8,7 +8,7 @@ import { useConfirm } from "../hooks/confirm"; import { useMyAccount } from "../hooks/user"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushParams } from "../util/history"; -import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState } from "./controls/Grid"; +import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { Fields } from "./forms/Fields"; import { Filter } from "./forms/Filter"; import { ShortVerticalDivider } from "./Common"; @@ -85,7 +85,7 @@ export const Queries: React.FunctionComponent = ({ return formatQuery(filter); }, [filter]); - const columns = React.useMemo(() => { + const columns = React.useMemo((): FluentColumns => { return { col1: { width: 16, diff --git a/esp/src/src-react/components/QueryErrors.tsx b/esp/src/src-react/components/QueryErrors.tsx index 21192d10414..67e7eaa87ac 100644 --- a/esp/src/src-react/components/QueryErrors.tsx +++ b/esp/src/src-react/components/QueryErrors.tsx @@ -4,8 +4,8 @@ import { scopedLogger } from "@hpcc-js/util"; import * as ESPQuery from "src/ESPQuery"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; const logger = scopedLogger("../components/QueryErrors.tsx"); @@ -27,19 +27,19 @@ export const QueryErrors: React.FunctionComponent = ({ return ESPQuery.Get(querySet, queryId); }, [querySet, queryId]); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "queryErrors", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Cluster: { label: nlsHPCC.Cluster, width: 140 }, Errors: { label: nlsHPCC.Errors }, State: { label: nlsHPCC.State, width: 120 }, - } - }); + }; + }, []); const refreshData = React.useCallback(() => { query?.getDetails() @@ -72,8 +72,18 @@ export const QueryErrors: React.FunctionComponent = ({ }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "queryErrors"); + return } - main={} + main={} />; }; diff --git a/esp/src/src-react/components/QueryGraphs.tsx b/esp/src/src-react/components/QueryGraphs.tsx index 1205e942cd7..8535274f47b 100644 --- a/esp/src/src-react/components/QueryGraphs.tsx +++ b/esp/src/src-react/components/QueryGraphs.tsx @@ -5,8 +5,8 @@ import * as ESPQuery from "src/ESPQuery"; import * as Utility from "src/Utility"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; const logger = scopedLogger("src-react/components/QueryGraphs.tsx"); @@ -39,28 +39,28 @@ export const QueryGraphs: React.FunctionComponent = ({ return ESPQuery.Get(querySet, queryId); }, [querySet, queryId]); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "queryGraphs", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: { width: 27, selectorType: "checkbox" }, Name: { label: nlsHPCC.Name, - formatter: React.useCallback(function (Name, row) { + formatter: (Name, row) => { return <>   {Name} ; - }, []) + } }, Type: { label: nlsHPCC.Type, width: 72 }, - } - }); + }; + }, []); const refreshData = React.useCallback(() => { query?.getDetails() @@ -96,8 +96,18 @@ export const QueryGraphs: React.FunctionComponent = ({ }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "queryGraphs"); + return } - main={} + main={} />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/QueryLibrariesUsed.tsx b/esp/src/src-react/components/QueryLibrariesUsed.tsx index c398a35e01a..8c15d9b9b5b 100644 --- a/esp/src/src-react/components/QueryLibrariesUsed.tsx +++ b/esp/src/src-react/components/QueryLibrariesUsed.tsx @@ -4,8 +4,8 @@ import { scopedLogger } from "@hpcc-js/util"; import * as ESPQuery from "src/ESPQuery"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; const logger = scopedLogger("src-react/components/QueryLibrariesUsed.tsx"); @@ -27,17 +27,17 @@ export const QueryLibrariesUsed: React.FunctionComponent([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "queryLibraries", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Name: { label: nlsHPCC.LibrariesUsed } - } - }); + }; + }, []); const refreshData = React.useCallback(() => { query?.getDetails() @@ -68,8 +68,18 @@ export const QueryLibrariesUsed: React.FunctionComponent} - main={} + main={} />; }; diff --git a/esp/src/src-react/components/QueryLogicalFiles.tsx b/esp/src/src-react/components/QueryLogicalFiles.tsx index 8865fae7d28..68f678e5ec9 100644 --- a/esp/src/src-react/components/QueryLogicalFiles.tsx +++ b/esp/src/src-react/components/QueryLogicalFiles.tsx @@ -4,10 +4,10 @@ import { scopedLogger } from "@hpcc-js/util"; import * as ESPQuery from "src/ESPQuery"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushUrl } from "../util/history"; import { ShortVerticalDivider } from "./Common"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; const logger = scopedLogger("../components/QueryLogicalFiles.tsx"); @@ -34,23 +34,23 @@ export const QueryLogicalFiles: React.FunctionComponent }, [querySet, queryId]); const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "queryLogicalFiles", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: { selectorType: "checkbox", width: 25 }, File: { label: nlsHPCC.File, - formatter: React.useCallback(function (item, row) { + formatter: (item, row) => { return {item}; - }, []) - }, - } - }); + } + } + }; + }, []); const refreshData = React.useCallback(() => { query?.getDetails() @@ -94,6 +94,8 @@ export const QueryLogicalFiles: React.FunctionComponent }, ], [querySet, refreshData, selection, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "queryLogicalFiles"); + // Selection --- React.useEffect(() => { const state = { ...defaultUIState }; @@ -107,6 +109,14 @@ export const QueryLogicalFiles: React.FunctionComponent return } - main={} + main={} />; }; diff --git a/esp/src/src-react/components/QuerySummaryStats.tsx b/esp/src/src-react/components/QuerySummaryStats.tsx index 38eadd5dcf9..d944e84813b 100644 --- a/esp/src/src-react/components/QuerySummaryStats.tsx +++ b/esp/src/src-react/components/QuerySummaryStats.tsx @@ -2,8 +2,8 @@ import * as React from "react"; import { CommandBar, ICommandBarItemProps } from "@fluentui/react"; import { Query } from "@hpcc-js/comms"; import nlsHPCC from "src/nlsHPCC"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; interface QuerySummaryStatsProps { querySet: string; @@ -19,14 +19,14 @@ export const QuerySummaryStats: React.FunctionComponent return Query.attach({ baseUrl: "" }, querySet, queryId); }, [querySet, queryId]); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort: { attribute: "__hpcc_id", descending: false }, - filename: "querySummaryStats", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { Endpoint: { label: nlsHPCC.EndPoint, width: 72, sortable: true }, Status: { label: nlsHPCC.Status, width: 72, sortable: true }, StartTime: { label: nlsHPCC.StartTime, width: 160, sortable: true }, @@ -40,8 +40,8 @@ export const QuerySummaryStats: React.FunctionComponent TimeMaxTotalExecuteMinutes: { label: nlsHPCC.TimeMaxTotalExecuteMinutes, width: 88, sortable: true }, Percentile97: { label: nlsHPCC.Percentile97, width: 80, sortable: true }, Percentile97Estimate: { label: nlsHPCC.Percentile97Estimate, sortable: true } - } - }); + }; + }, []); const refreshData = React.useCallback(() => { query?.fetchSummaryStats().then(({ StatsList }) => { @@ -80,8 +80,18 @@ export const QuerySummaryStats: React.FunctionComponent }, ], [refreshData]); + const copyButtons = useCopyButtons(columns, selection, "querySummaryStats"); + return } - main={} + main={} />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/QuerySuperFiles.tsx b/esp/src/src-react/components/QuerySuperFiles.tsx index c9214986114..6c200e7fd6f 100644 --- a/esp/src/src-react/components/QuerySuperFiles.tsx +++ b/esp/src/src-react/components/QuerySuperFiles.tsx @@ -4,10 +4,10 @@ import { scopedLogger } from "@hpcc-js/util"; import * as ESPQuery from "src/ESPQuery"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { HolyGrail } from "../layouts/HolyGrail"; import { pushUrl } from "../util/history"; import { ShortVerticalDivider } from "./Common"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; const logger = scopedLogger("src-react/components/QuerySuperFiles.tsx"); @@ -34,23 +34,23 @@ export const QuerySuperFiles: React.FunctionComponent = ({ }, [querySet, queryId]); const [uiState, setUIState] = React.useState({ ...defaultUIState }); const [data, setData] = React.useState([]); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "__hpcc_id", - sort, - filename: "querySuperFiles", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: { selectorType: "checkbox", width: 25 }, File: { label: nlsHPCC.File, - formatter: React.useCallback(function (item, row) { + formatter: (item, row) => { return {item}; - }, []) - }, - } - }); + } + } + }; + }, []); const refreshData = React.useCallback(() => { query?.getDetails() @@ -93,6 +93,8 @@ export const QuerySuperFiles: React.FunctionComponent = ({ }, ], [querySet, refreshData, selection, uiState.hasSelection]); + const copyButtons = useCopyButtons(columns, selection, "querySuperFiles"); + // Selection --- React.useEffect(() => { const state = { ...defaultUIState }; @@ -106,6 +108,14 @@ export const QuerySuperFiles: React.FunctionComponent = ({ return } - main={} + main={} />; }; \ No newline at end of file diff --git a/esp/src/src-react/components/Resources.tsx b/esp/src/src-react/components/Resources.tsx index b17a5ae143d..08797dc3315 100644 --- a/esp/src/src-react/components/Resources.tsx +++ b/esp/src/src-react/components/Resources.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Link, ScrollablePane, Sticky } from "@fluentui/react"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useFluentGrid } from "../hooks/grid"; import { useWorkunitResources } from "../hooks/workunit"; import { updateParam } from "../util/history"; +import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; import { IFrame } from "./IFrame"; @@ -33,27 +33,26 @@ export const Resources: React.FunctionComponent = ({ const [resources, , , refreshData] = useWorkunitResources(wuid); const [data, setData] = React.useState([]); const [webUrl, setWebUrl] = React.useState(""); + const { + selection, setSelection, + setTotal, + refreshTable } = useFluentStoreState({}); // Grid --- - const { Grid, selection, copyButtons } = useFluentGrid({ - data, - primaryID: "DisplayPath", - alphaNumColumns: { Name: true, Value: true }, - sort, - filename: "resources", - columns: { + const columns = React.useMemo((): FluentColumns => { + return { col1: { width: 27, selectorType: "checkbox" }, DisplayPath: { label: nlsHPCC.Name, sortable: true, - formatter: React.useCallback(function (url, row) { + formatter: (url, row) => { return {url}; - }, [wuid]) + } } - } - }); + }; + }, [wuid]); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -82,6 +81,8 @@ export const Resources: React.FunctionComponent = ({ }, ], [refreshData, selection, uiState.hasSelection, wuid, preview]); + const copyButtons = useCopyButtons(columns, selection, "resources"); + // Selection --- React.useEffect(() => { const state = { ...defaultUIState }; @@ -113,6 +114,15 @@ export const Resources: React.FunctionComponent = ({ {preview && webUrl ?