diff --git a/frontend/src/pages/modelServing/screens/const.ts b/frontend/src/pages/modelServing/screens/const.ts index 7c30346dd5..c1f0ccf91a 100644 --- a/frontend/src/pages/modelServing/screens/const.ts +++ b/frontend/src/pages/modelServing/screens/const.ts @@ -88,11 +88,18 @@ export const TimeframeStep: TimeframeStepType = { [TimeframeTitle.ONE_HOUR]: 12, [TimeframeTitle.ONE_DAY]: 24 * 12, [TimeframeTitle.ONE_WEEK]: 7 * 24 * 12, - [TimeframeTitle.ONE_MONTH]: 30 * 7 * 24 * 12, + [TimeframeTitle.ONE_MONTH]: 30 * 24 * 12, // [TimeframeTitle.UNLIMITED]: 30 * 7 * 24 * 12, // TODO: determine if we "zoom out" more }; export const RefreshIntervalValue: RefreshIntervalValueType = { + [RefreshIntervalTitle.FIFTEEN_SECONDS]: 15 * 1000, + [RefreshIntervalTitle.THIRTY_SECONDS]: 30 * 1000, [RefreshIntervalTitle.ONE_MINUTE]: 60 * 1000, [RefreshIntervalTitle.FIVE_MINUTES]: 5 * 60 * 1000, + [RefreshIntervalTitle.FIFTEEN_MINUTES]: 15 * 60 * 1000, + [RefreshIntervalTitle.THIRTY_MINUTES]: 30 * 60 * 1000, + [RefreshIntervalTitle.ONE_HOUR]: 60 * 60 * 1000, + [RefreshIntervalTitle.TWO_HOURS]: 2 * 60 * 60 * 1000, + [RefreshIntervalTitle.ONE_DAY]: 24 * 60 * 60 * 1000, }; diff --git a/frontend/src/pages/modelServing/screens/metrics/BiasTab.tsx b/frontend/src/pages/modelServing/screens/metrics/BiasTab.tsx index d13c05626f..94f176dbc2 100644 --- a/frontend/src/pages/modelServing/screens/metrics/BiasTab.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/BiasTab.tsx @@ -8,38 +8,36 @@ import { ToolbarGroup, ToolbarItem, } from '@patternfly/react-core'; -import { useParams } from 'react-router-dom'; import MetricsPageToolbar from '~/pages/modelServing/screens/metrics/MetricsPageToolbar'; import BiasMetricConfigSelector from '~/pages/modelServing/screens/metrics/BiasMetricConfigSelector'; -import { BiasMetricConfig } from '~/concepts/explainability/types'; import { useExplainabilityModelData } from '~/concepts/explainability/useExplainabilityModelData'; import TrustyChart from '~/pages/modelServing/screens/metrics/TrustyChart'; -import { useBrowserStorage } from '~/components/browserStorage'; import EmptyBiasConfigurationCard from '~/pages/modelServing/screens/metrics/EmptyBiasConfigurationCard'; import EmptyBiasChartSelectionCard from '~/pages/modelServing/screens/metrics/EmptyBiasChartSelectionCard'; import DashboardExpandableSection from '~/concepts/dashboard/DashboardExpandableSection'; +import useBiasChartsBrowserStorage from '~/pages/modelServing/screens/metrics/useBiasChartsBrowserStorage'; -const SELECTED_CHARTS_STORAGE_KEY_PREFIX = 'odh.dashboard.xai.selected_bias_charts'; const OPEN_WRAPPER_STORAGE_KEY_PREFIX = `odh.dashboard.xai.bias_metric_chart_wrapper_open`; const BiasTab: React.FC = () => { - const { inferenceService } = useParams(); - const { biasMetricConfigs, loaded, loadError } = useExplainabilityModelData(); - const [selectedBiasConfigs, setSelectedBiasConfigs] = useBrowserStorage( - `${SELECTED_CHARTS_STORAGE_KEY_PREFIX}-${inferenceService}`, - [], - true, - true, - ); + const [selectedBiasConfigs, setSelectedBiasConfigs] = useBiasChartsBrowserStorage(); + + const firstRender = React.useRef(true); React.useEffect(() => { if (loaded && !loadError) { - setSelectedBiasConfigs( - selectedBiasConfigs.filter((selection) => - biasMetricConfigs.map((c) => c.id).includes(selection.id), - ), - ); + if (firstRender.current) { + // If the user has just navigated here AND they haven't previously selected any charts to display, + // don't show them the "No selected" empty state, instead show them the first available chart. + // However, the user still needs to be shown said empty state if they deselect all charts. + firstRender.current = false; + if (selectedBiasConfigs.length === 0 && biasMetricConfigs.length > 0) { + // If biasMetricConfigs is empty, the "No Configured Metrics" empty state will be shown, so no need + // to set anything. + setSelectedBiasConfigs([biasMetricConfigs[0]]); + } + } } }, [loaded, biasMetricConfigs, setSelectedBiasConfigs, selectedBiasConfigs, loadError]); diff --git a/frontend/src/pages/modelServing/screens/metrics/EmptyBiasChartSelectionCard.tsx b/frontend/src/pages/modelServing/screens/metrics/EmptyBiasChartSelectionCard.tsx index a8bc5cfa0c..1ee8f5b4e0 100644 --- a/frontend/src/pages/modelServing/screens/metrics/EmptyBiasChartSelectionCard.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/EmptyBiasChartSelectionCard.tsx @@ -7,7 +7,7 @@ import { EmptyStateIcon, Title, } from '@patternfly/react-core'; -import { PlusCircleIcon } from '@patternfly/react-icons'; +import { SearchIcon } from '@patternfly/react-icons'; import { EMPTY_BIAS_CHART_SELECTION_DESC, EMPTY_BIAS_CHART_SELECTION_TITLE, @@ -17,7 +17,7 @@ const EmptyBiasChartSelectionCard = () => ( - + {EMPTY_BIAS_CHART_SELECTION_TITLE} diff --git a/frontend/src/pages/modelServing/screens/metrics/biasConfigurationModal/DeleteBiasConfigurationModal.tsx b/frontend/src/pages/modelServing/screens/metrics/biasConfigurationModal/DeleteBiasConfigurationModal.tsx index d3f19f4d0d..4502c99a6d 100644 --- a/frontend/src/pages/modelServing/screens/metrics/biasConfigurationModal/DeleteBiasConfigurationModal.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/biasConfigurationModal/DeleteBiasConfigurationModal.tsx @@ -3,6 +3,8 @@ import { MetricTypes } from '~/api'; import { ExplainabilityContext } from '~/concepts/explainability/ExplainabilityContext'; import { BiasMetricConfig } from '~/concepts/explainability/types'; import DeleteModal from '~/pages/projects/components/DeleteModal'; +import useBiasChartsBrowserStorage from '~/pages/modelServing/screens/metrics/useBiasChartsBrowserStorage'; +import { byNotId } from '~/pages/modelServing/screens/metrics/utils'; type DeleteBiasConfigurationModalProps = { configurationToDelete?: BiasMetricConfig; @@ -19,6 +21,12 @@ const DeleteBiasConfigurationModal: React.FC apiState: { api }, } = React.useContext(ExplainabilityContext); + const [selectedBiasConfigCharts, setSelectedBiasConfigCharts] = useBiasChartsBrowserStorage(); + + const deselectDeleted = (biasConfigId: string) => { + setSelectedBiasConfigCharts(selectedBiasConfigCharts.filter(byNotId(biasConfigId))); + }; + const onBeforeClose = (deleted: boolean) => { onClose(deleted); setDeleting(false); @@ -41,6 +49,7 @@ const DeleteBiasConfigurationModal: React.FC : api.deleteSpdRequest; deleteFunc({}, configurationToDelete.id) .then(() => onBeforeClose(true)) + .then(() => deselectDeleted(configurationToDelete.id)) .catch((e) => { setError(e); setDeleting(false); diff --git a/frontend/src/pages/modelServing/screens/metrics/useBiasChartsBrowserStorage.ts b/frontend/src/pages/modelServing/screens/metrics/useBiasChartsBrowserStorage.ts new file mode 100644 index 0000000000..94a1a18326 --- /dev/null +++ b/frontend/src/pages/modelServing/screens/metrics/useBiasChartsBrowserStorage.ts @@ -0,0 +1,24 @@ +import { useParams } from 'react-router-dom'; +import { useBrowserStorage } from '~/components/browserStorage'; +import { BiasMetricConfig } from '~/concepts/explainability/types'; +import { SetBrowserStorageHook } from '~/components/browserStorage/BrowserStorageContext'; + +const SELECTED_CHARTS_STORAGE_KEY_PREFIX = 'odh.dashboard.xai.selected_bias_charts'; + +const useBiasChartsBrowserStorage = (): [ + BiasMetricConfig[], + SetBrowserStorageHook, +] => { + const { inferenceService } = useParams(); + + const [selectedBiasConfigs, setSelectedBiasConfigs] = useBrowserStorage( + `${SELECTED_CHARTS_STORAGE_KEY_PREFIX}-${inferenceService}`, + [], + true, + true, + ); + + return [selectedBiasConfigs, setSelectedBiasConfigs]; +}; + +export default useBiasChartsBrowserStorage; diff --git a/frontend/src/pages/modelServing/screens/types.ts b/frontend/src/pages/modelServing/screens/types.ts index 45b0063fa4..f643dec90a 100644 --- a/frontend/src/pages/modelServing/screens/types.ts +++ b/frontend/src/pages/modelServing/screens/types.ts @@ -21,8 +21,15 @@ export type TimeframeTimeType = { export type TimeframeStepType = TimeframeTimeType; export enum RefreshIntervalTitle { + FIFTEEN_SECONDS = '15 seconds', + THIRTY_SECONDS = '30 seconds', ONE_MINUTE = '1 minute', FIVE_MINUTES = '5 minutes', + FIFTEEN_MINUTES = '15 minutes', + THIRTY_MINUTES = '30 minutes', + ONE_HOUR = '1 hour', + TWO_HOURS = '2 hours', + ONE_DAY = '1 day', } export type RefreshIntervalValueType = {