From e2022835201a70d73f79a91e075aa90b4053cb8d Mon Sep 17 00:00:00 2001 From: Jeremy Clements <79224539+jeclrsg@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:50:07 -0500 Subject: [PATCH] HPCC-32861 ECL Watch v9 WU logs tab tooltip Adds a tooltip to each of the tabs on WU (and File and Query) details pages. The tooltip defaults to just displaying the tab label. But in the case of the WU logs tab, the tooltip will display any reason reported by ESP as to why logging is unavailable. Signed-off-by: Jeremy Clements <79224539+jeclrsg@users.noreply.github.com> --- esp/src/src-react/components/Logs.tsx | 2 +- esp/src/src-react/components/Menu.tsx | 12 +++---- .../src-react/components/WorkunitDetails.tsx | 17 +++------- .../controls/TabbedPanes/OverflowTabList.tsx | 6 ++-- .../controls/TabbedPanes/TabInfo.ts | 1 + esp/src/src-react/hooks/platform.ts | 34 ++++++++++++++----- esp/src/src/nls/hpcc.ts | 3 ++ 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/esp/src/src-react/components/Logs.tsx b/esp/src/src-react/components/Logs.tsx index 02fcd0e80a6..321d54fd330 100644 --- a/esp/src/src-react/components/Logs.tsx +++ b/esp/src/src-react/components/Logs.tsx @@ -112,7 +112,7 @@ export const Logs: React.FunctionComponent = ({ const now = React.useMemo(() => new Date(), []); - const { columns: logColumns } = useLogAccessInfo(); + const { logsColumns: logColumns } = useLogAccessInfo(); // Grid --- const columns = React.useMemo((): FluentColumns => { diff --git a/esp/src/src-react/components/Menu.tsx b/esp/src/src-react/components/Menu.tsx index d2c1e3da292..f9bc7b5a5e3 100644 --- a/esp/src/src-react/components/Menu.tsx +++ b/esp/src/src-react/components/Menu.tsx @@ -2,11 +2,11 @@ import * as React from "react"; import { IconButton, IContextualMenuItem, INavLink, INavLinkGroup, Link, mergeStyleSets, Nav, Stack } from "@fluentui/react"; import { useConst } from "@fluentui/react-hooks"; import nlsHPCC from "src/nlsHPCC"; -import { hasLogAccess } from "src/ESPLog"; import { containerized, bare_metal } from "src/BuildInfo"; import { navCategory } from "../util/history"; import { MainNav, routes } from "../routes"; import { useFavorite, useFavorites, useHistory } from "../hooks/favorite"; +import { useLogAccessInfo } from "../hooks/platform"; import { useSessionStore } from "../hooks/store"; import { useUserTheme } from "../hooks/theme"; import { useMyAccount } from "../hooks/user"; @@ -295,12 +295,7 @@ export const SubNavigation: React.FunctionComponent = ({ } }), [theme]); - const [logsDisabled, setLogsDisabled] = React.useState(true); - React.useEffect(() => { - hasLogAccess().then(response => { - setLogsDisabled(!response); - }); - }, []); + const { logsEnabled, logsStatusMessage } = useLogAccessInfo(); const linkStyle = React.useCallback((disabled) => { return disabled ? { background: themeV9.colorNeutralBackgroundDisabled, @@ -326,9 +321,10 @@ export const SubNavigation: React.FunctionComponent = ({ {subMenuItems[mainNav]?.map((row, idx) => { - const linkDisabled = (row.itemKey === "/topology/logs" && logsDisabled) || (row.itemKey.indexOf("security") > -1 && !isAdmin); + const linkDisabled = (row.itemKey === "/topology/logs" && !logsEnabled) || (row.itemKey.indexOf("security") > -1 && !isAdmin); return = ({ const [variables, , , refreshVariables] = useWorkunitVariables(wuid); const [otTraceParent, setOtTraceParent] = React.useState(""); const [logCount, setLogCount] = React.useState("*"); - const [logsDisabled, setLogsDisabled] = React.useState(true); + const { logsEnabled, logsStatusMessage } = useLogAccessInfo(); const [_nextPrev, setNextPrev] = useNextPrev(); const query = React.useMemo(() => { @@ -121,13 +120,6 @@ export const WorkunitDetails: React.FunctionComponent = ({ }; }, [nextWuid, query, setNextPrev, wuid]); - useDeepEffect(() => { - hasLogAccess().then(response => { - setLogsDisabled(!response); - return response; - }); - }, [wuid], [queryParams]); - const onTabSelect = React.useCallback((tab: TabInfo) => { pushUrl(tab.__state ?? `${parentUrl}/${wuid}/${tab.id}`); updateFullscreen(fullscreen); @@ -174,7 +166,8 @@ export const WorkunitDetails: React.FunctionComponent = ({ id: "logs", label: nlsHPCC.Logs, count: logCount, - disabled: logsDisabled + tooltipText: !logsEnabled ? (logsStatusMessage || nlsHPCC.LogsDisabled) : null, + disabled: !logsEnabled }, { id: "eclsummary", label: nlsHPCC.ECL @@ -182,7 +175,7 @@ export const WorkunitDetails: React.FunctionComponent = ({ id: "xml", label: nlsHPCC.XML }]; - }, [logCount, logsDisabled, workunit?.ApplicationValueCount, workunit?.DebugValueCount, workunit?.GraphCount, workunit?.HelpersCount, workunit?.ResourceURLCount, workunit?.ResultCount, workunit?.SourceFileCount, workunit?.VariableCount, workunit?.WorkflowCount, wuid]); + }, [logCount, logsEnabled, logsStatusMessage, workunit?.ApplicationValueCount, workunit?.DebugValueCount, workunit?.GraphCount, workunit?.HelpersCount, workunit?.ResourceURLCount, workunit?.ResultCount, workunit?.SourceFileCount, workunit?.VariableCount, workunit?.WorkflowCount, wuid]); return {({ size }) => diff --git a/esp/src/src-react/components/controls/TabbedPanes/OverflowTabList.tsx b/esp/src/src-react/components/controls/TabbedPanes/OverflowTabList.tsx index e9cf3520ccf..63a15308e08 100644 --- a/esp/src/src-react/components/controls/TabbedPanes/OverflowTabList.tsx +++ b/esp/src/src-react/components/controls/TabbedPanes/OverflowTabList.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { Overflow, OverflowItem, SelectTabData, SelectTabEvent, Tab, TabList } from "@fluentui/react-components"; +import { Overflow, OverflowItem, SelectTabData, SelectTabEvent, Tab, TabList, Tooltip } from "@fluentui/react-components"; import { Count } from "./Count"; import { TabInfo } from "./TabInfo"; import { OverflowMenu } from "../OverflowMenu"; @@ -28,7 +28,9 @@ export const OverflowTabList: React.FunctionComponent = ({ tab.__state = state; } return - {tab.label} + + {tab.label} + ; }), tabsIndex]; }, [selected, state, tabs]); diff --git a/esp/src/src-react/components/controls/TabbedPanes/TabInfo.ts b/esp/src/src-react/components/controls/TabbedPanes/TabInfo.ts index 7d87929b3a6..d21edad8120 100644 --- a/esp/src/src-react/components/controls/TabbedPanes/TabInfo.ts +++ b/esp/src/src-react/components/controls/TabbedPanes/TabInfo.ts @@ -6,5 +6,6 @@ export interface TabInfo { label: string; count?: string | number; disabled?: boolean; + tooltipText?: string; __state?: any; } diff --git a/esp/src/src-react/hooks/platform.ts b/esp/src/src-react/hooks/platform.ts index 33f2089c260..e403a37c119 100644 --- a/esp/src/src-react/hooks/platform.ts +++ b/esp/src/src-react/hooks/platform.ts @@ -3,6 +3,7 @@ import { Octokit } from "octokit"; import { useConst } from "@fluentui/react-hooks"; import { scopedLogger } from "@hpcc-js/util"; import { LogaccessService, Topology, WsLogaccess, WsTopology, WorkunitsServiceEx } from "@hpcc-js/comms"; +import nlsHPCC from "src/nlsHPCC"; import { getBuildInfo, BuildInfo, fetchModernMode } from "src/Session"; import { cmake_build_type, containerized, ModernMode } from "src/BuildInfo"; import { sessionKeyValStore, userKeyValStore } from "src/KeyValStore"; @@ -209,19 +210,34 @@ export function useModernMode(): { return { modernMode, setModernMode }; } -export function useLogAccessInfo(): { - managerType: string; - columns: WsLogaccess.Column[] -} { - const [managerType, setManagerType] = React.useState(""); - const [columns, setColumns] = React.useState(); +interface LogAccessInfo { + logsEnabled: boolean; + logsManagerType: string; + logsColumns: WsLogaccess.Column[]; + logsStatusMessage: string; +} + +export function useLogAccessInfo(): LogAccessInfo { + const [logsEnabled, setLogsEnabled] = React.useState(false); + const [logsManagerType, setLogsManagerType] = React.useState(""); + const [logsColumns, setLogsColumns] = React.useState(); + const [logsStatusMessage, setLogsStatusMessage] = React.useState(""); React.useEffect(() => { service.GetLogAccessInfo({}).then(response => { - setManagerType(response.RemoteLogManagerType ?? ""); - setColumns(response?.Columns?.Column); + if (response.hasOwnProperty("Exceptions")) { + setLogsStatusMessage(response["Exceptions"]?.Exception[0]?.Message ?? nlsHPCC.LogAccess_GenericException); + } else { + if (response.RemoteLogManagerType === null) { + setLogsStatusMessage(nlsHPCC.LogAccess_LoggingNotConfigured); + } else { + setLogsEnabled(true); + setLogsManagerType(response.RemoteLogManagerType); + setLogsColumns(response?.Columns?.Column); + } + } }); }, []); - return { managerType, columns }; + return { logsEnabled, logsManagerType, logsColumns, logsStatusMessage }; } \ No newline at end of file diff --git a/esp/src/src/nls/hpcc.ts b/esp/src/src/nls/hpcc.ts index 592e8cb09d3..182faf5b59f 100644 --- a/esp/src/src/nls/hpcc.ts +++ b/esp/src/src/nls/hpcc.ts @@ -496,6 +496,8 @@ export = { Location: "Location", Lock: "Lock", LogAccessType: "Log Access Type", + LogAccess_GenericException: "ws_logaccess::GetLogAccessInfo, an exception has occurred.", + LogAccess_LoggingNotConfigured: "A logging engine has not been configured.", LogDirectory: "Log Directory", LogEventType: "Log Event Type", LogFile: "Log File", @@ -529,6 +531,7 @@ export = { Login: "Login", Logout: "Log Out", Logs: "Logs", + LogsDisabled: "Logs Disabled", LogVisualization: "Log Visualization", LogVisualizationUnconfigured: "Log Visualization is not configured, please check your configuration manager settings.", log_analysis_1: "log_analysis_1*",