Validate unique dropdown options

pull/256/head
Candid Dauth 2024-03-28 12:50:45 +01:00
rodzic e2b0f11c92
commit 4941d77e98
2 zmienionych plików z 75 dodań i 3 usunięć

Wyświetl plik

@ -239,4 +239,54 @@ test("Update type with duplicate fields", async () => {
});
}).rejects.toThrowError("Field names must be unique.");
});
});
test("Create type with duplicate dropdown values", async () => {
const client = await openClient();
await createTemporaryPad(client, { createDefaultTypes: false }, async () => {
await expect(async () => {
await client.addType({
name: "Test type",
type: "marker",
fields: [
{
name: "Dropdown",
type: "dropdown",
options: [
{ value: "Value 1" },
{ value: "Value 1" }
]
}
]
});
}).rejects.toThrowError("Dropdown option values must be unique.");
});
});
test("Update type with duplicate dropdown values", async () => {
const client = await openClient();
await createTemporaryPad(client, { createDefaultTypes: false }, async () => {
const type = await client.addType({
name: "Test type",
type: "marker"
});
await expect(async () => {
await client.editType({
id: type.id,
fields: [
{
name: "Dropdown",
type: "dropdown",
options: [
{ value: "Value 1" },
{ value: "Value 1" }
]
}
]
});
}).rejects.toThrowError("Dropdown option values must be unique.");
});
});

Wyświetl plik

@ -22,6 +22,28 @@ export const fieldOptionValidator = cruValidator({
export type FieldOption<Mode extends CRU = CRU.READ> = CRUType<Mode, typeof fieldOptionValidator>;
export type FieldOptionUpdate = FieldOption<CRU.UPDATE>;
const noDuplicateOptionValues = (options: Array<FieldOption<CRU>>, ctx: z.RefinementCtx) => {
const values: Record<string, number> = {};
for (const option of options) {
values[option.value] = (values[option.value] ?? 0) + 1;
}
for (let i = 0; i < options.length; i++) {
if (values[options[i].value] > 1) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Dropdown option values must be unique.",
path: [i, "value"]
});
}
}
};
export const fieldOptionsValidator = {
read: z.array(fieldOptionValidator.read).superRefine(noDuplicateOptionValues),
create: z.array(fieldOptionValidator.create).superRefine(noDuplicateOptionValues),
update: z.array(fieldOptionValidator.update).superRefine(noDuplicateOptionValues)
};
export const fieldValidator = cruValidator({
name: z.string().trim().min(1),
type: fieldTypeValidator,
@ -34,9 +56,9 @@ export const fieldValidator = cruValidator({
controlStroke: z.boolean().optional(),
options: {
read: z.array(fieldOptionValidator.read).optional(),
create: z.array(fieldOptionValidator.create).optional(),
update: z.array(fieldOptionValidator.update).optional()
read: fieldOptionsValidator.read.optional(),
create: fieldOptionsValidator.create.optional(),
update: fieldOptionsValidator.update.optional()
},
oldName: onlyUpdate(z.string().optional())