@premieroctet/next-admin
Version:
Next-Admin provides a customizable and turnkey admin dashboard for applications built with Next.js and powered by the Prisma ORM. It aims to simplify the development process by providing a turnkey admin system that can be easily integrated into your proje
896 lines • 34.4 kB
TypeScript
import * as OutlineIcons from "@heroicons/react/24/outline";
import type { NextAdminJSONSchema } from "@premieroctet/next-admin-json-schema";
import type { NextApiRequest } from "next";
import type React from "react";
import type { ChangeEvent, ComponentProps, ReactNode } from "react";
import type { PropertyValidationError } from "./exceptions/ValidationError";
import type { Prisma, PrismaClient } from "./types-prisma";
declare type JSONSchema7Definition = NextAdminJSONSchema & {
relation?: ModelName;
};
type OmitNever<T> = {
[K in keyof T as T[K] extends never ? never : K]: T[K];
};
type ExtendsStringButIsNotString<T> = T extends string ? string extends T ? false : true : false;
/** Type for Model */
export type ModelName = Prisma.ModelName;
export type Payload = Prisma.TypeMap["model"][ModelName]["payload"];
export type ModelPayload<M extends ModelName> = Prisma.TypeMap["model"][M]["payload"];
export type ScalarField<T extends ModelName> = ModelPayload<T>["scalars"];
export type ObjectField<T extends ModelName> = ModelPayload<T>["objects"];
export type NonArrayObjectField<T extends ModelName> = OmitNever<{
[K in keyof ModelPayload<T>["objects"]]: ModelPayload<T>["objects"][K] extends Array<any> ? never : ModelPayload<T>["objects"][K];
}>;
export type ModelFromPayload<P extends Payload, T extends object | number = object> = {
[Property in keyof P["scalars"]]: P["scalars"][Property];
} & {
[Property in keyof P["objects"]]: P["objects"][Property] extends {
scalars: infer S;
} ? T extends object ? S : T : never | P["objects"][Property] extends {
scalars: infer S;
}[] ? T extends object ? S[] : T[] : never | P["objects"][Property] extends {
scalars: infer S;
} | null ? T extends object ? S | null : T | null : never;
};
export type Model<M extends ModelName, T extends object | number = object> = ModelFromPayload<Prisma.TypeMap["model"][M]["payload"], T>;
export type PropertyPayload<M extends ModelName, P extends keyof ObjectField<M>> = Prisma.TypeMap["model"][M]["payload"]["objects"][P] extends Array<infer T> ? T : never | Prisma.TypeMap["model"][M]["payload"]["objects"][P] extends infer T | null ? T : never | Prisma.TypeMap["model"][M]["payload"]["objects"][P];
export type ModelFromProperty<M extends ModelName, P extends keyof ObjectField<M>> = PropertyPayload<M, P> extends Payload ? ModelFromPayload<PropertyPayload<M, P>> : never;
export type ModelWithoutRelationships<M extends ModelName> = Model<M, number>;
export type NoticeField = {
readonly id: string;
title: string;
description?: string;
};
type GreaterThan<A extends number, B extends number, S extends any[] = []> = S["length"] extends A ? false : S["length"] extends B ? true : GreaterThan<A, B, [...S, any]>;
type LessThan<A extends number, B extends number, S extends any[] = []> = S["length"] extends B ? false : S["length"] extends A ? true : LessThan<A, B, [...S, any]>;
type Substract<A extends number, B extends number, I extends any[] = [], O extends any[] = []> = LessThan<A, B> extends true ? never : LessThan<I["length"], A> extends true ? Substract<A, B, [
...I,
any
], LessThan<I["length"], B> extends true ? O : [...O, any]> : O["length"];
type Leaves<T> = T extends object ? {
[K in keyof T]: `${Exclude<K, symbol>}${Leaves<T[K]> extends never ? "" : `.${Leaves<Exclude<T[K], undefined>>}`}`;
}[keyof T] : never;
export type NestableField<P extends Payload, S extends number = 4> = {
[K in keyof P["scalars"]]: true;
} & {
[K in keyof P["objects"]]: P["objects"][K] extends infer T | null ? T extends Payload ? GreaterThan<S, 0> extends true ? NestableField<T, Substract<S, 1>> : never : T extends Array<infer U> ? U extends Payload ? GreaterThan<S, 0> extends true ? NestableField<U, Substract<S, 1>> : never : never : never : never;
};
export type Field<P extends ModelName> = keyof Model<P>;
/** Type for Form */
/** Type for Options */
export type ListFieldsOptions<T extends ModelName> = {
[P in Field<T>]?: {
/**
* a function that takes the field value as a parameter, and that return a JSX node. It also accepts a second argument which is the `NextAdmin` context.
* @param item
* @param context
* @returns
*/
formatter?: (item: P extends keyof ObjectField<T> ? ObjectField<T>[P] extends Array<any> ? number : ModelFromProperty<T, P> : Model<T>[P], context?: NextAdminContext) => ReactNode;
} & (P extends keyof NonArrayObjectField<T> ? {
/**
* The field to use for relationship sorting, defaults to the id field
*/
sortBy?: keyof ModelFromProperty<T, P>;
} : {});
};
export declare enum LogicalOperator {
And = "AND",
Or = "OR",
Not = "NOT"
}
export type Filter<T extends ModelName> = Prisma.TypeMap["model"][T]["operations"]["findMany"]["args"]["where"];
export type FilterWrapper<T extends ModelName> = {
/**
* a string to identify filter, must be unique
*/
name: string;
/**
* a boolean to set filter as default active on list page
*/
active?: boolean;
/**
* a Prisma filter, equivalent to `where` clause in Prisma queries
* @link https://www.prisma.io/docs/orm/reference/prisma-client-reference#filter-conditions-and-operators
*/
value: Filter<T>;
/**
* An id that will be used to give filters with the same group name a radio like behavior
*/
group?: string;
};
type RelationshipSearch<T> = {
[S in keyof T]: {
field: T[S] extends object ? S : never;
};
}[keyof T];
type OptionFormatterFromRelationshipSearch<T extends ModelName, P extends keyof ObjectField<T>> = {
[S in RelationshipSearch<ModelFromProperty<T, P>>["field"]]: {
/**
* only for relation fields, a function that takes the field values as a parameter and returns a string. Useful to display your record in related list.
* @param item
* @returns
*/
relationOptionFormatter?: (item: ModelFromProperty<T, P>[S]) => string;
/**
* model name on which to execute a research. Useful in case the field is related to an explicit many-to-many table
*/
relationshipSearchField?: S;
} | {
/**
* only for relation fields, a function that takes the field values as a parameter and returns a string. Useful to display your record in related list.
* @param item
* @returns
*/
optionFormatter?: (item: ModelFromProperty<T, P>) => string;
};
}[RelationshipSearch<ModelFromProperty<T, P>>["field"]];
export type RelationshipPagination = {
perPage?: number;
};
export type ScalarArray = string[] | number[] | boolean[];
export type EditFieldsOptions<T extends ModelName> = {
[P in Field<T>]?: {
/**
* a function that takes the field value as a parameter, and that returns a boolean.
* @param value
* @returns
*/
validate?: (value: ModelWithoutRelationships<T>[P]) => true | string;
/**
* a string defining an OpenAPI field format, overriding the one set in the generator. An extra `file` format can be used to be able to have a file input.
*/
format?: FormatOptions<ModelWithoutRelationships<T>[P]>;
/**
* an object that can take the following properties.
*/
handler?: Handler<T, P, Model<T>[P]>;
/**
* a React Element that should receive [`CustomInputProps`](#custominputprops). For App Router, this element must be a client component. Don't set any props, they will be passed automatically to the component.
*/
input?: React.ReactElement<CustomInputProps>;
/**
* a helper text that is displayed underneath the input.
*/
helperText?: string;
/**
* a tooltip content to show for the field.
*/
tooltip?: string;
/**
* a boolean to indicate that the field is read only.
*/
disabled?: boolean;
/**
* a true value to force a field to be required in the form, note that if the field is required by the Prisma schema, you cannot set `required` to false
*/
required?: true;
/**
* 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> & ({
/**
* Property to indicate how to display the multi select widget :
* - `list`: displayed as a list of elements that has a link and a delete button
* - `table`: displayed as the table list for a resource. Requires to have display options configured for the related model
* - `select`: displayed as a multi select dropdown
*
* @default "select"
*/
display?: "select";
} | {
display?: "table";
pagination?: RelationshipPagination;
} | {
display?: "list";
orderField?: keyof ModelFromProperty<T, P>;
pagination?: RelationshipPagination;
}) : P extends keyof ScalarField<T> ? ScalarField<T>[P] extends (infer Q)[] ? ExtendsStringButIsNotString<Q> extends true ? {
display?: "list" | "select";
} : {} : {} : {});
};
export type UploadedFile = {
buffer: Buffer;
infos: {
name: string;
type: string | null;
};
};
export type Handler<M extends ModelName, P extends Field<M>, T extends Model<M>[P]> = {
/**
* a function that takes the field value as a parameter and returns a transformed value displayed in the form.
* @param input
* @returns
*/
get?: (input: T) => any;
/**
* an async function that is used only for formats `file` and `data-url`. It takes a buffer as parameter and must return a string. Useful to upload a file to a remote provider.
* @param file - This object contains the file buffer and information.
* @param context - This object contains record information, such as the resource ID.
* @returns result - Promise<string> - the file uri
*/
upload?: (buffer: Buffer, infos: {
name: string;
type: string | null;
}, context: {
/**
* the resource ID if it exists, otherwise undefined
*/
resourceId: string | number | undefined;
}) => Promise<string>;
/**
* an async function that is used to remove a file from a remote provider
*
* @param fileUri string - the remote file uri
* @returns success - Promise<boolean> - true if the deletion succeeded, false otherwise. If false is returned, the file will not be removed from the record.
*/
deleteFile?: (fileUri: string) => Promise<boolean>;
/**
* an optional string displayed in the input field as an error message in case of a failure during the upload handler.
*/
uploadErrorMessage?: string;
/**
* an async function that takes the resource value as parameter and returns a boolean. If false is returned, the deletion will not happen.
* @param input
* @returns boolean
*/
delete?: (input: T) => Promise<boolean> | boolean;
};
export type RichTextFormat = "html" | "json";
export type FormatOptions<T> = T extends string ? "textarea" | "password" | "color" | "email" | "uri" | "data-url" | "date" | "date-time" | "time" | "time-second" | "alt-datetime" | "alt-date" | "file" | `richtext-${RichTextFormat}` | "json" : never | T extends Date ? "date" | "date-time" | "time" : never | T extends number ? "updown" | "range" : never | T extends string[] ? "file" : never;
export type ListExport = {
/**
* a string defining the format of the export. It is mandatory.
*/
format: string;
/**
* a string defining the URL of the export. It is mandatory.
*/
url: string;
};
export type FieldSort<T extends ModelName> = {
/**
* the model's field name on which the sort is applied. It is mandatory.
*/
field: Field<T>;
/**
* the sort direction to apply. It is optional
*/
direction?: Prisma.SortOrder;
};
type VirtualFieldWithType<T extends ModelName> = {
formatter: (context: NextAdminContext<Model<T>>) => string;
} & ({
type?: "link";
url: (context: NextAdminContext<Model<T>>) => string;
} | {
type?: Exclude<ListDataFieldValue["type"], "link">;
});
export type VirtualField<T extends ModelName> = {
key: string;
label: string;
dependsOn?: Field<T>[];
} & (VirtualFieldWithType<T> | {
formatter: (context: NextAdminContext<Model<T>>) => React.ReactElement;
type?: never;
});
export type ListOptions<T extends ModelName> = {
/**
* an url to export the list data as CSV.
*/
exports?: ListExport[] | ListExport;
/**
* an array of fields that are displayed in the list.
* @default all scalar
*/
display?: Array<Field<T> | VirtualField<T>>;
/**
* an array of searchable fields.
* @default all scalar
*/
search?: Leaves<NestableField<Prisma.TypeMap["model"][T]["payload"]>>[];
/**
* an array of fields that are copyable into the clipboard.
* @default none
*/
copy?: Field<T>[];
/**
* an object containing the model fields as keys, and customization values.
*/
fields?: ListFieldsOptions<T>;
/**
* an optional object to determine the default sort to apply on the list.
*/
defaultSort?: FieldSort<T> | FieldSort<T>[];
/**
* An optional field to enable ordering on the list.
* ⚠️ When enabled, it will disable all other types of sorting.
* @restriction Only scalar fields are allowed, and primary keys are not permitted. The field must be a numeric type.
*/
orderField?: keyof ScalarField<T>;
/**
* define a set of Prisma filters that user can choose in list
*/
filters?: Array<FilterWrapper<T> | (() => Promise<FilterWrapper<T>[]>)>;
/**
* define a set of Prisma filters that are always active in list
*/
where?: Filter<T>[];
/**
* an optional number indicating the default amount of items in the list
*/
defaultListSize?: number;
};
export type RelationshipsRawData = Record<string, any>;
export type SubmitResourceResponse = {
error: string;
updated?: undefined;
data?: undefined;
redirect?: undefined;
created?: undefined;
createdId?: undefined;
validation?: undefined;
} | {
error: string;
updated?: undefined;
data?: undefined;
redirect?: undefined;
created?: undefined;
createdId?: undefined;
validation: PropertyValidationError[];
} | {
error?: undefined;
updated: true;
data: any;
redirect: boolean;
created?: undefined;
createdId?: undefined;
validation?: undefined;
relationshipsRawData?: RelationshipsRawData;
} | {
error?: undefined;
updated?: undefined;
data: any;
redirect: boolean;
created: true;
createdId: any;
validation?: undefined;
relationshipsRawData?: RelationshipsRawData;
};
export type EditModelHooks = {
/**
* a function that is called before the form data is sent to the database.
*
* @param data - the form data as a record
* @param mode - the mode of the form, either "create" or "edit"
* @param request - the request object. Note: on App Router, it will not be possible to call `formData` as the handler already calls it once
* @returns the transformed form data record or a Response or NextApiResponse.
* @throws HookError - if the hook fails, the status and message will be sent in the handler's response
*/
beforeDb?: (data: Record<string, string | (UploadedFile | string)[] | null>, mode: "create" | "edit", request: Request | NextApiRequest) => Promise<Record<string, string | (UploadedFile | string)[] | null>>;
/**
* a function that is called after the form submission. It takes the response of the db insertion as a parameter.
* @param data
*/
afterDb?: (data: SubmitResourceResponse, mode: "create" | "edit", request: Request | NextApiRequest) => Promise<SubmitResourceResponse>;
};
export type EditOptions<T extends ModelName> = {
/**
* an array of fields that are displayed in the form. It can also be an object that will be displayed in the form of a notice.
* @default all scalar
*/
display?: Array<Field<T> | NoticeField | (string & {})>;
/**
* an object containing the styles of the form.
*/
styles?: {
/**
* a string defining the classname of the form.
*/
_form?: string;
} & Partial<{
[Key in Field<T>]: string;
} & Record<string, string>>;
/**
* an object containing the model fields as keys, and customization values.
*/
fields?: EditFieldsOptions<T>;
/**
* a message displayed if an error occurs during the form submission, after the form validation and before any call to prisma.
*/
submissionErrorMessage?: string;
/**
* a set of hooks to call before and after the form data insertion into the database.
*/
hooks?: EditModelHooks;
customFields?: CustomFieldsType;
};
type CustomFieldsType = {
[key: string]: {
input?: React.ReactElement<CustomInputProps>;
tooltip?: string;
format?: FormatOptions<any>;
helperText?: string;
required?: boolean;
};
};
export type ActionStyle = "default" | "destructive";
export type MessageData = {
type: "error" | "info" | "success";
message: string;
};
export type ServerActionCustomComponent = React.ReactElement<{
message?: string;
}>;
export type MessageDataWithCustomComponent = MessageData & {
component?: ServerActionCustomComponent;
};
export type MessageContextType = {
showMessage: (message: MessageDataWithCustomComponent) => void;
message: MessageDataWithCustomComponent | null;
hideMessage: () => void;
};
export type BareModelAction<M extends ModelName> = {
title: string;
id: string;
canExecute?: (item: Model<M>) => boolean;
icon?: keyof typeof OutlineIcons;
style?: ActionStyle;
/**
* Max depth of the related records to select
*
* @default 2
*/
depth?: number;
};
export type ServerAction = {
type: "server";
action: (ids: string[] | number[]) => Promise<void | MessageData>;
successMessage?: string;
errorMessage?: string;
/**
* Component shown inside the Message component. If not passed, the message
* string is displayed in a `p` HTML element.
*/
component?: ServerActionCustomComponent;
} & BareModelAction<ModelName>;
export type ClientAction<T extends ModelName> = {
type: "dialog";
component: React.ReactElement<ClientActionDialogContentProps<T>>;
/**
* Class name to apply to the dialog content
*/
className?: string;
} & BareModelAction<T>;
export type ModelAction<T extends ModelName> = ServerAction | ClientAction<T>;
export type UnionModelAction = {
[M in ModelName]: ModelAction<M>;
}[ModelName];
export type OutputModelAction = (Omit<UnionModelAction, "action" | "canExecute" | "component"> & {
allowedIds?: string[] | number[];
})[];
export type ModelIcon = keyof typeof OutlineIcons;
export declare enum Permission {
CREATE = "create",
EDIT = "edit",
DELETE = "delete"
}
export type PermissionType = "create" | "edit" | "delete";
export type ModelMiddleware<T extends ModelName> = {
/**
* a function that is called before the form data is sent to the database.
* @param data - the form data as a record
* @param currentData - the current data in the database
* @returns boolean - if false is returned, the update will not happen.
*/
edit?: (updatedData: Model<T>, currentData: Model<T>) => Promise<boolean> | boolean;
/**
* a function that is called before resource is deleted from the database.
* @param data - the current data in the database
* @returns boolean - if false is returned, the deletion will not happen.
*/
delete?: (data: Model<T>) => Promise<boolean> | boolean;
};
export type ModelOptions<T extends ModelName> = {
[P in T]?: {
/**
* a function that is used to display your record in related list.
* @default "id"
*/
toString?: (item: Model<P>) => string;
/**
* define list options for this model.
*/
list?: ListOptions<P>;
/**
* define edit options for this model.
*/
edit?: EditOptions<P>;
/**
* a string used to display the model name in the sidebar and in the section title.
*/
title?: string;
/**
* an object containing the aliases of the model fields as keys, and the field name.
*/
aliases?: Partial<Record<Field<P>, string>> & {
[key: string]: string;
};
actions?: ModelAction<P>[];
/**
* the outline HeroIcon name displayed in the sidebar and pages title
* @type ModelIcon
* @link https://heroicons.com/outline
*/
icon?: ModelIcon;
permissions?: PermissionType[];
middlewares?: ModelMiddleware<P>;
};
};
export type SidebarGroup = {
/**
* Some optional css classes to improve appearance of group title.
*/
className?: string;
/**
* the name of the group.
*/
title: string;
/**
* the model names to display in the group.
*/
models: ModelName[];
};
export type SidebarConfiguration = {
/**
* an array of objects that creates groups for specific resources.
*/
groups: SidebarGroup[];
};
export type ExternalLink = {
/**
* the label of the link displayed on the sidebar. This is mandatory.
*/
label: string;
/**
* the URL of the link. This is mandatory.
*/
url: string;
};
export type NextAdminOptions = {
/**
* Global admin title
*
* @default "Admin"
*/
title?: ReactNode;
/**
* `model` is an object that represents the customization options for each model in your schema.
*/
model?: ModelOptions<ModelName>;
/**
* `pages` is an object that allows you to add your own sub pages as a sidebar menu entry.
*/
pages?: Record<string, {
/**
* the title of the page displayed on the sidebar.
*/
title: string;
/**
* the outline HeroIcon name displayed in the sidebar and pages title
* @type ModelIcon
* @link https://heroicons.com/outline
*/
icon?: ModelIcon;
}>;
/**
* The `sidebar` property allows you to customise the aspect of the sidebar menu.
*/
sidebar?: SidebarConfiguration;
/**
* The `externalLinks` property allows you to add external links to the sidebar menu.
*/
externalLinks?: ExternalLink[];
/**
* The `forceColorScheme` property defines a default color palette between `light`, `dark` and `system`, don't allows the user to modify it.
* @default 'system'
*/
forceColorScheme?: ColorScheme;
/**
* The `defaultColorScheme` property defines a default color palette between `light`, `dark` and `system`, but allows the user to modify it.
* @default 'system'
*/
defaultColorScheme?: ColorScheme;
};
/** Type for Schema */
export type SchemaProperty<M extends ModelName> = {
[P in Field<M>]?: NextAdminJSONSchema & {
items?: JSONSchema7Definition;
relation?: ModelName;
};
};
export type SchemaModel<M extends ModelName> = Partial<Omit<NextAdminJSONSchema, "properties">> & {
properties: SchemaProperty<M>;
};
export type SchemaDefinitions = {
[M in ModelName]: SchemaModel<M>;
};
export type Schema = Partial<Omit<NextAdminJSONSchema, "definitions">> & {
definitions: SchemaDefinitions;
};
export type AdminFormData<M extends ModelName> = {
[P in Field<M>]?: string;
};
export type Body<F> = {
[P in keyof F]?: string;
} & {
[key: string]: string;
};
export type Order<M extends ModelName> = {
[P in Field<M>]?: Prisma.SortOrder | {
_count: Prisma.SortOrder;
} | {
[key: string]: Prisma.SortOrder;
};
};
export type Select<M extends ModelName> = {
[P in Field<M>]?: boolean;
} & {
_count?: {
select: {
[key in string]: boolean;
};
};
};
export type Enumeration = {
label: string;
value: string;
data?: any;
};
export type PrismaListRequest<M extends ModelName> = {
select?: Select<M>;
where?: {};
orderBy?: Order<M>;
skip?: number;
take?: number;
};
export type ListData<T extends ModelName> = ListDataItem<T>[];
export type ListDataItem<T extends ModelName> = Model<T> & Record<string, ListDataFieldValue>;
export type ListDataFieldValueWithFormat = {
__nextadmin_formatted: React.ReactNode;
};
export type ListDataFieldValue = ListDataFieldValueWithFormat & ({
type: "scalar";
value: string | number | boolean;
} | {
type: "count";
value: number;
} | {
type: "link";
value: {
label: string;
url: string;
};
isOverridden?: boolean | null;
} | {
type: "date";
value: Date;
});
export type UserData = {
name: string;
picture?: string;
};
export type AdminUser = {
data: UserData;
logout?: [RequestInfo, RequestInit?] | (() => void | Promise<void>) | string;
};
export type AdminComponentProps = {
basePath: string;
apiBasePath: string;
schema: Schema;
data?: ListData<ModelName>;
rawData?: any[];
relationshipsRawData?: RelationshipsRawData;
listFilterOptions?: Array<FilterWrapper<ModelName>>;
resource?: ModelName | null;
slug?: string;
/**
* Page router only
*/
message?: {
type: "success" | "info";
content: string;
};
error?: string | null;
validation?: PropertyValidationError[];
resources?: ModelName[];
total?: number;
isAppDir?: boolean;
locale?: string | null;
/**
* Mandatory for page router
*/
options?: NextAdminOptions;
resourcesTitles?: Record<Prisma.ModelName, string | undefined>;
resourcesIcons?: Record<Prisma.ModelName, ModelIcon>;
customInputs?: Record<Field<ModelName>, React.ReactElement<CustomInputProps> | undefined> | null;
resourcesIdProperty?: Record<ModelName, string>;
/**
* App router only
*/
pageComponent?: React.ComponentType;
customPages?: Array<{
title: string;
path: string;
icon?: ModelIcon;
}>;
actions?: OutputModelAction;
translations?: Translations;
/**
* Global admin title
*
* @default "Admin"
*/
title?: ReactNode;
sidebar?: SidebarConfiguration;
user?: AdminUser;
externalLinks?: ExternalLink[];
dialogComponents?: Record<string, React.ReactElement<ClientActionDialogContentProps<ModelName>>> | null;
};
export type AppRouterComponentProps = AdminComponentProps;
export type PageRouterComponentProps = AppRouterComponentProps | Omit<AdminComponentProps, "resource" | "action"> | Pick<AdminComponentProps, "pageComponent" | "basePath" | "apiBasePath" | "isAppDir" | "message" | "resources" | "error" | "schema">;
export type MainLayoutProps = Pick<AdminComponentProps, "resource" | "resources" | "resourcesTitles" | "customPages" | "basePath" | "apiBasePath" | "isAppDir" | "translations" | "locale" | "title" | "sidebar" | "resourcesIcons" | "user" | "externalLinks" | "options" | "resourcesIdProperty" | "schema">;
export type CustomUIProps = {
dashboard?: React.JSX.Element | (() => React.JSX.Element);
pageLoader?: React.JSX.Element;
};
export type ActionFullParams = ActionParams & {
prisma: PrismaClient;
options: NextAdminOptions;
};
export type ActionParams = {
params?: string[];
schema: any;
};
export type SubmitFormResult = {
deleted?: boolean;
created?: boolean;
updated?: boolean;
redirect?: boolean;
error?: string;
createdId?: number;
validation?: any;
};
export type NextAdminContext<ModelData = any> = {
locale?: string | null;
row?: ModelData;
};
export type CustomInputProps<TItem extends any = any> = Partial<{
name: string;
value: string;
onChange: (evt: ChangeEvent<HTMLInputElement>) => void;
readonly: boolean;
rawErrors: string[];
disabled: boolean;
required?: boolean;
mode: "create" | "edit";
item: TItem;
}> & ComponentProps<"input">;
export type TranslationKeys = "actions.delete.label" | "actions.label" | "export.label" | "actions.create.label" | "actions.edit.label" | "form.button.delete.label" | "form.delete.alert" | "form.button.save.label" | "form.button.save_edit.label" | "list.empty.label" | "list.empty.caption" | "list.footer.indicator.showing" | "list.footer.indicator.to" | "list.footer.indicator.of" | "list.header.add.label" | "list.header.search.placeholder" | "list.header.result" | "list.header.search.result" | "list.header.search.result_filtered" | "list.row.actions.delete.label" | "list.row.actions.delete.alert" | "list.row.actions.delete.success" | "list.row.actions.delete.error" | "list.row.actions.export" | "form.widgets.file_upload.label" | "form.widgets.file_upload.drag_and_drop" | "form.widgets.file_upload.delete" | "form.widgets.multiselect.select" | "form.widgets.scalar_array.add" | "selector.loading" | "theme.dark" | "theme.light" | "theme.system" | "user.logout" | "search.advanced.title" | "search.advanced.add" | "search.advanced.clear" | "search.advanced.cancel" | "search.advanced.save" | "search.advanced.and_or_group" | "search.advanced.conditions.equals" | "search.advanced.conditions.not" | "search.advanced.conditions.in" | "search.advanced.conditions.notIn" | "search.advanced.conditions.lt" | "search.advanced.conditions.lte" | "search.advanced.conditions.gt" | "search.advanced.conditions.gte" | "search.advanced.conditions.contains" | "search.advanced.conditions.search" | "search.advanced.conditions.startsWith" | "search.advanced.conditions.endsWith" | "search.advanced.conditions.null" | "search.advanced.conditions.nnull";
export type Translations = {
[key in TranslationKeys]?: string;
} & {
[key: string]: string;
};
export declare const colorSchemes: string[];
export type ColorScheme = (typeof colorSchemes)[number];
export type BasicColorScheme = Exclude<ColorScheme, "system">;
export type PageProps = {
params: {
[key: string]: string[] | string;
};
searchParams: {
[key: string]: string | string[] | undefined;
} | undefined;
};
export type PromisePageProps = {
[key in keyof PageProps]: Promise<PageProps[key]>;
};
export type GetNextAdminPropsParams = {
/**
* `params` is an array of strings that represents the dynamic segments of your route. (e.g. `[[...params]]`)
*/
params?: string | string[];
/**
* `searchParams` is an object that represents the query parameters of your route. (e.g. `?key=value`)
*/
searchParams: {
[key: string]: string | string[] | undefined;
} | undefined;
/**
* `basePath` is a string that represents the base path of your admin. (e.g. `/admin`)
*/
basePath: string;
/**
* `apiBasePath` is a string that represents the base path of the admin API route. (e.g. `/api/admin`)
*/
apiBasePath: string;
/**
* `options` is an object that represents the options of your admin.
* @link https://next-admin.js.org/docs/api-docs#next-admin-options
*/
options?: NextAdminOptions;
/**
* `prisma` is an instance of PrismaClient.
*/
prisma: PrismaClient;
isAppDir?: boolean;
/**
* `locale` is a string that represents the locale of your admin. (e.g. `en`)
*/
locale?: string;
/**
* `getMessages` is a function that returns a promise of an object that represents the translations of your admin.
* @param locale
* @returns
*/
getMessages?: (locale: string) => Promise<Record<string, string>>;
};
export type GetMainLayoutPropsParams = Omit<GetNextAdminPropsParams, "schema" | "searchParams" | "prisma">;
export type RequestContext<P extends string> = {
params: Promise<{
[key in P]: string[];
}>;
};
export type CreateAppHandlerParams<P extends string = "nextadmin"> = {
/**
* `apiBasePath` is a string that represents the base path of the admin API route. (e.g. `/api`) - optional.
*/
apiBasePath: string;
/**
* Next-admin options
*/
options?: NextAdminOptions;
/**
* Prisma client instance
*/
prisma: PrismaClient;
/**
* A function that acts as a middleware. Useful to add authentication logic for example.
*/
onRequest?: (req: Request, ctx: RequestContext<P>) => ReturnType<Response["json"]> | ReturnType<Response["text"]> | Promise<void>;
/**
* A string indicating the name of the dynamic segment.
*
* Example:
* - If the dynamic segment is `[[...nextadmin]]`, then the `paramKey` should be `nextadmin`.
* - If the dynamic segment is `[[...admin]]`, then the `paramKey` should be `admin`.
*
* @default "nextadmin"
*/
paramKey?: P;
};
export type FormProps = {
data: any;
schema: SchemaDefinitions[ModelName];
resource: ModelName;
slug?: string;
validation?: PropertyValidationError[];
title: string;
customInputs?: Record<Field<ModelName>, React.ReactElement<CustomInputProps> | undefined> | null;
actions?: AdminComponentProps["actions"];
icon?: ModelIcon;
resourcesIdProperty: Record<ModelName, string>;
clientActionsComponents?: AdminComponentProps["dialogComponents"];
relationshipsRawData?: RelationshipsRawData;
};
export type ClientActionDialogContentProps<T extends ModelName> = Partial<{
resource: ModelName;
resourceIds: Array<string | number>;
data: Array<Model<T>>;
onClose: (message?: MessageData) => void;
}>;
export {};
//# sourceMappingURL=types.d.ts.map