diff --git a/package.json b/package.json index c3907f4..91f1a2a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@auth0/auth0-react": "1.10.2", "@emotion/react": "11.7.1", "@emotion/styled": "11.6.0", - "@kingsrook/qqq-frontend-core": "1.0.86", + "@kingsrook/qqq-frontend-core": "1.0.87", "@mui/icons-material": "5.4.1", "@mui/material": "5.11.1", "@mui/styles": "5.11.1", diff --git a/src/qqq/components/misc/HelpContent.tsx b/src/qqq/components/misc/HelpContent.tsx index fb04d8c..f66f13d 100644 --- a/src/qqq/components/misc/HelpContent.tsx +++ b/src/qqq/components/misc/HelpContent.tsx @@ -28,7 +28,7 @@ import QContext from "QContext"; interface Props { - helpContents: QHelpContent[]; + helpContents: null | QHelpContent | QHelpContent[]; roles: string[]; heading?: string; helpContentKey?: string; @@ -93,9 +93,27 @@ const getMatchingHelpContent = (helpContents: QHelpContent[], roles: string[]): /******************************************************************************* ** test if a list of help contents would find any matches from a list of roles. *******************************************************************************/ -export const hasHelpContent = (helpContents: QHelpContent[], roles: string[]) => +export const hasHelpContent = (helpContents: null | QHelpContent | QHelpContent[], roles: string[]) => { - return getMatchingHelpContent(helpContents, roles) != null; + return getMatchingHelpContent(nullOrSingletonOrArrayToArray(helpContents), roles) != null; +} + + +/******************************************************************************* + ** + *******************************************************************************/ +const nullOrSingletonOrArrayToArray = (helpContents: null | QHelpContent | QHelpContent[]): QHelpContent[] => +{ + let array: QHelpContent[] = []; + if(Array.isArray(helpContents)) + { + array = helpContents; + } + else if(helpContents != null) + { + array.push(helpContents); + } + return (array); } @@ -106,7 +124,8 @@ export const hasHelpContent = (helpContents: QHelpContent[], roles: string[]) => function HelpContent({helpContents, roles, heading, helpContentKey}: Props): JSX.Element { const {helpHelpActive} = useContext(QContext); - let selectedHelpContent = getMatchingHelpContent(helpContents, roles); + const helpContentsArray = nullOrSingletonOrArrayToArray(helpContents); + let selectedHelpContent = getMatchingHelpContent(helpContentsArray, roles); let content = null; if (helpHelpActive) diff --git a/src/qqq/components/widgets/Widget.tsx b/src/qqq/components/widgets/Widget.tsx index bc4838d..7b3f327 100644 --- a/src/qqq/components/widgets/Widget.tsx +++ b/src/qqq/components/widgets/Widget.tsx @@ -28,9 +28,11 @@ import Icon from "@mui/material/Icon"; import Tooltip from "@mui/material/Tooltip/Tooltip"; import Typography from "@mui/material/Typography"; import parse from "html-react-parser"; -import React, {useEffect, useState} from "react"; +import React, {useContext, useEffect, useState} from "react"; import {NavigateFunction, useNavigate} from "react-router-dom"; +import QContext from "QContext"; import colors from "qqq/assets/theme/base/colors"; +import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent"; import WidgetDropdownMenu, {DropdownOption} from "qqq/components/widgets/components/WidgetDropdownMenu"; import {WidgetUtils} from "qqq/components/widgets/WidgetUtils"; import HtmlUtils from "qqq/utils/HtmlUtils"; @@ -359,6 +361,8 @@ function Widget(props: React.PropsWithChildren): JSX.Element const [lastSeenLabel, setLastSeenLabel] = useState(""); const [usingLabelAsTitle, setUsingLabelAsTitle] = useState(false); + const {helpHelpActive} = useContext(QContext); + function renderComponent(component: LabelComponent, componentIndex: number) { if(component && component.render) @@ -608,9 +612,18 @@ function Widget(props: React.PropsWithChildren): JSX.Element setUsingLabelAsTitle(props.widgetData.isLabelPageTitle); } - if (props.widgetMetaData.tooltip) + const helpRoles = ["ALL_SCREENS"] + const slotName = "label"; + const showHelp = helpHelpActive || hasHelpContent(props.widgetMetaData?.helpContent?.get(slotName), helpRoles); + + if(showHelp) { - labelElement = {labelElement}; + const formattedHelpContent = ; + labelElement = {labelElement}; + } + else if (props.widgetMetaData?.tooltip) + { + labelElement = {labelElement}; } const isTable = props.widgetMetaData.type == "table"; diff --git a/src/qqq/components/widgets/tables/DataTable.tsx b/src/qqq/components/widgets/tables/DataTable.tsx index 023b4a3..863b987 100644 --- a/src/qqq/components/widgets/tables/DataTable.tsx +++ b/src/qqq/components/widgets/tables/DataTable.tsx @@ -30,8 +30,8 @@ import TableContainer from "@mui/material/TableContainer"; import TableRow from "@mui/material/TableRow"; import Tooltip from "@mui/material/Tooltip"; import parse from "html-react-parser"; -import {useEffect, useMemo, useState} from "react"; -import {useAsyncDebounce, useGlobalFilter, usePagination, useSortBy, useTable, useExpanded} from "react-table"; +import React, {useEffect, useMemo, useState} from "react"; +import {useAsyncDebounce, useExpanded, useGlobalFilter, usePagination, useSortBy, useTable} from "react-table"; import colors from "qqq/assets/theme/base/colors"; import MDInput from "qqq/components/legacy/MDInput"; import MDPagination from "qqq/components/legacy/MDPagination"; @@ -173,6 +173,17 @@ function DataTable({ ); } + if(table.columnHeaderTooltips) + { + for (let column of columnsToMemo) + { + if(table.columnHeaderTooltips[column.accessor]) + { + column.tooltip = table.columnHeaderTooltips[column.accessor]; + } + } + } + const columns = useMemo(() => columnsToMemo, [table]); const data = useMemo(() => table.rows, [table]); const gridTemplateColumns = widths.join(" "); @@ -324,6 +335,7 @@ function DataTable({ {...column.getHeaderProps(isSorted && column.getSortByToggleProps())} align={column.align ? column.align : "left"} sorted={setSortedValue(column)} + tooltip={column.tooltip} > {column.render("header")} diff --git a/src/qqq/components/widgets/tables/TableCard.tsx b/src/qqq/components/widgets/tables/TableCard.tsx index ae14974..b4fd395 100644 --- a/src/qqq/components/widgets/tables/TableCard.tsx +++ b/src/qqq/components/widgets/tables/TableCard.tsx @@ -43,6 +43,7 @@ import Client from "qqq/utils/qqq/Client"; export interface TableDataInput { columns: { [key: string]: any }[]; + columnHeaderTooltips?: { [columnName: string]: string | JSX.Element } rows: { [key: string]: any }[]; } diff --git a/src/qqq/components/widgets/tables/TableWidget.tsx b/src/qqq/components/widgets/tables/TableWidget.tsx index 2ac71ea..1024ded 100644 --- a/src/qqq/components/widgets/tables/TableWidget.tsx +++ b/src/qqq/components/widgets/tables/TableWidget.tsx @@ -23,7 +23,9 @@ import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData"; // @ts-ignore import {htmlToText} from "html-to-text"; -import React, {useEffect, useState} from "react"; +import React, {useContext, useEffect, useState} from "react"; +import QContext from "QContext"; +import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent"; import TableCard from "qqq/components/widgets/tables/TableCard"; import Widget, {WidgetData} from "qqq/components/widgets/Widget"; import {WidgetUtils} from "qqq/components/widgets/WidgetUtils"; @@ -46,6 +48,7 @@ function TableWidget(props: Props): JSX.Element const [isExportDisabled, setIsExportDisabled] = useState(false); // hmm, would like true here, but it broke... const [csv, setCsv] = useState(null as string); const [fileName, setFileName] = useState(null as string); + const {helpHelpActive} = useContext(QContext); const rows = props.widgetData?.rows; const columns = props.widgetData?.columns; @@ -133,6 +136,23 @@ function TableWidget(props: Props): JSX.Element labelAdditionalElementsLeft.push(WidgetUtils.generateExportButton(onExportClick)); } + ////////////////////////////////////////////////////// + // look for column-header tooltips from helpContent // + ////////////////////////////////////////////////////// + const columnHeaderTooltips: {[columnName: string]: JSX.Element} = {} + for (let column of props.widgetData?.columns ?? []) + { + const helpRoles = ["ALL_SCREENS"] + const slotName = `columnHeader=${column.accessor}`; + const showHelp = helpHelpActive || hasHelpContent(props.widgetMetaData?.helpContent?.get(slotName), helpRoles); + + if(showHelp) + { + const formattedHelpContent = ; + columnHeaderTooltips[column.accessor] = formattedHelpContent; + } + } + return ( diff --git a/src/qqq/components/widgets/tables/cells/DataTableHeadCell.tsx b/src/qqq/components/widgets/tables/cells/DataTableHeadCell.tsx index b9a9c0c..dd43069 100644 --- a/src/qqq/components/widgets/tables/cells/DataTableHeadCell.tsx +++ b/src/qqq/components/widgets/tables/cells/DataTableHeadCell.tsx @@ -22,6 +22,7 @@ import Box from "@mui/material/Box"; import Icon from "@mui/material/Icon"; import {Theme} from "@mui/material/styles"; +import Tooltip from "@mui/material/Tooltip"; import {ReactNode} from "react"; import colors from "qqq/assets/theme/base/colors"; import {useMaterialUIController} from "qqq/context"; @@ -33,9 +34,10 @@ interface Props children: ReactNode; sorted?: false | "none" | "asce" | "desc"; align?: "left" | "right" | "center"; + tooltip?: string | JSX.Element; } -function DataTableHeadCell({width, children, sorted, align, ...rest}: Props): JSX.Element +function DataTableHeadCell({width, children, sorted, align, tooltip, ...rest}: Props): JSX.Element { const [controller] = useMaterialUIController(); const {darkMode} = controller; @@ -73,39 +75,43 @@ function DataTableHeadCell({width, children, sorted, align, ...rest}: Props): JS userSelect: sorted && "none", })} > - {children} - {sorted && ( - ({ - fontSize: size.lg, - })} - > + <> + { + tooltip ? {children} : children + } + {sorted && ( ({ + fontSize: size.lg, + })} > - arrow_drop_up + + arrow_drop_up + + + arrow_drop_down + - - arrow_drop_down - - - )} + )} + );