Skip to content

Commit

Permalink
Default and restrict threshold, add tooltips, default duplicate name …
Browse files Browse the repository at this point in the history
…and set feature flag (#1390)

* Default and restrict threshold, add tooltips, default duplicate name and set feature flag

* fix lint

* add tooltips and dropdown descriptions

* clear data when closing configuration modal

* really solve deleting issue, make empty table view a common component and apply it everywhere

* address comments
  • Loading branch information
DaoDaoNoCode authored Jun 16, 2023
1 parent 9f369a6 commit e2f799d
Show file tree
Hide file tree
Showing 33 changed files with 356 additions and 186 deletions.
1 change: 1 addition & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type DashboardConfig = K8sResourceCommon & {
disableCustomServingRuntimes: boolean;
modelMetricsNamespace: string;
disablePipelines: boolean;
disableBiasMetrics: boolean;
};
groupsConfig?: {
adminGroups: string;
Expand Down
1 change: 1 addition & 0 deletions backend/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const blankDashboardCR: DashboardConfig = {
disableCustomServingRuntimes: false,
modelMetricsNamespace: '',
disablePipelines: true,
disableBiasMetrics: false,
},
notebookController: {
enabled: true,
Expand Down
3 changes: 3 additions & 0 deletions docs/dashboard_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The following are a list of features that are supported, along with there defaul
| disableProjectSharing | false | Disables Project Sharing from Data Science Projects. |
| disableCustomServingRuntimes | false | Disables Custom Serving Runtimes from the Admin Panel. |
| modelMetricsNamespace | false | Enables the namespace in which the Model Serving Metrics' Prometheus Operator is installed. |
| disableBiasMetrics | false | Disables Model Bias from Model Serving metrics. |

## Defaults

Expand All @@ -46,6 +47,7 @@ spec:
disableProjectSharing: false
disableCustomServingRuntimes: false
modelMetricsNamespace: ''
disableBiasMetrics: false
```
## Additional fields
Expand Down Expand Up @@ -136,6 +138,7 @@ spec:
disableProjectSharing: true
disableCustomServingRuntimes: false
modelMetricsNamespace: ''
disableBiasMetrics: false
notebookController:
enabled: true
notebookSizes:
Expand Down
1 change: 1 addition & 0 deletions frontend/src/__mocks__/mockDashboardConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const mockDashboardConfig = ({
modelMetricsNamespace: 'test-project',
disablePipelines: false,
disableProjectSharing: false,
disableBiasMetrics: false,
},
notebookController: {
enabled: true,
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/api/prometheus/serving.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
RefreshIntervalTitle,
TimeframeTitle,
} from '~/pages/modelServing/screens/types';
import useBiasMetricsEnabled from '~/concepts/explainability/useBiasMetricsEnabled';
import useQueryRangeResourceData, {
useQueryRangeResourceDataTrusty,
} from './useQueryRangeResourceData';
Expand All @@ -32,6 +33,7 @@ export const useModelServingMetrics = (
refresh: () => void;
} => {
const [end, setEnd] = React.useState(lastUpdateTime);
const [biasMetricsEnabled] = useBiasMetricsEnabled();

const runtimeRequestCount = useQueryRangeResourceData(
type === 'runtime',
Expand Down Expand Up @@ -82,15 +84,15 @@ export const useModelServingMetrics = (
);

const inferenceTrustyAISPD = useQueryRangeResourceDataTrusty(
type === 'inference',
biasMetricsEnabled && type === 'inference',
queries[InferenceMetricType.TRUSTY_AI_SPD],
end,
timeframe,
refreshInterval,
);

const inferenceTrustyAIDIR = useQueryRangeResourceDataTrusty(
type === 'inference',
biasMetricsEnabled && type === 'inference',
queries[InferenceMetricType.TRUSTY_AI_DIR],
end,
timeframe,
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/api/prometheus/usePrometheusQueryRange.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import * as React from 'react';
import axios from 'axios';

import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState';
import useFetchState, {
FetchState,
FetchStateCallbackPromise,
NotReadyError,
} from '~/utilities/useFetchState';
import {
PrometheusQueryRangeResponse,
PrometheusQueryRangeResponseData,
Expand All @@ -25,13 +29,17 @@ const usePrometheusQueryRange = <T = PrometheusQueryRangeResultValue>(
const endInS = endInMs / 1000;
const start = endInS - span;

if (!active) {
return Promise.reject(new NotReadyError('Prometheus query is not active'));
}

return axios
.post<{ response: PrometheusQueryRangeResponse }>(apiPath, {
query: `query=${queryLang}&start=${start}&end=${endInS}&step=${step}`,
})

.then((response) => responsePredicate(response.data?.response.data));
}, [endInMs, span, apiPath, queryLang, step, responsePredicate]);
}, [endInMs, span, apiPath, queryLang, step, responsePredicate, active]);

return useFetchState<T[]>(fetchData, []);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import {
} from '@patternfly/react-core';
import { SearchIcon } from '@patternfly/react-icons';

type EmptyTableViewProps = {
type DashboardEmptyTableViewProps = {
onClearFilters: () => void;
};

const EmptyTableView: React.FC<EmptyTableViewProps> = ({ onClearFilters }) => (
const DashboardEmptyTableView: React.FC<DashboardEmptyTableViewProps> = ({ onClearFilters }) => (
<Bullseye>
<EmptyState>
<EmptyStateIcon icon={SearchIcon} />
Expand All @@ -33,4 +33,4 @@ const EmptyTableView: React.FC<EmptyTableViewProps> = ({ onClearFilters }) => (
</Bullseye>
);

export default EmptyTableView;
export default DashboardEmptyTableView;
15 changes: 15 additions & 0 deletions frontend/src/concepts/dashboard/DashboardHelpTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as React from 'react';
import { Tooltip } from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';

type DashboardHelpTooltipProps = {
content: string;
};

const DashboardHelpTooltip: React.FC<DashboardHelpTooltipProps> = ({ content }) => (
<Tooltip removeFindDomNode content={content}>
<HelpIcon />
</Tooltip>
);

export default DashboardHelpTooltip;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import useFetchState, {
FetchStateCallbackPromise,
NotReadyError,
} from '~/utilities/useFetchState';
import useBiasMetricsEnabled from './useBiasMetricsEnabled';

// TODO create component for ensuring API availability, see pipelines for example.

Expand Down Expand Up @@ -113,8 +114,12 @@ const useFetchContextData = (apiState: TrustyAPIState): ExplainabilityContextDat
};

const useFetchBiasMetricConfigs = (apiState: TrustyAPIState): FetchState<BiasMetricConfig[]> => {
const [biasMetricsEnabled] = useBiasMetricsEnabled();
const callback = React.useCallback<FetchStateCallbackPromise<BiasMetricConfig[]>>(
(opts) => {
if (!biasMetricsEnabled) {
return Promise.reject(new NotReadyError('Bias metrics is not enabled'));
}
if (!apiState.apiAvailable) {
return Promise.reject(new NotReadyError('API not yet available'));
}
Expand All @@ -125,7 +130,7 @@ const useFetchBiasMetricConfigs = (apiState: TrustyAPIState): FetchState<BiasMet
throw e;
});
},
[apiState.api, apiState.apiAvailable],
[apiState.api, apiState.apiAvailable, biasMetricsEnabled],
);

return useFetchState(callback, [], { initialPromisePurity: true });
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/concepts/explainability/useBiasMetricsEnabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useAppContext } from '~/app/AppContext';
import { featureFlagEnabled } from '~/utilities/utils';

const useBiasMetricsEnabled = () => {
const {
dashboardConfig: {
spec: {
dashboardConfig: { disableBiasMetrics },
},
},
} = useAppContext();

return [featureFlagEnabled(disableBiasMetrics)];
};

export default useBiasMetricsEnabled;
7 changes: 6 additions & 1 deletion frontend/src/concepts/explainability/useTrustyAPIRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import useFetchState, {
import { getTrustyAIAPIRoute } from '~/api/';
import { RouteKind } from '~/k8sTypes';
import { FAST_POLL_INTERVAL } from '~/utilities/const';
import useBiasMetricsEnabled from './useBiasMetricsEnabled';

type State = string | null;
const useTrustyAPIRoute = (hasCR: boolean, namespace: string): FetchState<State> => {
const [biasMetricsEnabled] = useBiasMetricsEnabled();
const callback = React.useCallback<FetchStateCallbackPromise<State>>(
(opts) => {
if (!biasMetricsEnabled) {
return Promise.reject(new NotReadyError('Bias metrics is not enabled'));
}
if (!hasCR) {
return Promise.reject(new NotReadyError('CR not created'));
}
Expand All @@ -27,7 +32,7 @@ const useTrustyAPIRoute = (hasCR: boolean, namespace: string): FetchState<State>
throw e;
});
},
[hasCR, namespace],
[hasCR, namespace, biasMetricsEnabled],
);

// TODO: add duplicate functionality to useFetchState.
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/concepts/explainability/useTrustyAiNamespaceCR.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import React from 'react';
import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState';
import useFetchState, {
FetchState,
FetchStateCallbackPromise,
NotReadyError,
} from '~/utilities/useFetchState';
import { TrustyAiKind } from '~/k8sTypes';
import useBiasMetricsEnabled from './useBiasMetricsEnabled';

type State = TrustyAiKind | null;
const useTrustyAiNamespaceCR = (namespace: string): FetchState<State> => {
const [biasMetricsEnabled] = useBiasMetricsEnabled();
// TODO: the logic needs to be fleshed out once the TrustyAI operator is complete.
const callback = React.useCallback<FetchStateCallbackPromise<State>>(
(opts) => (namespace && opts ? Promise.resolve(null) : Promise.reject()),
[namespace],
(opts) => {
if (!biasMetricsEnabled) {
return Promise.reject(new NotReadyError('Bias metrics is not enabled'));
}
return namespace && opts ? Promise.resolve(null) : Promise.reject();
},
[namespace, biasMetricsEnabled],
);

const state = useFetchState<State>(callback, null, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PipelineCoreResourceKF, PipelineRunKF } from '~/concepts/pipelines/kfTy
import { pipelineRunColumns } from '~/concepts/pipelines/content/tables/columns';
import PipelineRunTableRow from '~/concepts/pipelines/content/tables/pipelineRun/PipelineRunTableRow';
import useCheckboxTable from '~/components/table/useCheckboxTable';
import EmptyTableView from '~/concepts/pipelines/content/tables/EmptyTableView';
import DashboardEmptyTableView from '~/concepts/dashboard/DashboardEmptyTableView';
import usePipelineRunFilter from '~/concepts/pipelines/content/tables/pipelineRun/usePipelineRunFilter';
import PipelineRunTableToolbar from '~/concepts/pipelines/content/tables/pipelineRun/PipelineRunTableToolbar';
import DeletePipelineCoreResourceModal from '~/concepts/pipelines/content/DeletePipelineCoreResourceModal';
Expand All @@ -32,7 +32,7 @@ const PipelineRunTable: React.FC<PipelineRunTableProps> = ({ runs }) => {
data={filteredRuns}
columns={pipelineRunColumns}
enablePagination
emptyTableView={<EmptyTableView onClearFilters={toolbarProps.onClearFilters} />}
emptyTableView={<DashboardEmptyTableView onClearFilters={toolbarProps.onClearFilters} />}
toolbarContent={
<PipelineRunTableToolbar
{...toolbarProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useCheckboxTable from '~/components/table/useCheckboxTable';
import PipelineRunJobTableRow from '~/concepts/pipelines/content/tables/pipelineRunJob/PipelineRunJobTableRow';
import PipelineRunJobTableToolbar from '~/concepts/pipelines/content/tables/pipelineRunJob/PipelineRunJobTableToolbar';
import usePipelineRunJobFilter from '~/concepts/pipelines/content/tables/pipelineRunJob/usePipelineRunJobFilter';
import EmptyTableView from '~/concepts/pipelines/content/tables/EmptyTableView';
import DashboardEmptyTableView from '~/concepts/dashboard/DashboardEmptyTableView';
import DeletePipelineCoreResourceModal from '~/concepts/pipelines/content/DeletePipelineCoreResourceModal';
import { usePipelinesAPI } from '~/concepts/pipelines/context';

Expand All @@ -30,7 +30,7 @@ const PipelineRunJobTable: React.FC<PipelineRunTableProps> = ({ jobs }) => {
data={filterJobs}
columns={pipelineRunJobColumns}
enablePagination
emptyTableView={<EmptyTableView onClearFilters={toolbarProps.onClearFilters} />}
emptyTableView={<DashboardEmptyTableView onClearFilters={toolbarProps.onClearFilters} />}
toolbarContent={
<PipelineRunJobTableToolbar
{...toolbarProps}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/pages/modelServing/ModelServingRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { Navigate, Route } from 'react-router-dom';
import ProjectsRoutes from '~/concepts/projects/ProjectsRoutes';
import { ExplainabilityProvider } from '~/concepts/explainability/ExplainabilityContext';
import useBiasMetricsEnabled from '~/concepts/explainability/useBiasMetricsEnabled';
import BiasConfigurationBreadcrumbPage from './screens/metrics/BiasConfigurationBreadcrumbPage';
import GlobalInferenceMetricsPage from './screens/metrics/GlobalInferenceMetricsPage';
import ModelServingContextProvider from './ModelServingContext';
Expand All @@ -11,6 +12,7 @@ import useModelMetricsEnabled from './useModelMetricsEnabled';

const ModelServingRoutes: React.FC = () => {
const [modelMetricsEnabled] = useModelMetricsEnabled();
const [biasMetricsEnabled] = useBiasMetricsEnabled();

//TODO: Split route to project and mount provider here. This will allow you to load data when model switching is later implemented.
return (
Expand All @@ -22,7 +24,9 @@ const ModelServingRoutes: React.FC = () => {
<Route index element={<Navigate to=".." />} />
<Route path=":inferenceService" element={<GlobalInferenceMetricsWrapper />}>
<Route path=":tab?" element={<GlobalInferenceMetricsPage />} />
<Route path="configure" element={<BiasConfigurationBreadcrumbPage />} />
{biasMetricsEnabled && (
<Route path="configure" element={<BiasConfigurationBreadcrumbPage />} />
)}
</Route>
{/* TODO: Global Runtime metrics?? */}
<Route path="*" element={<Navigate to="." />} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as React from 'react';
import { Button } from '@patternfly/react-core';
import ManageInferenceServiceModal from '~/pages/modelServing/screens/projects/InferenceServiceModal/ManageInferenceServiceModal';
import Table from '~/components/table/Table';

import { InferenceServiceKind, ServingRuntimeKind } from '~/k8sTypes';
import { ProjectsContext } from '~/concepts/projects/ProjectsContext';
import DashboardEmptyTableView from '~/concepts/dashboard/DashboardEmptyTableView';
import InferenceServiceTableRow from './InferenceServiceTableRow';
import { getGlobalInferenceServiceColumns, getProjectInferenceServiceColumns } from './data';
import DeleteInferenceServiceModal from './DeleteInferenceServiceModal';
Expand Down Expand Up @@ -41,14 +40,7 @@ const InferenceServiceTable: React.FC<InferenceServiceTableProps> = ({
toolbarContent={toolbarContent}
enablePagination={enablePagination}
emptyTableView={
isGlobal ? (
<>
No projects match your filters.{' '}
<Button variant="link" isInline onClick={clearFilters}>
Clear filters
</Button>
</>
) : undefined
isGlobal ? <DashboardEmptyTableView onClearFilters={clearFilters} /> : undefined
}
rowRenderer={(is) => (
<InferenceServiceTableRow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ import {
EmptyStateVariant,
Title,
} from '@patternfly/react-core';
import { PlusCircleIcon } from '@patternfly/react-icons';
import { WrenchIcon } from '@patternfly/react-icons';
import { EMPTY_BIAS_CONFIGURATION_DESC, EMPTY_BIAS_CONFIGURATION_TITLE } from './const';

const BiasConfigurationEmptyState: React.FC = () => (
<EmptyState variant={EmptyStateVariant.large} data-id="empty-empty-state">
<EmptyStateIcon icon={PlusCircleIcon} />
type BiasConfigurationEmptyStateProps = {
actionButton: React.ReactNode;
variant: EmptyStateVariant;
};

const BiasConfigurationEmptyState: React.FC<BiasConfigurationEmptyStateProps> = ({
actionButton,
variant,
}) => (
<EmptyState variant={variant} data-id="bias-metrics-empty-state">
<EmptyStateIcon icon={WrenchIcon} />
<Title headingLevel="h2" size="lg">
No bias metrics configured
{EMPTY_BIAS_CONFIGURATION_TITLE}
</Title>
<EmptyStateBody>
No bias metrics for this model have been configured. To monitor model bias, you must first
configure metrics
</EmptyStateBody>
<EmptyStateBody>{EMPTY_BIAS_CONFIGURATION_DESC}</EmptyStateBody>
{actionButton}
</EmptyState>
);

Expand Down
Loading

0 comments on commit e2f799d

Please sign in to comment.