Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add max items for scalar arrays #534

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions .changeset/modern-kids-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@premieroctet/next-admin": patch
---

feat: add max items for scalar arrays
5 changes: 5 additions & 0 deletions apps/docs/pages/docs/api/model-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,11 @@ When you define a field, use the field's name as the key and the following objec
description:
"a function that takes the resource value as a parameter, and returns a boolean that shows or hides the field in the edit form",
},
{
name: "maxLength",
type: "Number",
description: "a number that defines the maximum number of items a scalar array can contain."
}
]}
/>

Expand Down
4 changes: 2 additions & 2 deletions apps/example/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ export const options: NextAdminOptions = {
input: <DatePicker />,
},
posts: {
display: "list",
orderField: "order",
display: "table",
},
avatar: {
format: "file",
Expand Down Expand Up @@ -301,6 +300,7 @@ export const options: NextAdminOptions = {
return faker.image.url({ width: 200, height: 200 });
},
},
maxLength: 5,
},
},
display: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ const FileWidget = (props: Props) => {
return [selectedFiles[0]];
}

return [...old, ...Array.from(selectedFiles)];
const newArray = [...old, ...Array.from(selectedFiles)];

if (props.schema?.maxItems) {
return newArray.slice(0, props.schema.maxItems);
}

return newArray;
});
}
};
Expand Down Expand Up @@ -82,7 +88,13 @@ const FileWidget = (props: Props) => {
setFieldDirty(props.name);
setFiles((old) => {
if (acceptsMultipleFiles) {
return [...old, ...Array.from(event.dataTransfer.files)];
const newArray = [...old, ...Array.from(event.dataTransfer.files)];

if (props.schema?.maxItems) {
return newArray.slice(0, props.schema.maxItems);
}

return newArray;
}

return [event.dataTransfer.files[0]];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,19 @@ const ScalarArrayField = ({
};

const onAddNewItem = () => {
setFormDataList((prev) => [
...prev,
{
id: crypto.randomUUID(),
value: "",
},
]);
setFormDataList((prev) => {
if (schema.maxItems && prev.length >= schema.maxItems) {
return prev;
}

return [
...prev,
{
id: crypto.randomUUID(),
value: "",
},
];
});
setFieldDirty(name);
};

Expand All @@ -115,7 +121,10 @@ const ScalarArrayField = ({
<Button
type="button"
className="w-fit"
disabled={disabled}
disabled={
disabled ||
(schema.maxItems ? formDataList.length >= schema.maxItems : false)
}
onClick={onAddNewItem}
>
{t("form.widgets.scalar_array.add")}
Expand Down
3 changes: 3 additions & 0 deletions packages/next-admin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ type OptionFormatterFromRelationshipSearch<
};
}[RelationshipSearch<ModelFromProperty<T, P>>["field"]];

export type ScalarArray = string[] | number[] | boolean[];

export type EditFieldsOptions<T extends ModelName> = {
[P in Field<T>]?: {
/**
Expand Down Expand Up @@ -284,6 +286,7 @@ export type EditFieldsOptions<T extends ModelName> = {
* a function that takes the field value as parameter and returns a boolean to determine if the field is displayed in the form.
*/
visible?: (value: ModelWithoutRelationships<T>) => boolean;
maxLength?: Model<T>[P] extends ScalarArray ? number : never;
} & (P extends keyof ObjectField<T>
? OptionFormatterFromRelationshipSearch<T, P> &
(
Expand Down
21 changes: 20 additions & 1 deletion packages/next-admin/src/utils/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,8 @@ export const transformSchema = <M extends ModelName>(
fillRelationInSchema(resource, options),
fillDescriptionInSchema(resource, edit),
addCustomProperties(resource, edit),
orderSchema(resource, options)
orderSchema(resource, options),
applyArrayMaxLength(resource, edit)
);

export const applyVisiblePropertiesInSchema = <M extends ModelName>(
Expand Down Expand Up @@ -1294,6 +1295,24 @@ export const addCustomProperties =
return schema;
};

export const applyArrayMaxLength =
<M extends ModelName>(resource: M, editOptions: EditOptions<M>) =>
(schema: Schema) => {
const modelName = resource;
const modelSchema = schema.definitions[
modelName
] as SchemaDefinitions[ModelName];
if (!modelSchema) return schema;
Object.entries(modelSchema.properties).forEach(([name]) => {
const propertyName = name as Field<typeof modelName>;
const fieldValue = schema.definitions[modelName].properties[propertyName];
if (fieldValue && editOptions?.fields?.[propertyName]?.maxLength) {
fieldValue.maxItems = editOptions?.fields?.[propertyName]?.maxLength;
}
});
return schema;
};

export const getResourceFromParams = (
params: string[],
resources: Prisma.ModelName[]
Expand Down
Loading