Skip to content

Commit 3dbcee3

Browse files
committed
fix: show form errors and update mapping schema validation
1 parent 16665e2 commit 3dbcee3

File tree

3 files changed

+86
-13
lines changed

3 files changed

+86
-13
lines changed

site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { useFormik } from "formik";
3939
import { Plus, Trash } from "lucide-react";
4040
import { type FC, useId, useState } from "react";
4141
import { docs } from "utils/docs";
42+
import { isUUID } from "utils/uuid";
4243
import * as Yup from "yup";
4344
import { OrganizationPills } from "./OrganizationPills";
4445

@@ -52,9 +53,23 @@ interface IdpSyncPageViewProps {
5253
const validationSchema = Yup.object({
5354
field: Yup.string().trim(),
5455
organization_assign_default: Yup.boolean(),
55-
mapping: Yup.object().shape({
56-
[`${String}`]: Yup.array().of(Yup.string()),
57-
}),
56+
mapping: Yup.object()
57+
.test(
58+
"valid-mapping",
59+
"Invalid organization sync settings mapping structure",
60+
(value) => {
61+
if (!value) return true;
62+
return Object.entries(value).every(
63+
([key, arr]) =>
64+
typeof key === "string" &&
65+
Array.isArray(arr) &&
66+
arr.every((item) => {
67+
return typeof item === "string" && isUUID(item);
68+
}),
69+
);
70+
},
71+
)
72+
.default({}),
5873
});
5974

6075
export const IdpOrgSyncPageView: FC<IdpSyncPageViewProps> = ({
@@ -164,7 +179,11 @@ export const IdpOrgSyncPageView: FC<IdpSyncPageViewProps> = ({
164179
</p>
165180
</div>
166181
</div>
167-
182+
{form.errors && (
183+
<p className="text-content-danger text-sm m-0">
184+
{form?.errors?.field}
185+
</p>
186+
)}
168187
<div className="flex flex-col gap-4">
169188
<div className="flex flex-row pt-8 gap-2 justify-between items-start">
170189
<div className="grid items-center gap-1">
@@ -231,6 +250,11 @@ export const IdpOrgSyncPageView: FC<IdpSyncPageViewProps> = ({
231250
</Button>
232251
</div>
233252
</div>
253+
{form.errors && (
254+
<p className="text-content-danger text-sm m-0">
255+
{Object.values(form?.errors?.mapping || {})}
256+
</p>
257+
)}
234258
<IdpMappingTable isEmpty={organizationMappingCount === 0}>
235259
{form.values.mapping &&
236260
Object.entries(form.values.mapping)

site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { useFormik } from "formik";
2626
import { Plus, Trash } from "lucide-react";
2727
import { type FC, useId, useState } from "react";
2828
import { docs } from "utils/docs";
29+
import { isUUID } from "utils/uuid";
2930
import * as Yup from "yup";
3031
import { ExportPolicyButton } from "./ExportPolicyButton";
3132
import { IdpMappingTable } from "./IdpMappingTable";
@@ -45,9 +46,23 @@ const groupSyncValidationSchema = Yup.object({
4546
field: Yup.string().trim(),
4647
regex_filter: Yup.string().trim(),
4748
auto_create_missing_groups: Yup.boolean(),
48-
mapping: Yup.object().shape({
49-
[`${String}`]: Yup.array().of(Yup.string()),
50-
}),
49+
mapping: Yup.object()
50+
.test(
51+
"valid-mapping",
52+
"Invalid group sync settings mapping structure",
53+
(value) => {
54+
if (!value) return true;
55+
return Object.entries(value).every(
56+
([key, arr]) =>
57+
typeof key === "string" &&
58+
Array.isArray(arr) &&
59+
arr.every((item) => {
60+
return typeof item === "string" && isUUID(item);
61+
}),
62+
);
63+
},
64+
)
65+
.default({}),
5166
});
5267

5368
export const IdpGroupSyncForm = ({
@@ -149,6 +164,11 @@ export const IdpGroupSyncForm = ({
149164
</p>
150165
</div>
151166
</div>
167+
{form.errors && (
168+
<p className="text-content-danger text-sm m-0">
169+
{form?.errors?.field || form?.errors?.regex_filter}
170+
</p>
171+
)}
152172
</div>
153173
<div className="flex flex-row items-center gap-3">
154174
<Spinner size="sm" loading={form.isSubmitting} className="w-9">
@@ -233,7 +253,11 @@ export const IdpGroupSyncForm = ({
233253
</Button>
234254
</div>
235255
</div>
236-
256+
{form.errors && (
257+
<p className="text-content-danger text-sm m-0">
258+
{Object.values(form?.errors?.mapping || {})}
259+
</p>
260+
)}
237261
<div className="flex flex-col">
238262
<IdpMappingTable type="Group" rowCount={groupMappingCount}>
239263
{groupSyncSettings?.mapping &&

site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Spinner } from "components/Spinner/Spinner";
1212
import { useFormik } from "formik";
1313
import { Plus, Trash } from "lucide-react";
1414
import { type FC, useId, useState } from "react";
15+
import { isUUID } from "utils/uuid";
1516
import * as Yup from "yup";
1617
import { ExportPolicyButton } from "./ExportPolicyButton";
1718
import { IdpMappingTable } from "./IdpMappingTable";
@@ -25,13 +26,27 @@ interface IdpRoleSyncFormProps {
2526
onSubmit: (data: RoleSyncSettings) => void;
2627
}
2728

28-
const roleyncValidationSchema = Yup.object({
29+
const roleSyncValidationSchema = Yup.object({
2930
field: Yup.string().trim(),
3031
regex_filter: Yup.string().trim(),
3132
auto_create_missing_groups: Yup.boolean(),
32-
mapping: Yup.object().shape({
33-
[`${String}`]: Yup.array().of(Yup.string()),
34-
}),
33+
mapping: Yup.object()
34+
.test(
35+
"valid-mapping",
36+
"Invalid role sync settings mapping structure",
37+
(value) => {
38+
if (!value) return true;
39+
return Object.entries(value).every(
40+
([key, arr]) =>
41+
typeof key === "string" &&
42+
Array.isArray(arr) &&
43+
arr.every((item) => {
44+
return typeof item === "string";
45+
}),
46+
);
47+
},
48+
)
49+
.default({}),
3550
});
3651

3752
export const IdpRoleSyncForm = ({
@@ -46,7 +61,7 @@ export const IdpRoleSyncForm = ({
4661
field: roleSyncSettings?.field ?? "",
4762
mapping: roleSyncSettings?.mapping ?? {},
4863
},
49-
validationSchema: roleyncValidationSchema,
64+
validationSchema: roleSyncValidationSchema,
5065
onSubmit,
5166
enableReinitialize: Boolean(roleSyncSettings),
5267
});
@@ -113,6 +128,11 @@ export const IdpRoleSyncForm = ({
113128
If empty, role sync is deactivated
114129
</p>
115130
</div>
131+
{form.errors && (
132+
<p className="text-content-danger text-sm m-0">
133+
{form?.errors?.field}
134+
</p>
135+
)}
116136
<div className="flex flex-row gap-2 justify-between items-start">
117137
<div className="grid items-center gap-1">
118138
<Label className="text-sm" htmlFor={`${id}-idp-role-name`}>
@@ -178,6 +198,11 @@ export const IdpRoleSyncForm = ({
178198
</Button>
179199
</div>
180200
</div>
201+
{form.errors && (
202+
<p className="text-content-danger text-sm m-0">
203+
{Object.values(form?.errors?.mapping || {})}
204+
</p>
205+
)}
181206
<IdpMappingTable type="Role" rowCount={roleMappingCount}>
182207
{roleSyncSettings?.mapping &&
183208
Object.entries(roleSyncSettings.mapping)

0 commit comments

Comments
 (0)