From 5eeb875356f0ca56f78738cac6d0e47a0e471f8d Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Thu, 12 Dec 2024 11:20:22 +0000 Subject: [PATCH] HPCC-33117 Switch Workunits page to use @hpcc-js/comms fully WU Monitoring is opt in, rather than opt out, which is preferable for the React WUs page. Signed-off-by: Gordon Smith --- esp/src/src-react/comms/workunit.ts | 71 ++++++++++++++++++++++ esp/src/src-react/components/Workunits.tsx | 17 +++--- 2 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 esp/src/src-react/comms/workunit.ts diff --git a/esp/src/src-react/comms/workunit.ts b/esp/src/src-react/comms/workunit.ts new file mode 100644 index 00000000000..26debedffa9 --- /dev/null +++ b/esp/src/src-react/comms/workunit.ts @@ -0,0 +1,71 @@ +import { Workunit, WorkunitsService, type WsWorkunits } from "@hpcc-js/comms"; +import { Thenable } from "src/store/Deferred"; +import { Paged } from "src/store/Paged"; +import { BaseStore } from "src/store/Store"; +import { wuidToDateTime } from "src/Utility"; + +const service = new WorkunitsService({ baseUrl: "" }); + +export type WUQueryStore = BaseStore; + +export function CreateWUQueryStore(): BaseStore { + const store = new Paged({ + start: "PageStartFrom", + count: "PageSize", + sortBy: "Sortby", + descending: "Descending" + }, "Wuid", (request, abortSignal): Thenable<{ data: Workunit[], total: number }> => { + if (request.Sortby && request.Sortby === "TotalClusterTime") { + request.Sortby = "ClusterTime"; + } + return service.WUQuery(request, abortSignal).then(response => { + const page = { + start: undefined, + end: undefined + }; + const data = response.Workunits.ECLWorkunit.map((wu): Workunit => { + const start = wuidToDateTime(wu.Wuid); + if (!page.start || page.start > start) { + page.start = start; + } + let timePartsSection = 0; + const end = new Date(start); + const timeParts = wu.TotalClusterTime?.split(":") ?? []; + while (timeParts.length) { + const timePart = timeParts.pop(); + switch (timePartsSection) { + case 0: + end.setSeconds(end.getSeconds() + +timePart); + break; + case 1: + end.setMinutes(end.getMinutes() + +timePart); + break; + case 2: + end.setHours(end.getHours() + +timePart); + break; + case 3: + end.setDate(end.getDate() + +timePart); + break; + } + ++timePartsSection; + } + if (!page.end || page.end < end) { + page.end = end; + } + const retVal = Workunit.attach(service, wu.Wuid, wu); + // HPCC-33121 - Move to @hpcc-js/comms --- + retVal["__timeline_timings"] = { + start, + end, + page + }; + return retVal; + }); + return { + data, + total: response.NumWUs + }; + }); + }); + return store; +} diff --git a/esp/src/src-react/components/Workunits.tsx b/esp/src/src-react/components/Workunits.tsx index 5826e790dde..b53ba30dabc 100644 --- a/esp/src/src-react/components/Workunits.tsx +++ b/esp/src/src-react/components/Workunits.tsx @@ -1,8 +1,9 @@ import * as React from "react"; import { CommandBar, ContextualMenuItemType, DetailsRow, ICommandBarItemProps, IDetailsRowProps, Icon, Image, Link } from "@fluentui/react"; import { hsl as d3Hsl } from "@hpcc-js/common"; +import { Workunit } from "@hpcc-js/comms"; import { SizeMe } from "react-sizeme"; -import { CreateWUQueryStore, defaultSort, emptyFilter, Get, WUQueryStore, formatQuery } from "src/ESPWorkunit"; +import { defaultSort, emptyFilter, getStateImage, WUQueryStore, formatQuery } from "src/ESPWorkunit"; import * as WsWorkunits from "src/WsWorkunits"; import { formatCost } from "src/Session"; import { userKeyValStore } from "src/KeyValStore"; @@ -14,6 +15,7 @@ import { useLogicalClustersPalette } from "../hooks/platform"; import { calcSearch, pushParams } from "../util/history"; import { useHasFocus, useIsMounted } from "../hooks/util"; import { HolyGrail } from "../layouts/HolyGrail"; +import { CreateWUQueryStore } from "../comms/workunit"; import { FluentPagedGrid, FluentPagedFooter, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { Fields } from "./forms/Fields"; import { Filter } from "./forms/Filter"; @@ -122,11 +124,10 @@ export const Workunits: React.FunctionComponent = ({ Wuid: { label: nlsHPCC.WUID, width: 120, sortable: true, - formatter: (Wuid, row) => { - const wu = Get(Wuid); + formatter: (Wuid: string, wu: Workunit) => { const search = calcSearch(filter); return <> - +   {Wuid} ; @@ -294,10 +295,10 @@ export const Workunits: React.FunctionComponent = ({ }, [selection]); const renderRowTimings = React.useCallback((props: IDetailsRowProps, size: { readonly width: number; readonly height: number; }) => { - if (showTimeline && props?.item?.timings) { - const total = props.item.timings.page.end - props.item.timings.page.start; - const startPct = 100 - (props.item.timings.start - props.item.timings.page.start) / total * 100; - const endPct = 100 - (props.item.timings.end - props.item.timings.page.start) / total * 100; + if (showTimeline && props?.item?.__timeline_timings) { + const total = props.item.__timeline_timings.page.end - props.item.__timeline_timings.page.start; + const startPct = 100 - (props.item.__timeline_timings.start - props.item.__timeline_timings.page.start) / total * 100; + const endPct = 100 - (props.item.__timeline_timings.end - props.item.__timeline_timings.page.start) / total * 100; const backgroundColor = palette(props.item.Cluster); const borderColor = d3Hsl(backgroundColor).darker().toString();