瀏覽代碼

HPCC-26446 Enable favourites for all pages

Includes minor fixes

Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
Gordon Smith 3 年之前
父節點
當前提交
6296baa951

+ 0 - 12
esp/src/eclwatch/DFUQueryWidget.js

@@ -629,18 +629,6 @@ define([
                             return "";
                         }
                     },
-                    IsKeyFile: {
-                        width: 25, sortable: false,
-                        renderHeaderCell: function (node) {
-                            node.innerHTML = Utility.getImageHTML("index.png", context.i18n.Index);
-                        },
-                        formatter: function (keyfile, row) {
-                            if (row.ContentType === "key") {
-                                return Utility.getImageHTML("index.png");
-                            }
-                            return "";
-                        }
-                    },
                     __hpcc_displayName: tree({
                         label: this.i18n.LogicalName, width: 600,
                         formatter: function (name, row) {

+ 1 - 1
esp/src/eclwatch/HPCCPlatformWidget.js

@@ -441,7 +441,7 @@ define([
         },
 
         _onOpenModernECLWatch: function (evt) {
-            window.open("/esp/files/index.html");
+            window.location.href = "/esp/files/index.html";
         },
 
         _onOpenErrWarn: function (evt) {

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

@@ -5,7 +5,6 @@ import { SizeMe } from "react-sizeme";
 import nlsHPCC from "src/nlsHPCC";
 import * as FileSpray from "src/FileSpray";
 import * as ESPDFUWorkunit from "src/ESPDFUWorkunit";
-import { useFavorite } from "../hooks/favorite";
 import { pivotItemStyle } from "../layouts/pivot";
 import { pushUrl } from "../util/history";
 import { ShortVerticalDivider } from "./Common";
@@ -29,7 +28,6 @@ export const DFUWorkunitDetails: React.FunctionComponent<DFUWorkunitDetailsProps
     const [wuXML, setWuXML] = React.useState("");
     const [jobname, setJobname] = React.useState("");
     const [_protected, setProtected] = React.useState(false);
-    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
 
     React.useEffect(() => {
         setWorkunit(ESPDFUWorkunit.Get(wuid));
@@ -98,17 +96,7 @@ export const DFUWorkunitDetails: React.FunctionComponent<DFUWorkunitDetailsProps
     ], [_protected, canAbort, canDelete, canSave, jobname, workunit, wuid]);
 
     const rightButtons = React.useMemo((): ICommandBarItemProps[] => [
-        {
-            key: "star", iconProps: { iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" },
-            onClick: () => {
-                if (isFavorite) {
-                    removeFavorite();
-                } else {
-                    addFavorite();
-                }
-            }
-        }
-    ], [addFavorite, isFavorite, removeFavorite]);
+    ], []);
 
     return <SizeMe monitorHeight>{({ size }) =>
         <Pivot

+ 0 - 12
esp/src/src-react/components/Files.tsx

@@ -98,18 +98,6 @@ export const Files: React.FunctionComponent<FilesProps> = ({
                 return "";
             }
         },
-        IsKeyFile: {
-            width: 25, sortable: false,
-            renderHeaderCell: function (node) {
-                node.innerHTML = Utility.getImageHTML("index.png", nlsHPCC.Index);
-            },
-            formatter: function (keyfile, row) {
-                if (row.ContentType === "key") {
-                    return Utility.getImageHTML("index.png");
-                }
-                return "";
-            }
-        },
         __hpcc_displayName: tree({
             label: nlsHPCC.LogicalName, width: 600,
             formatter: function (name, row) {

+ 9 - 2
esp/src/src-react/components/Menu.tsx

@@ -4,7 +4,7 @@ import { useConst } from "@fluentui/react-hooks";
 import nlsHPCC from "src/nlsHPCC";
 import { MainNav, routes } from "../routes";
 import { pushUrl } from "../util/history";
-import { useFavorites, useHistory } from "../hooks/favorite";
+import { useFavorite, useFavorites, useHistory } from "../hooks/favorite";
 import { useUserTheme } from "../hooks/theme";
 import { Breadcrumbs } from "./Breadcrumbs";
 
@@ -185,6 +185,7 @@ export const SubNavigation: React.FunctionComponent<SubNavigationProps> = ({
     const theme = useTheme();
 
     const [favorites] = useFavorites();
+    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
     const [history] = useHistory();
 
     const mainNav = React.useMemo(() => {
@@ -231,7 +232,13 @@ export const SubNavigation: React.FunctionComponent<SubNavigationProps> = ({
             </Stack.Item>
             <Stack.Item align="center" grow={0}>
                 <IconButton title={nlsHPCC.Advanced} iconProps={{ iconName: "History" }} menuProps={{ items: history }} />
-                <IconButton title={nlsHPCC.Advanced} iconProps={{ iconName: favoriteMenu.length === 0 ? "FavoriteStar" : "FavoriteStarFill" }} menuProps={{ items: favoriteMenu }} />
+                <IconButton title={nlsHPCC.Advanced} iconProps={{ iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" }} menuProps={{ items: favoriteMenu }} split onClick={() => {
+                    if (isFavorite) {
+                        removeFavorite();
+                    } else {
+                        addFavorite();
+                    }
+                }} styles={{ splitButtonMenuButton: { backgroundColor: theme.palette.themeLighter, border: "none" } }} />
             </Stack.Item>
         </Stack>
     </div>;

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

@@ -5,7 +5,6 @@ import { Table } from "@hpcc-js/dgrid";
 import nlsHPCC from "src/nlsHPCC";
 import { WUTimelinePatched } from "src/Timings";
 import { useMetricsOptions, useWorkunitMetrics } from "../hooks/metrics";
-import { useFavorite } from "../hooks/favorite";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { AutosizeHpccJSComponent } from "../layouts/HpccJSAdapter";
 import { DockPanel, DockPanelItems, ReactWidget } from "../layouts/DockPanel";
@@ -36,7 +35,6 @@ export const Metrics: React.FunctionComponent<MetricsProps> = ({
     const [metrics, _columns, _activities, _properties, _measures, _scopeTypes] = useWorkunitMetrics(wuid);
     const [showMetricOptions, setShowMetricOptions] = React.useState(false);
     const [options] = useMetricsOptions();
-    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
 
     //  Command Bar  ---
     const buttons = React.useMemo((): ICommandBarItemProps[] => [
@@ -54,17 +52,7 @@ export const Metrics: React.FunctionComponent<MetricsProps> = ({
     ], []);
 
     const rightButtons = React.useMemo((): ICommandBarItemProps[] => [
-        {
-            key: "star", iconProps: { iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" },
-            onClick: () => {
-                if (isFavorite) {
-                    removeFavorite();
-                } else {
-                    addFavorite();
-                }
-            }
-        },
-    ], [addFavorite, isFavorite, removeFavorite]);
+    ], []);
 
     //  Timeline ---
     const timeline = useConst(() => new WUTimelinePatched()

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

@@ -5,7 +5,6 @@ import { scopedLogger } from "@hpcc-js/util";
 import nlsHPCC from "src/nlsHPCC";
 import * as WsWorkunits from "src/WsWorkunits";
 import * as ESPQuery from "src/ESPQuery";
-import { useFavorite } from "../hooks/favorite";
 import { DojoAdapter } from "../layouts/DojoAdapter";
 import { pivotItemStyle } from "../layouts/pivot";
 import { pushUrl } from "../util/history";
@@ -32,7 +31,6 @@ export const QueryDetails: React.FunctionComponent<QueryDetailsProps> = ({
     const [query, setQuery] = React.useState<any>();
     const [suspended, setSuspended] = React.useState(false);
     const [activated, setActivated] = React.useState(false);
-    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
 
     const canSave = query && (
         suspended !== query?.Suspended ||
@@ -86,17 +84,7 @@ export const QueryDetails: React.FunctionComponent<QueryDetailsProps> = ({
     ], [activated, canSave, query, queryId, querySet, suspended]);
 
     const rightButtons = React.useMemo((): ICommandBarItemProps[] => [
-        {
-            key: "star", iconProps: { iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" },
-            onClick: () => {
-                if (isFavorite) {
-                    removeFavorite();
-                } else {
-                    addFavorite();
-                }
-            }
-        }
-    ], [addFavorite, isFavorite, removeFavorite]);
+    ], []);
 
     React.useEffect(() => {
         setQuery(ESPQuery.Get(querySet, queryId));

+ 1 - 14
esp/src/src-react/components/Result.tsx

@@ -7,7 +7,6 @@ import { WUResult } from "@hpcc-js/eclwatch";
 import nlsHPCC from "src/nlsHPCC";
 import { ESPBase } from "src/ESPBase";
 import { csvEncode } from "src/Utility";
-import { useFavorite } from "../hooks/favorite";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { AutosizeHpccJSComponent } from "../layouts/HpccJSAdapter";
 import { pushParams } from "../util/history";
@@ -238,7 +237,6 @@ export const Result: React.FunctionComponent<ResultProps> = ({
     const [result] = React.useState<CommsResult>(resultTable.calcResult());
     const [FilterFields, setFilterFields] = React.useState<Fields>({});
     const [showFilter, setShowFilter] = React.useState(false);
-    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
 
     React.useEffect(() => {
         result?.fetchXMLSchema().then(() => {
@@ -298,18 +296,7 @@ export const Result: React.FunctionComponent<ResultProps> = ({
                     { key: "csv", text: nlsHPCC.CSV, onClick: () => doDownload("csv", wuid, result.Sequence) },
                 ]
             }
-        },
-        {
-            key: "star", iconProps: { iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" },
-            onClick: () => {
-                if (isFavorite) {
-                    removeFavorite();
-                } else {
-                    addFavorite();
-                }
-            }
-        },
-
+        }
     ];
 
     return <HolyGrail

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

@@ -5,7 +5,6 @@ import { SizeMe } from "react-sizeme";
 import nlsHPCC from "src/nlsHPCC";
 import { WUStatus } from "src/react/index";
 import { useWorkunit } from "../hooks/workunit";
-import { useFavorite } from "../hooks/favorite";
 import { DojoAdapter } from "../layouts/DojoAdapter";
 import { pivotItemStyle } from "../layouts/pivot";
 import { ReflexContainer, ReflexElement, ReflexSplitter, classNames, styles } from "../layouts/react-reflex";
@@ -43,7 +42,6 @@ export const WorkunitDetails: React.FunctionComponent<WorkunitDetailsProps> = ({
     const [jobname, setJobname] = React.useState("");
     const [description, setDescription] = React.useState("");
     const [_protected, setProtected] = React.useState(false);
-    const [isFavorite, addFavorite, removeFavorite] = useFavorite(window.location.hash);
     const [showPublishForm, setShowPublishForm] = React.useState(false);
     const [showZapForm, setShowZapForm] = React.useState(false);
     const [showThorSlaveLogs, setShowThorSlaveLogs] = React.useState(false);
@@ -160,17 +158,7 @@ export const WorkunitDetails: React.FunctionComponent<WorkunitDetailsProps> = ({
     ], [_protected, canDelete, canDeschedule, canReschedule, canSave, description, jobname, workunit, wuid]);
 
     const rightButtons = React.useMemo((): ICommandBarItemProps[] => [
-        {
-            key: "star", iconProps: { iconName: isFavorite ? "FavoriteStarFill" : "FavoriteStar" },
-            onClick: () => {
-                if (isFavorite) {
-                    removeFavorite();
-                } else {
-                    addFavorite();
-                }
-            }
-        }
-    ], [addFavorite, isFavorite, removeFavorite]);
+    ], []);
 
     const serviceNames = workunit?.ServiceNames?.Item?.join("\n") || "";
     const resourceCount = workunit?.ResourceURLCount > 1 ? workunit?.ResourceURLCount - 1 : undefined;

+ 41 - 28
esp/src/src-react/components/forms/Fields.tsx

@@ -15,8 +15,9 @@ interface DropdownProps {
     label?: string;
     options?: IDropdownOption[];
     defaultSelectedKey?: string;
-    optional?: boolean;
     required?: boolean;
+    optional?: boolean;
+    disabled?: boolean;
     errorMessage?: string;
     onChange?: (event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number) => void;
     placeholder?: string;
@@ -30,6 +31,7 @@ const Dropdown: React.FunctionComponent<DropdownProps> = ({
     defaultSelectedKey,
     required = false,
     optional = !required,
+    disabled,
     errorMessage,
     onChange,
     placeholder,
@@ -59,7 +61,7 @@ const Dropdown: React.FunctionComponent<DropdownProps> = ({
         setSelOptions(selOptions);
     }, [optional, options, defaultSelectedKey, handleOnChange]);
 
-    return <DropdownBase key={key} label={label} errorMessage={errorMessage} required={required} className={className} defaultSelectedKey={defaultSelectedKey} selectedKey={selectedKey} onChange={handleOnChange} placeholder={placeholder} options={selOptions} />;
+    return <DropdownBase key={key} label={label} errorMessage={errorMessage} required={required} className={className} defaultSelectedKey={defaultSelectedKey} selectedKey={selectedKey} onChange={handleOnChange} placeholder={placeholder} disabled={disabled} options={selOptions} />;
 };
 
 export type FieldType = "string" | "number" | "checkbox" | "datetime" | "dropdown" | "link" | "links" | "progress" |
@@ -212,35 +214,46 @@ export const TargetClusterTextField: React.FunctionComponent<TargetClusterTextFi
 
     React.useEffect(() => {
         const topology = Topology.attach({ baseUrl: "" });
+        let active = true;
         topology.fetchLogicalClusters().then((response: TpLogicalClusterQuery.TpLogicalCluster[]) => {
-            let firstRow: IDropdownOption;
-            let firstHThor: IDropdownOption;
-            let firstThor: IDropdownOption;
-            const options = response.map((n, i) => {
-                const retVal = {
-                    key: n.Name || "unknown",
-                    text: n.Name + (n.Name !== n.Type ? ` (${n.Type})` : ""),
-                };
-                if (firstRow === undefined) {
-                    firstRow = retVal;
-                }
-                if (firstHThor === undefined && n.Type === "hthor") {
-                    firstHThor = retVal;
-                }
-                if (firstThor === undefined && n.Type === "thor") {
-                    firstThor = retVal;
-                }
-                return retVal;
-            });
-            if (props.defaultSelectedKey === undefined && (props.required === true || props.optional === false)) {
-                const selRow = firstThor || firstHThor || firstRow;
-                if (selRow) {
-                    setDefaultSelectedKey(selRow?.key as string);
-                }
+            if (active) {
+                const options = response.map((n, i) => {
+                    return {
+                        key: n.Name || "unknown",
+                        text: n.Name + (n.Name !== n.Type ? ` (${n.Type})` : ""),
+                        type: n.Type
+                    };
+                });
+                setTargetClusters(options);
+            }
+        });
+        return () => { active = false; };
+    }, []);
+
+    React.useEffect(() => {
+        let firstRow: IDropdownOption;
+        let firstHThor: IDropdownOption;
+        let firstThor: IDropdownOption;
+        targetClusters.forEach(row => {
+            if (firstRow === undefined) {
+                firstRow = row;
+            }
+            if (firstHThor === undefined && (row as any).type === "hthor") {
+                firstHThor = row;
             }
-            setTargetClusters(options);
+            if (firstThor === undefined && (row as any).type === "thor") {
+                firstThor = row;
+            }
+            return row;
         });
-    }, [props.defaultSelectedKey, props.optional, props.required]);
+        if (props.defaultSelectedKey === undefined && (props.required === true || props.optional === false)) {
+            const selRow = firstThor || firstHThor || firstRow;
+            if (selRow) {
+                setDefaultSelectedKey(selRow?.key as string);
+                props.onChange && props.onChange(undefined, selRow);
+            }
+        }
+    }, [props, targetClusters]);
 
     return <Dropdown {...props} defaultSelectedKey={defaultSelectedKey} options={targetClusters} />;
 };

+ 4 - 3
esp/src/src-react/layouts/HpccJSAdapter.tsx

@@ -18,7 +18,6 @@ export const HpccJSComponent: React.FunctionComponent<HpccJSComponentProps> = ({
     height,
     debounce = true
 }) => {
-
     const divID = useId("viz-component-");
 
     React.useEffect(() => {
@@ -41,8 +40,10 @@ export const HpccJSComponent: React.FunctionComponent<HpccJSComponentProps> = ({
         }
     }, [debounce, height, widget, width]);
 
-    return <div id={divID} className="hpcc-js-component" style={{ width, height }}>
-    </div>;
+    return (isNaN(width) || isNaN(height)) ?
+        <></> :
+        <div id={divID} className="hpcc-js-component" style={{ width, height }}>
+        </div>;
 };
 
 export interface AutosizeHpccJSComponentProps {

+ 1 - 0
esp/src/src/nls/hpcc.ts

@@ -276,6 +276,7 @@ export = {
         ExpireDays: "Expire in (days)",
         FailIfNoSourceFile: "Fail If No Source File",
         Fatal: "Fatal",
+        Favorites: "Favorites",
         Fetched: "Fetched",
         FetchingData: "Fetching Data...",
         fetchingresults: "fetching results",