Skip to content

Commit

Permalink
Updating dataset test components to use Redux
Browse files Browse the repository at this point in the history
  • Loading branch information
galvana committed Dec 2, 2024
1 parent fd7c444 commit f85139c
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 238 deletions.
2 changes: 2 additions & 0 deletions clients/admin-ui/src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { propertySlice } from "~/features/properties";
import { systemSlice } from "~/features/system";
import { dictSuggestionsSlice } from "~/features/system/dictionary-form/dict-suggestion.slice";
import { taxonomySlice } from "~/features/taxonomy";
import { datasetTestSlice } from "~/features/test-datasets";
import { userManagementSlice } from "~/features/user-management";

/**
Expand Down Expand Up @@ -79,6 +80,7 @@ const reducer = {
[dataSubjectsSlice.name]: dataSubjectsSlice.reducer,
[dataUseSlice.name]: dataUseSlice.reducer,
[datasetSlice.name]: datasetSlice.reducer,
[datasetTestSlice.name]: datasetTestSlice.reducer,
[datastoreConnectionSlice.name]: datastoreConnectionSlice.reducer,
[discoveryDetectionSlice.name]: discoveryDetectionSlice.reducer,
[featuresSlice.name]: featuresSlice.reducer,
Expand Down
142 changes: 60 additions & 82 deletions clients/admin-ui/src/features/test-datasets/DatasetEditorSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import yaml from "js-yaml";
import { useEffect, useMemo, useState } from "react";

import { useAppDispatch, useAppSelector } from "~/app/hooks";
import ClipboardButton from "~/features/common/ClipboardButton";
import { getErrorMessage, isErrorResult } from "~/features/common/helpers";
import { errorToastParams, successToastParams } from "~/features/common/toast";
Expand All @@ -25,23 +26,20 @@ import {
} from "~/features/datastore-connections";
import { Dataset, DatasetConfigSchema } from "~/types/api";

import { selectCurrentDataset, setCurrentDataset } from "./dataset-test.slice";
import { removeNulls } from "./helpers";

interface EditorSectionProps {
connectionKey: string;
onDatasetChange?: (dataset: DatasetConfigSchema | null) => void;
onSaveOrRefresh?: () => void;
}

const EditorSection = ({
connectionKey,
onDatasetChange,
onSaveOrRefresh,
}: EditorSectionProps) => {
const EditorSection = ({ connectionKey }: EditorSectionProps) => {
const toast = useToast();
const dispatch = useAppDispatch();
const [updateDataset] = useUpdateDatasetMutation();
const [state, setState] = useState({
selectedDataset: null as DatasetConfigSchema | null,
editorContent: "",
});

const [editorContent, setEditorContent] = useState<string>("");
const currentDataset = useAppSelector(selectCurrentDataset);

const {
data: datasetConfigs,
Expand All @@ -51,19 +49,16 @@ const EditorSection = ({
skip: !connectionKey,
});

const {
data: reachability,
isLoading: checkingReachability,
refetch: refetchReachability,
} = useGetDatasetReachabilityQuery(
{
connectionKey,
datasetKey: state.selectedDataset?.fides_key || "",
},
{
skip: !connectionKey || !state.selectedDataset?.fides_key,
},
);
const { data: reachability, refetch: refetchReachability } =
useGetDatasetReachabilityQuery(
{
connectionKey,
datasetKey: currentDataset?.fides_key || "",
},
{
skip: !connectionKey || !currentDataset?.fides_key,
},
);

const datasetOptions = useMemo(
() =>
Expand All @@ -75,70 +70,60 @@ const EditorSection = ({
);

useEffect(() => {
if (datasetConfigs?.items[0] && !state.selectedDataset) {
const initialDataset = datasetConfigs.items[0];
setState((prev) => ({ ...prev, selectedDataset: initialDataset }));
onDatasetChange?.(initialDataset);
}
}, [datasetConfigs, state.selectedDataset, onDatasetChange]);

const removeNulls = (obj: any): any => {
if (Array.isArray(obj)) {
return obj
.map((item) => removeNulls(item))
.filter((item) => item !== null);
}
if (obj && typeof obj === "object") {
return Object.fromEntries(
Object.entries(obj)
.map(([key, value]) => [key, removeNulls(value)])
.filter(([, value]) => value !== null),
);
if (datasetConfigs?.items.length) {
if (
!currentDataset ||
!datasetConfigs.items.find(
(item) => item.fides_key === currentDataset.fides_key,
)
) {
const initialDataset = datasetConfigs.items[0];
dispatch(setCurrentDataset(initialDataset));
}
}
return obj;
};
}, [datasetConfigs, currentDataset, dispatch]);

useEffect(() => {
if (state.selectedDataset?.ctl_dataset) {
setState((prev) => ({
...prev,
editorContent: yaml.dump(
removeNulls(state.selectedDataset?.ctl_dataset),
),
}));
if (currentDataset?.ctl_dataset) {
setEditorContent(yaml.dump(removeNulls(currentDataset?.ctl_dataset)));
}
}, [state.selectedDataset]);
}, [currentDataset]);

useEffect(() => {
if (connectionKey && state.selectedDataset?.fides_key) {
if (connectionKey && currentDataset?.fides_key) {
refetchReachability();
}
}, [connectionKey, state.selectedDataset?.fides_key, refetchReachability]);
}, [connectionKey, currentDataset, refetchReachability]);

const handleDatasetChange = (value: string) => {
const handleDatasetChange = async (value: string) => {
const selectedConfig = datasetConfigs?.items.find(
(item) => item.fides_key === value,
);
if (selectedConfig) {
setState((prev) => ({ ...prev, selectedDataset: selectedConfig }));
onDatasetChange?.(selectedConfig);
dispatch(setCurrentDataset(selectedConfig));
}
};

const handleSave = async () => {
try {
const datasetValues = yaml.load(state.editorContent) as Partial<Dataset>;
const updatedDataset = {
...state.selectedDataset!.ctl_dataset,
...datasetValues,
};
const result = await updateDataset(updatedDataset);
if (isErrorResult(result)) {
throw new Error(getErrorMessage(result.error));
if (currentDataset) {
const datasetValues = yaml.load(editorContent) as Partial<Dataset>;
const updatedDatasetConfig: DatasetConfigSchema = {
fides_key: currentDataset.fides_key,
ctl_dataset: {
...currentDataset.ctl_dataset,
...datasetValues,
},
};

const result = await updateDataset(updatedDatasetConfig.ctl_dataset);
if (isErrorResult(result)) {
throw new Error(getErrorMessage(result.error));
}
dispatch(setCurrentDataset(updatedDatasetConfig));
toast(successToastParams("Successfully modified dataset"));
await refetchDatasets();
}
await refetchReachability();
onSaveOrRefresh?.();
toast(successToastParams("Successfully modified dataset"));
} catch (error) {
toast(errorToastParams(getErrorMessage(error as FetchBaseQueryError)));
}
Expand All @@ -148,16 +133,11 @@ const EditorSection = ({
try {
const { data } = await refetchDatasets();
const refreshedDataset = data?.items.find(
(item) => item.fides_key === state.selectedDataset?.fides_key,
(item) => item.fides_key === currentDataset?.fides_key,
);
if (refreshedDataset?.ctl_dataset) {
setState((prev) => ({
...prev,
selectedDataset: refreshedDataset,
editorContent: yaml.dump(removeNulls(refreshedDataset.ctl_dataset)),
}));
setEditorContent(yaml.dump(removeNulls(refreshedDataset.ctl_dataset)));
}
onSaveOrRefresh?.();
toast(successToastParams("Successfully refreshed datasets"));
} catch (error) {
toast(errorToastParams(getErrorMessage(error as FetchBaseQueryError)));
Expand All @@ -178,12 +158,12 @@ const EditorSection = ({
<Select
id="format"
data-testid="export-format-select"
value={state.selectedDataset?.fides_key || ""}
value={currentDataset?.fides_key || ""}
options={datasetOptions}
onChange={handleDatasetChange}
className="w-64"
/>
<ClipboardButton copyText={state.editorContent} />
<ClipboardButton copyText={editorContent} />
</HStack>
<HStack spacing={2}>
<Button
Expand Down Expand Up @@ -213,11 +193,9 @@ const EditorSection = ({
>
<Editor
defaultLanguage="yaml"
value={state.editorContent}
value={editorContent}
height="100%"
onChange={(value) =>
setState((prev) => ({ ...prev, editorContent: value || "" }))
}
onChange={(value) => setEditorContent(value || "")}
onMount={() => {}}
options={{
fontFamily: "Menlo",
Expand Down
Loading

0 comments on commit f85139c

Please sign in to comment.