Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/7909-integration-property-picker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: Added
description: Added property picker to integration forms for assigning properties to dataset configs
pr: 7909
labels: []
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
Modal,
Select,
Switch,
useMessage,
} from "fidesui";
import _ from "lodash";
import React, { useMemo } from "react";
Expand All @@ -26,6 +27,7 @@ import {
useFormFieldsFromSchema,
} from "~/features/common/form/useFormFieldsFromSchema";
import DatasetSelectOption from "~/features/dataset/DatasetSelectOption";
import { useIntegrationPropertySelect } from "~/features/properties/useIntegrationPropertySelect";
import {
ConnectionConfigurationResponse,
ConnectionSystemTypeMap,
Expand All @@ -49,7 +51,7 @@ type ConnectorParametersFormProps = {
/**
* Parent callback when Save is clicked
*/
onSaveClick: (values: ConnectionConfigFormValues) => void;
onSaveClick: (values: ConnectionConfigFormValues) => Promise<void>;
/**
* Parent callback when Test Connection is clicked
*/
Expand Down Expand Up @@ -97,6 +99,19 @@ export const ConnectorParametersForm = ({
useLazyGetDatastoreConnectionStatusQuery();
const [patchConnection] = usePatchDatastoreConnectionsMutation();
const { plus: isPlusEnabled } = useFeatures();
const messageApi = useMessage();

const isEditingConnection = !!connectionConfig;

const {
propertyOptions,
initialPropertyIds,
savePropertyAssignments,
hasDatasets,
isLoading: isLoadingProperties,
Comment thread
jpople marked this conversation as resolved.
} = useIntegrationPropertySelect(
isEditingConnection ? connectionConfig?.key : undefined,
);

const { getFieldValidation, preprocessValues } =
useFormFieldsFromSchema(secretsSchema);
Expand All @@ -122,6 +137,7 @@ export const ConnectorParametersForm = ({
: {};

values.dataset = initialDatasets;
values.property_ids = initialPropertyIds;

// check if we need we need to pre-process any secrets values
// we currently only need to do this for Fides dataset references
Expand Down Expand Up @@ -159,12 +175,28 @@ export const ConnectorParametersForm = ({
defaultValues,
secretsSchema,
initialDatasets,
Comment thread
jpople marked this conversation as resolved.
initialPropertyIds,
connectionOption,
]);
Comment thread
jpople marked this conversation as resolved.

const handleFinish = (values: ConnectionConfigFormValues) => {
const handleFinish = async (values: ConnectionConfigFormValues) => {
const processedValues = preprocessValues(values);
onSaveClick(processedValues);
await onSaveClick(processedValues);

// Save property assignments if editing
if (
isEditingConnection &&
values.property_ids !== undefined &&
hasDatasets
) {
try {
await savePropertyAssignments(values.property_ids);
} catch {
messageApi.error(
"Integration saved but failed to update properties. Please try again.",
);
}
}
};

const handleAuthorizeConnectionClick = async () => {
Expand Down Expand Up @@ -334,6 +366,22 @@ export const ConnectorParametersForm = ({
/>
</Form.Item>
)}
{isPlusEnabled && isEditingConnection && hasDatasets && (
<Form.Item
name="property_ids"
label="Properties"
tooltip="Assign properties to this integration's datasets to scope privacy request processing"
>
<Select
aria-label="Properties"
mode="multiple"
options={propertyOptions}
loading={isLoadingProperties}
allowClear
placeholder="Select properties..."
/>
</Form.Item>
)}
<Flex justify="space-between">
<Flex gap="small">
{!connectionOption.authorization_required || authorized ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isEmpty, isEqual, isUndefined, mapValues, omitBy } from "lodash";
import { useRouter } from "next/router";
import { useCallback, useEffect, useMemo, useState } from "react";

import { useFeatures } from "~/features/common/features";
import { FormFieldFromSchema } from "~/features/common/form/FormFieldFromSchema";
import { useFormFieldsFromSchema } from "~/features/common/form/useFormFieldsFromSchema";
import { getErrorMessage } from "~/features/common/helpers";
Expand All @@ -28,6 +29,7 @@ import {
import { useDatasetConfigField } from "~/features/datastore-connections/system_portal_config/forms/fields/DatasetConfigField/useDatasetConfigField";
import { formatKey } from "~/features/datastore-connections/system_portal_config/helpers";
import { useSetSystemLinksMutation } from "~/features/integrations/system-links.slice";
import { useIntegrationPropertySelect } from "~/features/properties/useIntegrationPropertySelect";
import {
useGetSystemsQuery,
usePatchSystemConnectionConfigsMutation,
Expand All @@ -54,8 +56,12 @@ type FormValues = {
system_fides_key?: string;
secrets?: ConnectionSecrets;
dataset?: string[];
property_ids?: string[];
};

const PROPERTY_UPDATE_FAILED_MSG =
"Integration saved but failed to update properties. Please try again";

export const ConfigureIntegrationForm = ({
connection,
connectionOption,
Expand Down Expand Up @@ -91,6 +97,18 @@ export const ConfigureIntegrationForm = ({

const [setSystemLinks] = useSetSystemLinksMutation();

const { plus: hasPlus } = useFeatures();

const isEditing = !!connection;

const {
propertyOptions,
initialPropertyIds,
savePropertyAssignments,
hasDatasets,
isLoading: isLoadingProperties,
Comment thread
jpople marked this conversation as resolved.
} = useIntegrationPropertySelect(connection?.key);

const hasSecrets =
connectionOption.identifier !== ConnectionType.MANUAL_TASK &&
connectionOption.identifier !== ConnectionType.JIRA_TICKET;
Expand Down Expand Up @@ -172,15 +190,22 @@ export const ConfigureIntegrationForm = ({
}),
}),
dataset: initialDatasets,
property_ids: initialPropertyIds,
}),
[connection, initialSystemFidesKey, hasSecrets, secrets, initialDatasets],
[
connection,
initialSystemFidesKey,
hasSecrets,
secrets,
initialDatasets,
initialPropertyIds,
],
);

const [form] = Form.useForm<FormValues>();

const messageApi = useMessage();

const isEditing = !!connection;
const isSaas = connectionOption.type === SystemType.SAAS;

// Exclude secrets fields that haven't changed
Expand All @@ -196,6 +221,14 @@ export const ConfigureIntegrationForm = ({
isUndefined,
);

const handlePropertySave = async (propertyIds: string[]) => {
try {
await savePropertyAssignments(propertyIds);
} catch {
messageApi.error(PROPERTY_UPDATE_FAILED_MSG);
}
};

const handleSubmit = async (values: FormValues) => {
const processedValues = preprocessValues(values);

Expand Down Expand Up @@ -270,6 +303,11 @@ export const ConfigureIntegrationForm = ({
}
}

// Save property assignments if editing
if (isEditing && values.property_ids !== undefined && hasDatasets) {
await handlePropertySave(values.property_ids);
}

messageApi.success(
`Integration ${isEditing ? "updated" : "created"} successfully`,
);
Expand Down Expand Up @@ -317,6 +355,15 @@ export const ConfigureIntegrationForm = ({
}
}

// Save property assignments if editing
Comment thread
jpople marked this conversation as resolved.
if (isEditing && values.property_ids) {
try {
await savePropertyAssignments(values.property_ids);
} catch {
messageApi.error(PROPERTY_UPDATE_FAILED_MSG);
}
}

messageApi.success(
`Integration secret ${isEditing ? "updated" : "created"} successfully`,
);
Expand Down Expand Up @@ -464,6 +511,23 @@ export const ConfigureIntegrationForm = ({
</Form.Item>
)}
{hasSecrets && secrets && generateFields(secrets)}
{isEditing && hasPlus && hasDatasets && (
<Form.Item
name="property_ids"
label="Properties"
tooltip="Assign properties to this integration's datasets to scope privacy request processing"
className="w-full"
>
<Select
aria-label="Properties"
mode="multiple"
options={propertyOptions}
loading={isLoadingProperties}
allowClear
placeholder="Select properties..."
/>
</Form.Item>
)}
{connectionOption.identifier === ConnectionType.DATAHUB && (
<Form.Item
name="dataset"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { baseApi } from "~/features/common/api.slice";
import type {
BulkDatasetPropertyResponse,
BulkPropertyAssignment,
BulkPropertyRemoval,
DatasetPropertyIdsResponse,
} from "~/types/api";

export const datasetPropertiesApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
getPropertyIdsForDataset: builder.query<DatasetPropertyIdsResponse, string>(
{
query: (fidesKey) => ({
url: `plus/dataset-properties`,
params: { fides_key: fidesKey },
}),
providesTags: ["Property"],
},
),
bulkAssignProperties: builder.mutation<
BulkDatasetPropertyResponse,
BulkPropertyAssignment
>({
query: (body) => ({
url: `plus/dataset-properties/bulk-assign`,
method: "POST",
body,
}),
invalidatesTags: ["Property"],
}),
bulkRemoveProperties: builder.mutation<
BulkDatasetPropertyResponse,
BulkPropertyRemoval
>({
query: (body) => ({
url: `plus/dataset-properties/bulk-remove`,
method: "POST",
body,
}),
invalidatesTags: ["Property"],
}),
}),
});

export const {
useGetPropertyIdsForDatasetQuery,
useBulkAssignPropertiesMutation,
useBulkRemovePropertiesMutation,
} = datasetPropertiesApi;
Loading
Loading