Visitar URL original
feat: Data Quality Monitoring added in feast UI by jyejare · Pull Request #6422 · feast-dev/feast · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: Feature Store Monitoring UI support is added
Signed-off-by: Jitendra Yejare <11752425+jyejare@users.noreply.github.com>
  • Loading branch information
jyejare committed Jun 12, 2026
commit 5fd083e28ca23179b63de0107dd4fb2679f026f0
222 changes: 123 additions & 99 deletions ui/src/FeastUISansProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ import LabelViewInstance from "./pages/label-views/LabelViewInstance";
import PermissionsIndex from "./pages/permissions/Index";
import LineageIndex from "./pages/lineage/Index";
import NoProjectGuard from "./components/NoProjectGuard";
import MonitoringIndex from "./pages/monitoring/Index";
import FeatureMetricsDetail from "./pages/monitoring/FeatureMetricsDetail";

import TabsRegistryContext, {
FeastTabsRegistryInterface,
} from "./custom-tabs/TabsRegistryContext";
import MonitoringContext, {
MonitoringConfig,
} from "./contexts/MonitoringContext";
import CurlGeneratorTab from "./pages/feature-views/CurlGeneratorTab";
import FeatureFlagsContext, {
FeatureFlags,
Expand All @@ -47,6 +52,7 @@ interface FeastUIConfigs {
featureFlags?: FeatureFlags;
projectListPromise?: Promise<any>;
fetchOptions?: FetchOptions;
monitoringConfig?: MonitoringConfig;
}

const defaultProjectListPromise = (basename: string) => {
Expand Down Expand Up @@ -107,110 +113,128 @@ const FeastUISansProvidersInner = ({
<EuiProvider colorMode={colorMode}>
<EuiErrorBoundary>
<DataModeContext.Provider value={dataModeConfig}>
<TabsRegistryContext.Provider
value={{
RegularFeatureViewCustomTabs: [
{
label: "CURL Generator",
path: "curl-generator",
Component: CurlGeneratorTab,
},
...(feastUIConfigs?.tabsRegistry
?.RegularFeatureViewCustomTabs || []),
],
OnDemandFeatureViewCustomTabs:
feastUIConfigs?.tabsRegistry?.OnDemandFeatureViewCustomTabs ||
[],
StreamFeatureViewCustomTabs:
feastUIConfigs?.tabsRegistry?.StreamFeatureViewCustomTabs || [],
FeatureServiceCustomTabs:
feastUIConfigs?.tabsRegistry?.FeatureServiceCustomTabs || [],
FeatureCustomTabs:
feastUIConfigs?.tabsRegistry?.FeatureCustomTabs || [],
DataSourceCustomTabs:
feastUIConfigs?.tabsRegistry?.DataSourceCustomTabs || [],
EntityCustomTabs:
feastUIConfigs?.tabsRegistry?.EntityCustomTabs || [],
DatasetCustomTabs:
feastUIConfigs?.tabsRegistry?.DatasetCustomTabs || [],
}}
<MonitoringContext.Provider
value={
feastUIConfigs?.monitoringConfig || {
apiBaseUrl: "/api/v1",
enabled: true,
}
}
>
<FeatureFlagsContext.Provider
value={feastUIConfigs?.featureFlags || {}}
<TabsRegistryContext.Provider
value={{
RegularFeatureViewCustomTabs: [
{
label: "CURL Generator",
path: "curl-generator",
Component: CurlGeneratorTab,
},
...(feastUIConfigs?.tabsRegistry
?.RegularFeatureViewCustomTabs || []),
],
OnDemandFeatureViewCustomTabs:
feastUIConfigs?.tabsRegistry?.OnDemandFeatureViewCustomTabs ||
[],
StreamFeatureViewCustomTabs:
feastUIConfigs?.tabsRegistry?.StreamFeatureViewCustomTabs || [],
FeatureServiceCustomTabs:
feastUIConfigs?.tabsRegistry?.FeatureServiceCustomTabs || [],
FeatureCustomTabs:
feastUIConfigs?.tabsRegistry?.FeatureCustomTabs || [],
DataSourceCustomTabs:
feastUIConfigs?.tabsRegistry?.DataSourceCustomTabs || [],
EntityCustomTabs:
feastUIConfigs?.tabsRegistry?.EntityCustomTabs || [],
DatasetCustomTabs:
feastUIConfigs?.tabsRegistry?.DatasetCustomTabs || [],
}}
>
<ProjectListContext.Provider value={projectListContext}>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<RootProjectSelectionPage />} />
<Route
path="/p/:projectName/*"
element={<NoProjectGuard />}
>
<Route index element={<ProjectOverviewPage />} />
<Route
path="data-source/"
element={<DatasourceIndex />}
/>
<Route
path="data-source/:dataSourceName/*"
element={<DataSourceInstance />}
/>
<Route path="features/" element={<FeatureListPage />} />
<Route
path="feature-view/"
element={<FeatureViewIndex />}
/>
<Route
path="feature-view/:featureViewName/*"
element={<FeatureViewInstance />}
></Route>
<Route
path="feature-view/:FeatureViewName/feature/:FeatureName/*"
element={<FeatureInstance />}
/>
<Route
path="feature-service/"
element={<FeatureServiceIndex />}
/>
<Route
path="feature-service/:featureServiceName/*"
element={<FeatureServiceInstance />}
/>
<Route path="entity/" element={<EntityIndex />} />
<Route
path="entity/:entityName/*"
element={<EntityInstance />}
/>
<FeatureFlagsContext.Provider
value={feastUIConfigs?.featureFlags || {}}
>
<ProjectListContext.Provider value={projectListContext}>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<RootProjectSelectionPage />} />
<Route path="/p/:projectName/*" element={<NoProjectGuard />}>
<Route index element={<ProjectOverviewPage />} />
<Route path="data-source/" element={<DatasourceIndex />} />
<Route
path="/p/:projectName/*"
element={<NoProjectGuard />}
>
<Route index element={<ProjectOverviewPage />} />
<Route
path="data-source/"
element={<DatasourceIndex />}
/>
<Route
path="data-source/:dataSourceName/*"
element={<DataSourceInstance />}
/>
<Route path="features/" element={<FeatureListPage />} />
<Route
path="feature-view/"
element={<FeatureViewIndex />}
/>
<Route
path="feature-view/:featureViewName/*"
element={<FeatureViewInstance />}
></Route>
<Route
path="feature-view/:FeatureViewName/feature/:FeatureName/*"
element={<FeatureInstance />}
/>
<Route
path="feature-service/"
element={<FeatureServiceIndex />}
/>
<Route
path="feature-service/:featureServiceName/*"
element={<FeatureServiceInstance />}
/>
<Route path="entity/" element={<EntityIndex />} />
<Route
path="entity/:entityName/*"
element={<EntityInstance />}
/>

<Route path="label-view/" element={<LabelViewIndex />} />
<Route
path="label-view/:labelViewName/*"
element={<LabelViewInstance />}
/>
<Route
path="label-view/:FeatureViewName/label/:FeatureName/*"
element={<FeatureInstance />}
/>
<Route path="data-set/" element={<DatasetIndex />} />
<Route
path="data-set/:datasetName/*"
element={<DatasetInstance />}
/>
<Route
path="permissions/"
element={<PermissionsIndex />}
/>
<Route path="lineage/" element={<LineageIndex />} />
<Route path="label-view/" element={<LabelViewIndex />} />
<Route
path="label-view/:labelViewName/*"
element={<LabelViewInstance />}
/>
<Route
path="label-view/:FeatureViewName/label/:FeatureName/*"
element={<FeatureInstance />}
/>
<Route path="data-set/" element={<DatasetIndex />} />
<Route
path="data-set/:datasetName/*"
element={<DatasetInstance />}
/>
<Route path="permissions/" element={<PermissionsIndex />} />
<Route path="lineage/" element={<LineageIndex />} />
<Route
path="monitoring/"
element={<MonitoringIndex />}
/>
<Route
path="monitoring/feature/:featureViewName/:featureName"
element={<FeatureMetricsDetail />}
/>
</Route>
</Route>
</Route>
</Route>
<Route path="*" element={<NoMatch />} />
</Routes>
</ProjectListContext.Provider>
</FeatureFlagsContext.Provider>
</TabsRegistryContext.Provider>
<Route path="*" element={<NoMatch />} />
</Routes>
</ProjectListContext.Provider>
</FeatureFlagsContext.Provider>
</TabsRegistryContext.Provider>
</MonitoringContext.Provider>
</DataModeContext.Provider>
</EuiErrorBoundary>
</EuiProvider>
</EuiErrorBoundary>
</EuiProvider>
);
};

Expand Down
14 changes: 14 additions & 0 deletions ui/src/contexts/MonitoringContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";

interface MonitoringConfig {
apiBaseUrl: string;
enabled: boolean;
}

const MonitoringContext = React.createContext<MonitoringConfig>({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all monitoring hooks fire even when DQM isn’t configured. Consider defaulting to false and enabling only when DQM is present. Monitoring nav is always shown with no gating on monitoringConfig.enabled. Hide it when monitoring is disabled.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After discussions we are keeping it always and showing the empty state with requesting to enable monitoring, when monitoring is not enabled.

apiBaseUrl: "/api/v1",
enabled: true,
});

export default MonitoringContext;
export type { MonitoringConfig };
18 changes: 18 additions & 0 deletions ui/src/pages/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,24 @@ const SideNav = () => {
renderItem: (props) => <Link {...props} to={`${baseUrl}/data-set`} />,
isSelected: useMatchSubpath(`${baseUrl}/data-set`),
},
{
name: "Monitoring",
id: htmlIdGenerator("monitoring")(),
icon: <EuiIcon type="monitoringApp" />,
renderItem: (props) => (
<Link {...props} to={`${baseUrl}/monitoring`} />
),
isSelected: useMatchSubpath(`${baseUrl}/monitoring`),
},
{
name: "Data Labeling",
id: htmlIdGenerator("dataLabeling")(),
icon: <EuiIcon type="documentEdit" color="#006BB4" />,
renderItem: (props) => (
<Link {...props} to={`${baseUrl}/data-labeling`} />
),
isSelected: useMatchSubpath(`${baseUrl}/data-labeling`),
},
{
name: "Permissions",
id: htmlIdGenerator("permissions")(),
Expand Down
11 changes: 10 additions & 1 deletion ui/src/pages/features/FeatureInstance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { Route, Routes, useNavigate, useParams } from "react-router-dom";
import { EuiPageTemplate } from "@elastic/eui";

import { FeatureIcon } from "../../graphics/FeatureIcon";
import { useMatchExact } from "../../hooks/useMatchSubpath";
import { useMatchExact, useMatchSubpath } from "../../hooks/useMatchSubpath";
import FeatureOverviewTab from "./FeatureOverviewTab";
import FeatureMonitoringTab from "./FeatureMonitoringTab";
import { useDocumentTitle } from "../../hooks/useDocumentTitle";
import {
useFeatureCustomTabs,
Expand Down Expand Up @@ -34,12 +35,20 @@ const FeatureInstance = () => {
navigate("");
},
},
{
label: "Monitoring",
isSelected: useMatchSubpath("monitoring"),
onClick: () => {
navigate("monitoring");
},
},
...customNavigationTabs,
]}
/>
<EuiPageTemplate.Section>
<Routes>
<Route path="/" element={<FeatureOverviewTab />} />
<Route path="/monitoring" element={<FeatureMonitoringTab />} />
{CustomTabRoutes}
</Routes>
</EuiPageTemplate.Section>
Expand Down
Loading