Skip to content

Commit 9119129

Browse files
committed
refactor: filter linked progress
wip: hooked up wip: dimming wip: more wip: more refactors chore: lots of widgets chore: linting and refinements chore: update changelog wip: avatar update chore: updated avatar color chore: all of the async stuff chore: additional clean up chore: fix typos chore: fix async states
1 parent 9eda5a0 commit 9119129

File tree

29 files changed

+640
-372
lines changed

29 files changed

+640
-372
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type: Changed # One of: Added, Changed, Developer Experience, Deprecated, Docs, Fixed, Removed, Security
2+
description: Refactor progress widgets
3+
pr: 7846 # PR number
4+
labels: [] # Optional: ["high-risk", "db-migration"]

clients/admin-ui/cypress/e2e/action-center/assets-results.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import {
77
} from "cypress/support/stubs";
88

99
import { ACTION_CENTER_ROUTE } from "~/features/common/nav/routes";
10-
import { MONITOR_TYPES } from "~/features/data-discovery-and-detection/action-center/utils/getMonitorType";
10+
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
1111

12-
const WEB_MONITOR_ROUTE = `${ACTION_CENTER_ROUTE}/${MONITOR_TYPES.WEBSITE}`;
12+
const WEB_MONITOR_ROUTE = `${ACTION_CENTER_ROUTE}/${APIMonitorType.WEBSITE}`;
1313

1414
describe("Action center Asset Results", () => {
1515
beforeEach(() => {

clients/admin-ui/src/features/common/api.slice.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ export const baseApi = createApi({
113113
"Access Policy Control Groups",
114114
"Access Control",
115115
"Fides Dashboard",
116+
"Monitor Statistics",
117+
"Connection Type",
116118
],
117119
endpoints: () => ({}),
118120
});

clients/admin-ui/src/features/data-discovery-and-detection/action-center/ActionCenterLayout.tsx

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
Menu,
1010
} from "fidesui";
1111
import _ from "lodash";
12-
import { PropsWithChildren } from "react";
12+
import { PropsWithChildren, useState } from "react";
1313

1414
import FixedLayout from "~/features/common/FixedLayout";
1515
import { ACTION_CENTER_ROUTE } from "~/features/common/nav/routes";
@@ -18,6 +18,7 @@ import useActionCenterNavigation, {
1818
ActionCenterRoute,
1919
ActionCenterRouteConfig,
2020
} from "~/features/data-discovery-and-detection/action-center/hooks/useActionCenterNavigation";
21+
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
2122

2223
import MonitorStats from "./MonitorStats";
2324

@@ -28,14 +29,19 @@ export interface ActionCenterLayoutProps {
2829
dropdownProps?: DropdownProps;
2930
badgeProps?: BadgeProps;
3031
};
32+
refresh?: () => Promise<void>;
33+
monitorType?: APIMonitorType;
3134
}
3235

3336
const ActionCenterLayout = ({
3437
children,
3538
monitorId,
39+
monitorType,
3640
routeConfig,
3741
pageSettings,
42+
refresh,
3843
}: PropsWithChildren<ActionCenterLayoutProps>) => {
44+
const [refreshing, setRefreshing] = useState(false);
3945
const {
4046
items: menuItems,
4147
activeItem,
@@ -56,21 +62,41 @@ const ActionCenterLayout = ({
5662
]}
5763
isSticky={false}
5864
rightContent={
59-
pageSettings && (
60-
<Flex>
61-
<Badge {...pageSettings.badgeProps}>
62-
<Dropdown {...pageSettings.dropdownProps}>
63-
<Button
64-
aria-label="Page settings"
65-
icon={<Icons.SettingsView />}
66-
/>
67-
</Dropdown>
68-
</Badge>
69-
</Flex>
70-
)
65+
<Flex gap="small">
66+
{pageSettings && (
67+
<Flex>
68+
<Badge {...pageSettings.badgeProps}>
69+
<Dropdown {...pageSettings.dropdownProps}>
70+
<Button
71+
aria-label="Page settings"
72+
icon={<Icons.SettingsView />}
73+
/>
74+
</Dropdown>
75+
</Badge>
76+
</Flex>
77+
)}
78+
{refresh && (
79+
<Button
80+
aria-label="Page refresh"
81+
icon={<Icons.Renew />}
82+
onClick={async () => {
83+
setRefreshing(true);
84+
try {
85+
await refresh();
86+
} finally {
87+
setRefreshing(false);
88+
}
89+
}}
90+
disabled={refreshing}
91+
loading={refreshing}
92+
/>
93+
)}
94+
</Flex>
7195
}
7296
/>
73-
<MonitorStats monitorId={monitorId} />
97+
{monitorId && monitorType && (
98+
<MonitorStats monitorId={monitorId} monitorType={monitorType} />
99+
)}
74100
<Menu
75101
aria-label="Action center tabs"
76102
mode="horizontal"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { skipToken } from "@reduxjs/toolkit/query";
2+
import { Descriptions, Flex, Text } from "fidesui";
3+
4+
import { useFlags } from "~/features/common/features";
5+
6+
import {
7+
useGetConnectionQuery,
8+
useGetMonitorConfigQuery,
9+
} from "./action-center.slice";
10+
11+
export interface MonitorDetailsWidgetProps {
12+
monitorId: string;
13+
}
14+
15+
const MonitorDetailsWidget = ({ monitorId }: MonitorDetailsWidgetProps) => {
16+
const {
17+
flags: { heliosInsights },
18+
} = useFlags();
19+
const { data: configData } = useGetMonitorConfigQuery({
20+
monitor_config_id: monitorId,
21+
});
22+
const connectionKey = configData?.connection_config_key;
23+
const { data: connectionData } = useGetConnectionQuery(
24+
connectionKey ? { connection_key: connectionKey } : skipToken,
25+
);
26+
27+
return (
28+
heliosInsights && (
29+
<Flex className="w-full" gap="middle" vertical>
30+
<Text strong>Details</Text>
31+
<Descriptions
32+
size="small"
33+
items={[
34+
{
35+
label: "System",
36+
children: connectionData?.system_key,
37+
span: "filled",
38+
},
39+
{
40+
label: "Integration",
41+
children: connectionData?.key,
42+
43+
span: "filled",
44+
},
45+
]}
46+
/>
47+
</Flex>
48+
)
49+
);
50+
};
51+
52+
export default MonitorDetailsWidget;

clients/admin-ui/src/features/data-discovery-and-detection/action-center/MonitorList.const.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import {
66
} from "nuqs";
77
import * as v from "valibot";
88

9-
import { MONITOR_TYPES } from "./utils/getMonitorType";
9+
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
1010

1111
export const MonitorSearchFormQuerySchema = (
12-
availableMonitors: Array<MONITOR_TYPES>,
12+
availableMonitors: Array<APIMonitorType>,
1313
) =>
1414
v.object({
1515
search: v.nullish(v.string(), null),
@@ -18,7 +18,7 @@ export const MonitorSearchFormQuerySchema = (
1818
});
1919

2020
export const SearchFormQueryState = (
21-
availableMonitors: Array<MONITOR_TYPES>,
21+
availableMonitors: Array<APIMonitorType>,
2222
id?: string,
2323
) =>
2424
({

clients/admin-ui/src/features/data-discovery-and-detection/action-center/MonitorList.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ import { useGetAggregateMonitorResultsQuery } from "~/features/data-discovery-an
1111
import { EmptyMonitorsResult } from "~/features/data-discovery-and-detection/action-center/EmptyMonitorsResult";
1212
import useSearchForm from "~/features/data-discovery-and-detection/action-center/hooks/useSearchForm";
1313
import { MonitorResult } from "~/features/data-discovery-and-detection/action-center/MonitorResult";
14-
import { MONITOR_TYPES } from "~/features/data-discovery-and-detection/action-center/utils/getMonitorType";
1514
import { useGetUserMonitorsQuery } from "~/features/user-management";
15+
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
1616

1717
import MonitorListSearchForm from "./forms/MonitorListSearchForm";
1818
import {
1919
MonitorSearchForm,
2020
MonitorSearchFormQuerySchema,
2121
SearchFormQueryState,
2222
} from "./MonitorList.const";
23+
import MonitorStats from "./MonitorStats";
2324

2425
const MonitorList = () => {
2526
const message = useMessage();
@@ -30,9 +31,9 @@ const MonitorList = () => {
3031
useAntPagination();
3132

3233
const availableMonitorTypes = [
33-
...(webMonitorEnabled ? [MONITOR_TYPES.WEBSITE] : []),
34-
MONITOR_TYPES.DATASTORE,
35-
MONITOR_TYPES.INFRASTRUCTURE,
34+
...(webMonitorEnabled ? [APIMonitorType.WEBSITE] : []),
35+
APIMonitorType.DATASTORE,
36+
APIMonitorType.INFRASTRUCTURE,
3637
] as const;
3738

3839
const currentUser = useAppSelector(selectUser);
@@ -48,7 +49,10 @@ const MonitorList = () => {
4849
const defaultStewardFilter =
4950
(userMonitors ?? []).length > 0 ? currentUser?.id : undefined;
5051

51-
const { requestData, ...formProps } = useSearchForm<any, MonitorSearchForm>({
52+
const { requestData, ...formProps } = useSearchForm<
53+
Partial<Parameters<typeof useGetAggregateMonitorResultsQuery>[0]>,
54+
MonitorSearchForm
55+
>({
5256
schema: MonitorSearchFormQuerySchema([...availableMonitorTypes]),
5357
queryState: SearchFormQueryState(
5458
[...availableMonitorTypes],
@@ -64,7 +68,9 @@ const MonitorList = () => {
6468
search: search || undefined,
6569
monitor_type: monitor_type
6670
? [monitor_type]
67-
: availableMonitorTypes /** this should be handled via ant binding ideally. * */,
71+
: [
72+
...availableMonitorTypes,
73+
] /** this should be handled via ant binding ideally. * */,
6874
steward_user_id:
6975
typeof steward_key === "undefined" || !steward_key
7076
? []
@@ -100,6 +106,7 @@ const MonitorList = () => {
100106
}}
101107
availableMonitorTypes={availableMonitorTypes}
102108
/>
109+
<MonitorStats />
103110
<List
104111
loading={isLoading}
105112
dataSource={results}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Button, Flex, Icons, Text } from "fidesui";
2+
import Link from "next/link";
3+
import { useQueryStates } from "nuqs";
4+
5+
import { useFlags } from "~/features/common/features";
6+
import { INTEGRATION_MANAGEMENT_ROUTE } from "~/features/common/nav/routes";
7+
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
8+
9+
import { useGetAggregateStatisticsQuery } from "./action-center.slice";
10+
import { SearchFormQueryState } from "./MonitorList.const";
11+
import { ProgressCard } from "./ProgressCard/ProgressCard";
12+
import {
13+
buildWidgetProps,
14+
MONITOR_TYPE_TO_EMPTY_TEXT,
15+
MONITOR_TYPE_TO_ICON,
16+
MONITOR_TYPE_TO_LABEL,
17+
} from "./ProgressCard/utils";
18+
19+
export interface MonitorProgressWidgetProps {
20+
monitorId?: string;
21+
monitorType: APIMonitorType;
22+
disabled?: boolean;
23+
}
24+
25+
const renderIcon = (icon: Icons.CarbonIconType) => {
26+
const Icon = icon;
27+
return <Icon size={33} />;
28+
};
29+
30+
const MonitorProgressWidget = ({
31+
monitorId,
32+
monitorType,
33+
}: MonitorProgressWidgetProps) => {
34+
const {
35+
flags: { heliosInsights },
36+
} = useFlags();
37+
const [filters] = useQueryStates(
38+
SearchFormQueryState(Object.values(APIMonitorType)),
39+
);
40+
41+
const { data } = useGetAggregateStatisticsQuery(
42+
{
43+
monitor_type: monitorType,
44+
monitor_config_id: monitorId,
45+
steward_user_id: filters.steward_key ? [filters.steward_key] : undefined,
46+
},
47+
{
48+
refetchOnMountOrArgChange: true,
49+
},
50+
);
51+
52+
const totalMonitors = data?.total_monitors ?? 0;
53+
54+
return (
55+
heliosInsights && (
56+
<Flex className="w-full" gap="middle">
57+
{(data && totalMonitors > 0) || !!filters.steward_key ? (
58+
<ProgressCard
59+
{...buildWidgetProps({
60+
monitor_type: monitorType,
61+
total_monitors: totalMonitors,
62+
...data,
63+
})}
64+
compact={!!monitorId}
65+
disabled={
66+
(!!filters.monitor_type &&
67+
monitorType !== filters.monitor_type) ||
68+
(!!filters.steward_key && totalMonitors <= 0)
69+
}
70+
/>
71+
) : (
72+
<div>
73+
<Flex vertical gap="middle" align="center" justify="center">
74+
<span>{MONITOR_TYPE_TO_LABEL[monitorType]}</span>
75+
<Text>{renderIcon(MONITOR_TYPE_TO_ICON[monitorType])}</Text>
76+
<Text type="secondary" className="text-center">
77+
{MONITOR_TYPE_TO_EMPTY_TEXT[monitorType]}
78+
</Text>
79+
<Link href={INTEGRATION_MANAGEMENT_ROUTE}>
80+
<Button type="primary">Create</Button>
81+
</Link>
82+
</Flex>
83+
</div>
84+
)}
85+
</Flex>
86+
)
87+
);
88+
};
89+
90+
export default MonitorProgressWidget;

0 commit comments

Comments
 (0)