diff --git a/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx b/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx
index ad9723be64..226a2cb4fd 100644
--- a/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx
+++ b/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx
@@ -1,99 +1,38 @@
-import { useMemo } from 'react';
+import { FC, useEffect, useMemo, useState } from 'react';
import useApplication from 'hooks/api/getters/useApplication/useApplication';
-import { WarningAmber } from '@mui/icons-material';
import { formatDateYMDHMS } from 'utils/formatDate';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useConnectedInstancesTable } from './useConnectedInstancesTable';
import { ConnectedInstancesTable } from './ConnectedInstancesTable';
import { IApplication } from 'interfaces/application';
-import { useQueryParam } from 'use-query-params';
-import { styled } from '@mui/material';
-import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
+import { Box, ToggleButton, ToggleButtonGroup } from '@mui/material';
+import { useApplicationOverview } from 'hooks/api/getters/useApplicationOverview/useApplicationOverview';
+import { useConnectedInstances } from 'hooks/api/getters/useConnectedInstances/useConnectedInstances';
-const Container = styled('div')(({ theme }) => ({
- '* + *': {
- marginBlockStart: theme.spacing(2),
- },
-}));
-
-const EnvironmentSelectionContainer = styled('div')(({ theme }) => ({
- label: {
- '--padding-horizontal': theme.spacing(3),
- '--padding-vertical': theme.spacing(1),
- color: theme.palette.primary.main,
- background: theme.palette.background,
- paddingInline: 'var(--padding-horizontal)',
- paddingBlock: 'var(--padding-vertical)',
- border: `1px solid ${theme.palette.background.alternative}`,
- borderInlineStart: 'none',
- fontWeight: 'bold',
- position: 'relative',
-
- svg: {
- color: theme.palette.warning.main,
- position: 'absolute',
- fontSize: theme.fontSizes.bodySize,
- top: 'calc(var(--padding-horizontal) * .12)',
- right: 'calc(var(--padding-horizontal) * .2)',
- },
- },
- 'label:first-of-type': {
- borderInlineStart: `1px solid ${theme.palette.background.alternative}`,
- borderRadius: `${theme.shape.borderRadiusMedium}px 0 0 ${theme.shape.borderRadiusMedium}px`,
- },
- 'label:last-of-type': {
- borderRadius: `0 ${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px 0`,
- },
- 'label:has(input:checked)': {
- background: theme.palette.background.alternative,
- color: theme.palette.primary.contrastText,
-
- svg: {
- color: 'inherit',
- },
- },
- 'label:focus-within': {
- outline: `2px solid ${theme.palette.background.alternative}`,
- outlineOffset: theme.spacing(0.5),
- },
-
- fieldset: {
- border: 'none',
- padding: 0,
- margin: 0,
- },
- legend: {
- marginBlockEnd: theme.spacing(3),
- },
-
- '.visually-hidden': {
- border: 0,
- clip: 'rect(0 0 0 0)',
- height: 'auto',
- margin: 0,
- overflow: 'hidden',
- padding: 0,
- position: 'absolute',
- width: '1px',
- whiteSpace: 'nowrap',
- },
-}));
-
-export const ConnectedInstances = () => {
+export const ConnectedInstances: FC = () => {
const name = useRequiredPathParam('name');
const { application } = useApplication(name);
- const [currentEnvironment, setCurrentEnvironment] =
- useQueryParam('environment');
- const availableEnvironments = new Set(
- application?.instances.map(
- // @ts-expect-error: the type definition here is incomplete. It
- // should be updated as part of this project.
- (instance) => instance.environment,
- ),
+ const { data: applicationOverview } = useApplicationOverview(name);
+
+ const availableEnvironments = applicationOverview.environments.map(
+ (env) => env.name,
);
- const allEnvironmentsSorted = Array.from(availableEnvironments)
- .sort((a, b) => a.localeCompare(b))
- .map((env) => ({ name: env, problemsDetected: false }));
+ const allEnvironmentsSorted = Array.from(availableEnvironments).sort(
+ (a, b) => a.localeCompare(b),
+ );
+ const [currentEnvironment, setCurrentEnvironment] = useState(
+ allEnvironmentsSorted[0],
+ );
+ const { data: connectedInstances } = useConnectedInstances(
+ name,
+ currentEnvironment,
+ );
+
+ useEffect(() => {
+ if (!currentEnvironment && availableEnvironments.length > 0) {
+ setCurrentEnvironment(availableEnvironments[0]);
+ }
+ }, [JSON.stringify(availableEnvironments)]);
const tableData = useMemo(() => {
const map = ({
@@ -123,41 +62,28 @@ export const ConnectedInstances = () => {
useConnectedInstancesTable(tableData);
return (
-
-
-
-
+
+
{
getTableProps={getTableProps}
rows={rows}
/>
-
+
);
};
diff --git a/frontend/src/component/application/ConnectedInstances/useConnectedInstancesTable.tsx b/frontend/src/component/application/ConnectedInstances/useConnectedInstancesTable.tsx
index 234b1d8aa1..751ac8215e 100644
--- a/frontend/src/component/application/ConnectedInstances/useConnectedInstancesTable.tsx
+++ b/frontend/src/component/application/ConnectedInstances/useConnectedInstancesTable.tsx
@@ -14,7 +14,7 @@ export const useConnectedInstancesTable = (
instanceData: ConnectedInstancesTableData[],
) => {
const initialState = useMemo(
- () => ({ sortBy: [{ id: 'instanceId' }] }),
+ () => ({ sortBy: [{ id: 'lastSeen', desc: true }] }),
[],
);
diff --git a/frontend/src/hooks/api/getters/useConnectedInstances/useConnectedInstances.ts b/frontend/src/hooks/api/getters/useConnectedInstances/useConnectedInstances.ts
new file mode 100644
index 0000000000..912797b28a
--- /dev/null
+++ b/frontend/src/hooks/api/getters/useConnectedInstances/useConnectedInstances.ts
@@ -0,0 +1,44 @@
+import { SWRConfiguration } from 'swr';
+import { formatApiPath } from 'utils/formatPath';
+import handleErrorResponses from '../httpErrorResponseHandler';
+import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
+
+type ConnectedInstancesSchema = {
+ instances: {
+ instanceId: string;
+ sdk: string;
+ clientIp: string;
+ lastSeen: string;
+ }[];
+};
+
+export const useConnectedInstances = (
+ application: string,
+ environment?: string,
+ options: SWRConfiguration = {},
+) => {
+ const path = formatApiPath(
+ `api/admin/metrics/instances/${application}/${environment}`,
+ );
+ const { data, error } = useConditionalSWR(
+ Boolean(environment),
+ { instances: [] },
+ path,
+ fetcher,
+ options,
+ );
+
+ return {
+ data: data || { instances: [] },
+ error,
+ loading: !error && !data,
+ };
+};
+
+const fetcher = async (path: string): Promise => {
+ const res = await fetch(path).then(
+ handleErrorResponses('Connected instances'),
+ );
+ const data = await res.json();
+ return data;
+};