Skip to content

Commit 495a3ea

Browse files
authored
Implement adding/editing data uses on infrastructure monitor results (#7210)
1 parent 7a7a219 commit 495a3ea

File tree

8 files changed

+93
-117
lines changed

8 files changed

+93
-117
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type: Added # One of: Added, Changed, Developer Experience, Deprecated, Docs, Fixed, Removed, Security
2+
description: Allow editing data uses on infrastructure monitor results
3+
pr: 7210 # PR number
4+
labels: [] # Optional: ["high-risk", "db-migration"]

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,22 @@ import {
99
import useTaxonomies from "~/features/common/hooks/useTaxonomies";
1010

1111
const InfrastructureClassificationSelect = ({
12-
onSelectDataCategory,
12+
onSelectDataUse,
1313
urn,
1414
...props
1515
}: {
16-
onSelectDataCategory: (value: string) => void;
16+
onSelectDataUse: (value: string) => void;
1717
urn?: string;
1818
} & TaxonomySelectProps) => {
1919
const { getDataUseDisplayNameProps, getDataUses } = useTaxonomies();
2020
const dataUses = getDataUses().filter((use) => use.active);
2121
const [open, setOpen] = useState(false);
2222

23-
const options: TaxonomySelectOption[] = dataUses.map((dataCategory) => {
24-
const { name, primaryName } = getDataUseDisplayNameProps(
25-
dataCategory.fides_key,
26-
);
23+
const options: TaxonomySelectOption[] = dataUses.map((dataUse) => {
24+
const { name, primaryName } = getDataUseDisplayNameProps(dataUse.fides_key);
2725

2826
return {
29-
value: dataCategory.fides_key,
27+
value: dataUse.fides_key,
3028
label: (
3129
<div>
3230
<strong>{primaryName || name}</strong>
@@ -35,15 +33,15 @@ const InfrastructureClassificationSelect = ({
3533
),
3634
name,
3735
primaryName,
38-
description: dataCategory.description || "",
36+
description: dataUse.description || "",
3937
};
4038
});
4139
return (
4240
<TaxonomySelect
4341
options={options}
4442
prefix={
4543
<Button
46-
aria-label="Add Data Category"
44+
aria-label="Add data use"
4745
type="text"
4846
size="small"
4947
icon={<Icons.Add />}
@@ -66,7 +64,7 @@ const InfrastructureClassificationSelect = ({
6664
open={open}
6765
onOpenChange={(visible) => setOpen(visible)}
6866
onSelect={(value) => {
69-
onSelectDataCategory(value);
67+
onSelectDataUse(value);
7068
setOpen(false);
7169
}}
7270
data-classification-select={urn}

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

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { useMemo } from "react";
1414

1515
import { getBrandIconUrl, getDomain } from "~/features/common/utils";
16-
import { IdentityProviderApplicationMetadata } from "~/types/api/models/IdentityProviderApplicationMetadata";
16+
import { StagedResourceAPIResponse } from "~/types/api";
1717

1818
import { ActionCenterTabHash } from "../hooks/useActionCenterTabs";
1919
import InfrastructureClassificationSelect from "./InfrastructureClassificationSelect";
@@ -53,29 +53,17 @@ const tagRender: TagRender = (props) => {
5353
};
5454

5555
interface InfrastructureSystemListItemProps {
56-
item: {
57-
id?: string | null;
58-
urn?: string;
59-
name?: string | null;
60-
system_key?: string | null;
61-
vendor_id?: string | null;
62-
metadata?: IdentityProviderApplicationMetadata | null;
63-
diff_status?: string | null;
64-
data_uses?: string[];
65-
description?: string | null;
66-
preferred_data_categories?: string[] | null;
67-
classifications?: Array<{ label: string }> | null;
68-
};
56+
item: StagedResourceAPIResponse;
6957
selected?: boolean;
7058
onSelect?: (key: string, selected: boolean) => void;
7159
onNavigate?: (url: string) => void;
72-
rowClickUrl?: (item: InfrastructureSystemListItemProps["item"]) => string;
60+
rowClickUrl?: (item: StagedResourceAPIResponse) => string;
7361
monitorId: string;
7462
activeTab?: ActionCenterTabHash | null;
7563
allowIgnore?: boolean;
76-
onSetDataCategories?: (urn: string, dataCategories: string[]) => void;
77-
onSelectDataCategory?: (value: string) => void;
78-
dataCategoriesDisabled?: boolean;
64+
onSetDataUses?: (urn: string, dataUses: string[]) => void;
65+
onSelectDataUse?: (value: string) => void;
66+
dataUsesDisabled?: boolean;
7967
onPromoteSuccess?: () => void;
8068
}
8169

@@ -88,12 +76,12 @@ export const InfrastructureSystemListItem = ({
8876
monitorId,
8977
activeTab,
9078
allowIgnore,
91-
onSetDataCategories,
92-
onSelectDataCategory,
93-
dataCategoriesDisabled,
79+
onSetDataUses,
80+
onSelectDataUse,
81+
dataUsesDisabled,
9482
onPromoteSuccess,
9583
}: InfrastructureSystemListItemProps) => {
96-
const itemKey = item.urn ?? item.id ?? "";
84+
const itemKey = item.urn;
9785
const url = rowClickUrl?.(item);
9886
const { metadata } = item;
9987
const systemName = item.name ?? "Uncategorized";
@@ -135,14 +123,14 @@ export const InfrastructureSystemListItem = ({
135123
}
136124
};
137125

138-
// Handle data category selection
139-
const handleSelectDataCategory = (value: string) => {
140-
if (onSelectDataCategory) {
141-
onSelectDataCategory(value);
142-
} else if (onSetDataCategories && itemKey) {
143-
const currentCategories = item.preferred_data_categories ?? [];
144-
if (!currentCategories.includes(value)) {
145-
onSetDataCategories(itemKey, [...currentCategories, value]);
126+
// Handle data use selection
127+
const handleSelectDataUse = (value: string) => {
128+
if (onSelectDataUse) {
129+
onSelectDataUse(value);
130+
} else if (onSetDataUses && itemKey) {
131+
const currentDataUses = item.preferred_data_uses ?? [];
132+
if (!currentDataUses.includes(value)) {
133+
onSetDataUses(itemKey, [...currentDataUses, value]);
146134
}
147135
}
148136
};
@@ -190,31 +178,33 @@ export const InfrastructureSystemListItem = ({
190178
description={
191179
<InfrastructureClassificationSelect
192180
mode="multiple"
193-
value={item.preferred_data_categories ?? []}
181+
value={item.preferred_data_uses ?? []}
194182
urn={itemKey}
195183
tagRender={(props) => {
196-
const isFromClassifier = !!item.classifications?.find(
197-
(classification) => classification.label === props.value,
184+
// Show sparkle icon if the data use was auto-detected (in data_uses)
185+
// and not manually assigned (not in user_assigned_data_uses)
186+
const isAutoDetectedFromCompass = item.data_uses?.includes(
187+
props.value as string,
198188
);
199189

200190
const handleClose = () => {
201-
if (onSetDataCategories && itemKey) {
202-
const newDataCategories =
203-
item.preferred_data_categories?.filter(
204-
(category) => category !== props.value,
191+
if (onSetDataUses && itemKey) {
192+
const newDataUses =
193+
item.preferred_data_uses?.filter(
194+
(dataUse) => dataUse !== props.value,
205195
) ?? [];
206-
onSetDataCategories(itemKey, newDataCategories);
196+
onSetDataUses(itemKey, newDataUses);
207197
}
208198
};
209199

210200
return tagRender({
211201
...props,
212-
isFromClassifier,
202+
isFromClassifier: isAutoDetectedFromCompass,
213203
onClose: handleClose,
214204
});
215205
}}
216-
onSelectDataCategory={handleSelectDataCategory}
217-
disabled={dataCategoriesDisabled}
206+
onSelectDataUse={handleSelectDataUse}
207+
disabled={dataUsesDisabled}
218208
/>
219209
}
220210
/>

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

Lines changed: 13 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ import {
66
UNCATEGORIZED_SEGMENT,
77
} from "~/features/common/nav/routes";
88
import { useAntPagination } from "~/features/common/pagination/useAntPagination";
9-
import {
10-
StagedResourceAPIResponse,
11-
SystemStagedResourcesAggregateRecord,
12-
} from "~/types/api";
9+
import { StagedResourceAPIResponse } from "~/types/api";
1310
import { DiffStatus } from "~/types/api/models/DiffStatus";
1411

1512
import { useGetIdentityProviderMonitorResultsQuery } from "../../discovery-detection.slice";
@@ -29,12 +26,6 @@ interface UseDiscoveredInfrastructureSystemsTableConfig {
2926
vendorFilters?: string[] | null;
3027
}
3128

32-
// Extended type to include diff_status for list items
33-
type InfrastructureSystemListItem = SystemStagedResourcesAggregateRecord & {
34-
diff_status?: string | null;
35-
urn?: string;
36-
};
37-
3829
export const useDiscoveredInfrastructureSystemsTable = ({
3930
monitorId,
4031
statusFilters,
@@ -139,40 +130,13 @@ export const useDiscoveredInfrastructureSystemsTable = ({
139130
refetch: refetchOktaData,
140131
} = oktaDataQuery;
141132

142-
// Transform API data to table format
143-
// Vendor filters are now applied server-side via the vendor_id query parameter
144-
const transformedData = useMemo((): {
145-
items: InfrastructureSystemListItem[];
146-
total: number;
147-
} => {
148-
if (!oktaData?.items) {
149-
return { items: [], total: 0 };
150-
}
151-
152-
const items: InfrastructureSystemListItem[] = oktaData.items.map(
153-
(item: StagedResourceAPIResponse): InfrastructureSystemListItem => {
154-
return {
155-
id: item.urn,
156-
urn: item.urn,
157-
name: item.name ?? null,
158-
system_key: item.system_key ?? null,
159-
data_uses: item.data_uses ?? [],
160-
vendor_id: item.vendor_id ?? null,
161-
total_updates: 1,
162-
locations: item.locations ?? [],
163-
domains: item.domain ? [item.domain] : [],
164-
consent_status: null,
165-
metadata: item.metadata ?? null,
166-
diff_status: item.diff_status ?? null,
167-
};
168-
},
169-
);
170-
171-
return {
172-
items,
173-
total: oktaData.total ?? 0,
174-
};
175-
}, [oktaData]);
133+
const data = useMemo(
134+
() => ({
135+
items: oktaData?.items ?? [],
136+
total: oktaData?.total ?? 0,
137+
}),
138+
[oktaData],
139+
);
176140

177141
const handleTabChange = useCallback(
178142
async (tab: string | ActionCenterTabHash) => {
@@ -185,8 +149,8 @@ export const useDiscoveredInfrastructureSystemsTable = ({
185149
);
186150

187151
const rowClickUrl = useCallback(
188-
(record: InfrastructureSystemListItem) => {
189-
const recordId = record.urn ?? record.id ?? UNCATEGORIZED_SEGMENT;
152+
(record: StagedResourceAPIResponse) => {
153+
const recordId = record.urn ?? UNCATEGORIZED_SEGMENT;
190154
const activeTabHash = activeTab ? `#${activeTab}` : "";
191155
return `${ACTION_CENTER_ROUTE}/${MONITOR_TYPES.INFRASTRUCTURE}/${monitorId}/${recordId}${activeTabHash}`;
192156
},
@@ -195,7 +159,7 @@ export const useDiscoveredInfrastructureSystemsTable = ({
195159

196160
return {
197161
// Data
198-
data: transformedData,
162+
data,
199163
isLoading: oktaIsLoading,
200164
isFetching: oktaIsFetching,
201165
refetch: refetchOktaData,
@@ -218,12 +182,8 @@ export const useDiscoveredInfrastructureSystemsTable = ({
218182

219183
// Selection helpers
220184
getRecordKey: useCallback(
221-
(record: InfrastructureSystemListItem) =>
222-
record.urn ??
223-
record.id ??
224-
record.vendor_id ??
225-
record.name ??
226-
UNCATEGORIZED_SEGMENT,
185+
(record: StagedResourceAPIResponse) =>
186+
record.urn ?? record.vendor_id ?? record.name ?? UNCATEGORIZED_SEGMENT,
227187
[],
228188
),
229189
};

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useCallback } from "react";
33

44
import { getErrorMessage, isErrorResult } from "~/features/common/helpers";
55
import { errorToastParams, successToastParams } from "~/features/common/toast";
6-
import { SystemStagedResourcesAggregateRecord } from "~/types/api";
6+
import { StagedResourceAPIResponse } from "~/types/api";
77

88
import {
99
useBulkMuteIdentityProviderMonitorResultsMutation,
@@ -12,13 +12,9 @@ import {
1212
} from "../../discovery-detection.slice";
1313
import { InfrastructureSystemBulkActionType } from "../constants";
1414

15-
type InfrastructureSystemWithUrn = SystemStagedResourcesAggregateRecord & {
16-
urn?: string | null;
17-
};
18-
1915
interface UseInfrastructureSystemsBulkActionsConfig {
2016
monitorId: string;
21-
getRecordKey: (item: SystemStagedResourcesAggregateRecord) => string;
17+
getRecordKey: (item: StagedResourceAPIResponse) => string;
2218
onSuccess?: () => void;
2319
}
2420

@@ -49,12 +45,10 @@ export const useInfrastructureSystemsBulkActions = ({
4945
const handleBulkAction = useCallback(
5046
async (
5147
action: InfrastructureSystemBulkActionType,
52-
selectedItems: InfrastructureSystemWithUrn[],
48+
selectedItems: StagedResourceAPIResponse[],
5349
) => {
5450
// Extract URNs from selected items
55-
const urns = selectedItems
56-
.map((item) => item.urn)
57-
.filter((urn): urn is string => !!urn);
51+
const urns = selectedItems.map((item) => item.urn);
5852

5953
if (urns.length === 0) {
6054
toast(

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { useCallback, useMemo, useState } from "react";
22

3-
import { SystemStagedResourcesAggregateRecord } from "~/types/api";
3+
import { StagedResourceAPIResponse } from "~/types/api";
44

55
interface UseInfrastructureSystemsSelectionConfig<
6-
T extends SystemStagedResourcesAggregateRecord,
6+
T extends StagedResourceAPIResponse,
77
> {
88
items: T[] | undefined;
99
getRecordKey: (item: T) => string;
1010
}
1111

1212
export const useInfrastructureSystemsSelection = <
13-
T extends SystemStagedResourcesAggregateRecord,
13+
T extends StagedResourceAPIResponse,
1414
>({
1515
items,
1616
getRecordKey,

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { useCallback, useMemo } from "react";
1616

1717
import { DebouncedSearchInput } from "~/features/common/DebouncedSearchInput";
18+
import { useUpdateInfrastructureSystemDataUsesMutation } from "~/features/data-discovery-and-detection/discovery-detection.slice";
1819

1920
import { useGetMonitorConfigQuery } from "../action-center.slice";
2021
import { InfrastructureSystemListItem } from "../components/InfrastructureSystemListItem";
@@ -64,6 +65,18 @@ export const DiscoveredInfrastructureSystemsTable = ({
6465
monitor_config_id: monitorId,
6566
});
6667

68+
const [updateInfrastructureSystemDataUses] =
69+
useUpdateInfrastructureSystemDataUsesMutation();
70+
71+
const handleSetDataUses = async (urn: string, dataUses: string[]) => {
72+
await updateInfrastructureSystemDataUses({
73+
monitorId,
74+
urn,
75+
dataUses,
76+
});
77+
refetch();
78+
};
79+
6780
const {
6881
selectedItems,
6982
hasSelectedRows,
@@ -212,6 +225,7 @@ export const DiscoveredInfrastructureSystemsTable = ({
212225
activeTab={activeTab as ActionCenterTabHash | null}
213226
allowIgnore={allowIgnore}
214227
onPromoteSuccess={refetch}
228+
onSetDataUses={handleSetDataUses}
215229
/>
216230
)}
217231
/>

0 commit comments

Comments
 (0)