diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/__snapshots__/NavigationSidebar.test.tsx.snap b/frontend/src/component/layout/MainLayout/NavigationSidebar/__snapshots__/NavigationSidebar.test.tsx.snap
index 07aaa5b624..83eb5ebe97 100644
--- a/frontend/src/component/layout/MainLayout/NavigationSidebar/__snapshots__/NavigationSidebar.test.tsx.snap
+++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/__snapshots__/NavigationSidebar.test.tsx.snap
@@ -78,6 +78,10 @@ exports[`order of items in navigation > menu for enterprise plan 1`] = `
"icon": "AssignmentOutlinedIcon",
"text": "Single sign-on",
},
+ {
+ "icon": "HubOutlinedIcon",
+ "text": "Network",
+ },
{
"icon": "BuildOutlinedIcon",
"text": "Maintenance",
@@ -256,6 +260,10 @@ exports[`order of items in navigation > menu for pro plan 1`] = `
"icon": "AssignmentOutlinedIcon",
"text": "Single sign-on",
},
+ {
+ "icon": "HubOutlinedIcon",
+ "text": "Network",
+ },
{
"icon": "BuildOutlinedIcon",
"text": "Maintenance",
diff --git a/frontend/src/hooks/api/getters/useConnectedEdges/useConnectedEdges.ts b/frontend/src/hooks/api/getters/useConnectedEdges/useConnectedEdges.ts
new file mode 100644
index 0000000000..4e7afd89c1
--- /dev/null
+++ b/frontend/src/hooks/api/getters/useConnectedEdges/useConnectedEdges.ts
@@ -0,0 +1,39 @@
+import { useMemo } from 'react';
+import useUiConfig from '../useUiConfig/useUiConfig';
+import { formatApiPath } from 'utils/formatPath';
+import handleErrorResponses from '../httpErrorResponseHandler';
+import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
+import type { ConnectedEdge } from 'interfaces/connectedEdge';
+import type { SWRConfiguration } from 'swr';
+import { useUiFlag } from 'hooks/useUiFlag';
+
+const DEFAULT_DATA: ConnectedEdge[] = [];
+
+export const useConnectedEdges = (options?: SWRConfiguration) => {
+ const { isEnterprise } = useUiConfig();
+ const edgeObservabilityEnabled = useUiFlag('edgeObservability');
+
+ const { data, error, mutate } = useConditionalSWR(
+ isEnterprise() && edgeObservabilityEnabled,
+ DEFAULT_DATA,
+ formatApiPath('api/admin/metrics/edges'),
+ fetcher,
+ options,
+ );
+
+ return useMemo(
+ () => ({
+ connectedEdges: data ?? [],
+ loading: !error && !data,
+ refetch: () => mutate(),
+ error,
+ }),
+ [data, error, mutate],
+ );
+};
+
+const fetcher = (path: string) => {
+ return fetch(path)
+ .then(handleErrorResponses('Connected Edges'))
+ .then((res) => res.json());
+};
diff --git a/frontend/src/hooks/api/getters/useInstanceMetrics/useInstanceMetrics.ts b/frontend/src/hooks/api/getters/useInstanceMetrics/useInstanceMetrics.ts
index 31890661f8..f47dc34bd1 100644
--- a/frontend/src/hooks/api/getters/useInstanceMetrics/useInstanceMetrics.ts
+++ b/frontend/src/hooks/api/getters/useInstanceMetrics/useInstanceMetrics.ts
@@ -1,8 +1,10 @@
-import useSWR, { type SWRConfiguration } from 'swr';
+import type { SWRConfiguration } from 'swr';
import { useMemo } from 'react';
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import type { RequestsPerSecondSchema } from 'openapi';
+import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
+import useUiConfig from '../useUiConfig/useUiConfig';
export interface IInstanceMetricsResponse {
metrics: RequestsPerSecondSchema;
@@ -17,7 +19,13 @@ export interface IInstanceMetricsResponse {
export const useInstanceMetrics = (
options: SWRConfiguration = {},
): IInstanceMetricsResponse => {
- const { data, error, mutate } = useSWR(
+ const {
+ uiConfig: { networkViewEnabled },
+ } = useUiConfig();
+
+ const { data, error, mutate } = useConditionalSWR(
+ networkViewEnabled,
+ {},
formatApiPath(`api/admin/metrics/rps`),
fetcher,
options,
diff --git a/frontend/src/interfaces/connectedEdge.ts b/frontend/src/interfaces/connectedEdge.ts
new file mode 100644
index 0000000000..dc4d9bba6f
--- /dev/null
+++ b/frontend/src/interfaces/connectedEdge.ts
@@ -0,0 +1,23 @@
+export type ConnectedEdge = {
+ id?: string;
+ appName: string;
+ connectedStreamingClients: number;
+ edgeVersion: string;
+ instanceId: string;
+ region: string | null;
+ reportedAt: string;
+ started: string;
+ connectedVia?: string;
+ cpuUsage: string;
+ memoryUsage: number;
+ clientFeaturesAverageLatencyMs: string;
+ clientFeaturesP99LatencyMs: string;
+ frontendApiAverageLatencyMs: string;
+ frontendApiP99LatencyMs: string;
+ upstreamFeaturesAverageLatencyMs: string;
+ upstreamFeaturesP99LatencyMs: string;
+ upstreamMetricsAverageLatencyMs: string;
+ upstreamMetricsP99LatencyMs: string;
+ upstreamEdgeAverageLatencyMs: string;
+ upstreamEdgeP99LatencyMs: string;
+};
diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts
index 9a881e4569..a3931c9ad1 100644
--- a/frontend/src/interfaces/uiConfig.ts
+++ b/frontend/src/interfaces/uiConfig.ts
@@ -94,6 +94,7 @@ export type UiFlags = {
dataUsageMultiMonthView?: boolean;
uiGlobalFontSize?: boolean;
connectionCount?: boolean;
+ edgeObservability?: boolean;
};
export interface IVersionInfo {
diff --git a/src/lib/openapi/spec/ui-config-schema.ts b/src/lib/openapi/spec/ui-config-schema.ts
index 705b7acabb..f121a1d52d 100644
--- a/src/lib/openapi/spec/ui-config-schema.ts
+++ b/src/lib/openapi/spec/ui-config-schema.ts
@@ -101,7 +101,7 @@ export const uiConfigSchema = {
},
networkViewEnabled: {
type: 'boolean',
- description: 'Whether to enable the Unleash network view or not.',
+ description: 'Whether a Prometheus API is available.',
example: true,
},
frontendApiOrigins: {
diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts
index e1504613a6..5c9a96f01c 100644
--- a/src/lib/types/experimental.ts
+++ b/src/lib/types/experimental.ts
@@ -67,7 +67,8 @@ export type IFlagKey =
| 'dataUsageMultiMonthView'
| 'uiGlobalFontSize'
| 'connectionCount'
- | 'teamsIntegrationChangeRequests';
+ | 'teamsIntegrationChangeRequests'
+ | 'edgeObservability';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@@ -324,6 +325,10 @@ const flags: IFlags = {
process.env.EXPERIMENTAL_TEAMS_INTEGRATION_CHANGE_REQUESTS,
false,
),
+ edgeObservability: parseEnvVarBoolean(
+ process.env.EXPERIMENTAL_EDGE_OBSERVABILITY,
+ false,
+ ),
};
export const defaultExperimentalOptions: IExperimentalOptions = {