@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
555 lines (554 loc) • 31.8 kB
JavaScript
"use client";
;
var __webpack_modules__ = {
"./inputs/RichText/RichTextField": function(module) {
module.exports = import("./inputs/RichText/RichTextField.js").then(function(module) {
return module;
});
}
};
var __webpack_module_cache__ = {};
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
if (void 0 !== cachedModule) return cachedModule.exports;
var module = __webpack_module_cache__[moduleId] = {
exports: {}
};
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
(()=>{
__webpack_require__.n = (module)=>{
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
__webpack_require__.d(getter, {
a: getter
});
return getter;
};
})();
(()=>{
__webpack_require__.d = (exports1, definition)=>{
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
enumerable: true,
get: definition[key]
});
};
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
__webpack_require__.r = (exports1)=>{
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports1, '__esModule', {
value: true
});
};
})();
var __webpack_exports__ = {};
(()=>{
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
default: ()=>components_Form
});
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
const outline_namespaceObject = require("@heroicons/react/24/outline");
const core_namespaceObject = require("@rjsf/core");
var core_default = /*#__PURE__*/ __webpack_require__.n(core_namespaceObject);
const validator_ajv8_namespaceObject = require("@rjsf/validator-ajv8");
var validator_ajv8_default = /*#__PURE__*/ __webpack_require__.n(validator_ajv8_namespaceObject);
const external_clsx_namespaceObject = require("clsx");
var external_clsx_default = /*#__PURE__*/ __webpack_require__.n(external_clsx_namespaceObject);
const external_react_namespaceObject = require("react");
var external_react_default = /*#__PURE__*/ __webpack_require__.n(external_react_namespaceObject);
const external_tailwind_merge_namespaceObject = require("tailwind-merge");
const ClientActionDialogContext_js_namespaceObject = require("../context/ClientActionDialogContext.js");
var ClientActionDialogContext_js_default = /*#__PURE__*/ __webpack_require__.n(ClientActionDialogContext_js_namespaceObject);
const ConfigContext_js_namespaceObject = require("../context/ConfigContext.js");
const FormDataContext_js_namespaceObject = require("../context/FormDataContext.js");
var FormDataContext_js_default = /*#__PURE__*/ __webpack_require__.n(FormDataContext_js_namespaceObject);
const FormStateContext_js_namespaceObject = require("../context/FormStateContext.js");
var FormStateContext_js_default = /*#__PURE__*/ __webpack_require__.n(FormStateContext_js_namespaceObject);
const I18nContext_js_namespaceObject = require("../context/I18nContext.js");
const MessageContext_js_namespaceObject = require("../context/MessageContext.js");
const useDeleteAction_js_namespaceObject = require("../hooks/useDeleteAction.js");
const useRouterInternal_js_namespaceObject = require("../hooks/useRouterInternal.js");
const external_types_js_namespaceObject = require("../types.js");
const jsonSchema_js_namespaceObject = require("../utils/jsonSchema.js");
const tools_js_namespaceObject = require("../utils/tools.js");
const external_FormHeader_js_namespaceObject = require("./FormHeader.js");
var external_FormHeader_js_default = /*#__PURE__*/ __webpack_require__.n(external_FormHeader_js_namespaceObject);
const ArrayField_js_namespaceObject = require("./inputs/ArrayField.js");
var ArrayField_js_default = /*#__PURE__*/ __webpack_require__.n(ArrayField_js_namespaceObject);
const BaseInput_js_namespaceObject = require("./inputs/BaseInput.js");
var BaseInput_js_default = /*#__PURE__*/ __webpack_require__.n(BaseInput_js_namespaceObject);
const CheckboxWidget_js_namespaceObject = require("./inputs/CheckboxWidget.js");
var CheckboxWidget_js_default = /*#__PURE__*/ __webpack_require__.n(CheckboxWidget_js_namespaceObject);
const DateTimeWidget_js_namespaceObject = require("./inputs/DateTimeWidget.js");
var DateTimeWidget_js_default = /*#__PURE__*/ __webpack_require__.n(DateTimeWidget_js_namespaceObject);
const DateWidget_js_namespaceObject = require("./inputs/DateWidget.js");
var DateWidget_js_default = /*#__PURE__*/ __webpack_require__.n(DateWidget_js_namespaceObject);
const FileWidget_js_namespaceObject = require("./inputs/FileWidget/FileWidget.js");
var FileWidget_js_default = /*#__PURE__*/ __webpack_require__.n(FileWidget_js_namespaceObject);
const JsonField_js_namespaceObject = require("./inputs/JsonField.js");
var JsonField_js_default = /*#__PURE__*/ __webpack_require__.n(JsonField_js_namespaceObject);
const NullField_js_namespaceObject = require("./inputs/NullField.js");
var NullField_js_default = /*#__PURE__*/ __webpack_require__.n(NullField_js_namespaceObject);
const SelectWidget_js_namespaceObject = require("./inputs/SelectWidget.js");
var SelectWidget_js_default = /*#__PURE__*/ __webpack_require__.n(SelectWidget_js_namespaceObject);
const TextareaWidget_js_namespaceObject = require("./inputs/TextareaWidget.js");
var TextareaWidget_js_default = /*#__PURE__*/ __webpack_require__.n(TextareaWidget_js_namespaceObject);
const external_Message_js_namespaceObject = require("./Message.js");
const Button_js_namespaceObject = require("./radix/Button.js");
var Button_js_default = /*#__PURE__*/ __webpack_require__.n(Button_js_namespaceObject);
const Tooltip_js_namespaceObject = require("./radix/Tooltip.js");
const rjsf_js_namespaceObject = require("../utils/rjsf.js");
const react19_compat_js_namespaceObject = require("../utils/react19-compat.js");
const RichTextField = /*#__PURE__*/ (0, external_react_namespaceObject.lazy)(()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./inputs/RichText/RichTextField")));
const widgets = {
DateWidget: DateWidget_js_default(),
DateTimeWidget: DateTimeWidget_js_default(),
SelectWidget: SelectWidget_js_default(),
CheckboxWidget: CheckboxWidget_js_default(),
FileWidget: FileWidget_js_default(),
TextareaWidget: TextareaWidget_js_default()
};
const Form = ({ data, schema, resource, validation: validationProp, customInputs })=>{
const [validation, setValidation] = (0, external_react_namespaceObject.useState)(validationProp);
const { basePath, options, apiBasePath } = (0, ConfigContext_js_namespaceObject.useConfig)();
const modelOptions = options?.model?.[resource];
const canDelete = !modelOptions?.permissions || modelOptions?.permissions?.includes(external_types_js_namespaceObject.Permission.DELETE);
const canEdit = !modelOptions?.permissions || modelOptions?.permissions?.includes(external_types_js_namespaceObject.Permission.EDIT);
const canCreate = !modelOptions?.permissions || modelOptions?.permissions?.includes(external_types_js_namespaceObject.Permission.CREATE);
const { edit, id, ...schemas } = (0, jsonSchema_js_namespaceObject.getSchemas)(data, schema, modelOptions?.edit?.fields);
const { router } = (0, useRouterInternal_js_namespaceObject.useRouterInternal)();
const { t } = (0, I18nContext_js_namespaceObject.useI18n)();
const formRef = (0, external_react_namespaceObject.useRef)(null);
const [isPending, setIsPending] = (0, external_react_namespaceObject.useState)(false);
const allDisabled = edit && !canEdit;
const { runSingleDeletion } = (0, useDeleteAction_js_namespaceObject.useDeleteAction)(resource);
const { showMessage } = (0, MessageContext_js_namespaceObject.useMessage)();
const { cleanAll } = (0, FormStateContext_js_namespaceObject.useFormState)();
const { setFormData } = (0, FormDataContext_js_namespaceObject.useFormData)();
(0, external_react_namespaceObject.useEffect)(()=>{
if (!edit && !canCreate) router.replace({
pathname: "/"
});
}, [
canCreate,
edit,
router
]);
const submitButton = (0, external_react_namespaceObject.useMemo)(()=>(props)=>{
const { uiSchema } = props;
const { norender, props: buttonProps } = (0, rjsf_js_namespaceObject.getSubmitButtonOptions)(uiSchema);
if (norender) return null;
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
className: "align-center mt-4 flex flex-wrap justify-between gap-2",
children: [
(edit && canEdit || !edit && canCreate) && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
className: "order-2 flex gap-2",
children: [
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(Button_js_default(), {
...buttonProps,
className: "order-2 flex gap-2",
type: "submit",
name: "__admin_redirect",
value: "list",
loading: isPending,
children: [
!isPending && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(outline_namespaceObject.CheckCircleIcon, {
className: "h-6 w-6"
}),
t("form.button.save.label")
]
}),
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Button_js_default(), {
...buttonProps,
variant: "ghost",
className: "order-1 hidden sm:block",
tabIndex: -1,
type: "submit",
loading: isPending,
name: "save_edit",
children: t("form.button.save_edit.label")
})
]
}),
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: "order-1",
children: edit && canDelete && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(Button_js_default(), {
variant: "destructiveOutline",
className: "flex gap-2",
formNoValidate: true,
tabIndex: -1,
onClick: async (e)=>{
if (confirm(t("form.delete.alert"))) try {
setIsPending(true);
await runSingleDeletion(id);
router.replace({
pathname: `${basePath}/${(0, tools_js_namespaceObject.slugify)(resource)}`,
query: {
message: JSON.stringify({
type: "success",
message: t("form.delete.succeed")
})
}
});
} catch (e) {
showMessage({
type: "error",
message: t(e.message)
});
} finally{
setIsPending(false);
}
else e.preventDefault();
},
loading: isPending,
children: [
!isPending && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(outline_namespaceObject.TrashIcon, {
className: "h-4 w-4"
}),
t("form.button.delete.label")
]
})
})
]
});
}, [
isPending,
id
]);
const extraErrors = validation?.reduce((acc, curr)=>{
acc[curr.property] = {
__errors: [
curr.message
]
};
return acc;
}, {});
const onSubmit = (0, external_react_namespaceObject.useCallback)(async (formData)=>{
try {
setIsPending(true);
const response = await fetch(`${apiBasePath}/${(0, tools_js_namespaceObject.slugify)(resource)}${id ? `/${id}` : ""}`, {
method: "POST",
body: formData
});
const result = await response.json();
result?.validation ? setValidation(result.validation) : setValidation(void 0);
if (result?.data) {
setFormData(result.data);
cleanAll();
}
if (result?.deleted) return router.replace({
pathname: `${basePath}/${(0, tools_js_namespaceObject.slugify)(resource)}`,
query: {
message: JSON.stringify({
type: "success",
message: t("form.delete.succeed")
})
}
});
if (result?.created) {
const pathname = result?.redirect ? `${basePath}/${(0, tools_js_namespaceObject.slugify)(resource)}` : `${basePath}/${(0, tools_js_namespaceObject.slugify)(resource)}/${result.createdId}`;
return router.push({
pathname,
query: {
message: JSON.stringify({
type: "success",
message: t("form.create.succeed")
})
}
});
}
if (result?.updated) {
const pathname = result?.redirect ? `${basePath}/${(0, tools_js_namespaceObject.slugify)(resource)}` : location.pathname;
if (pathname === location.pathname) {
router.refresh();
showMessage({
type: "success",
message: t("form.update.succeed")
});
} else router.push({
pathname,
query: {
message: JSON.stringify({
type: "success",
message: t("form.update.succeed")
})
}
});
}
if (result?.error) showMessage({
type: "error",
message: t(result.error)
});
} finally{
setIsPending(false);
}
}, [
apiBasePath,
id
]);
const fields = (0, external_react_namespaceObject.useMemo)(()=>({
ArrayField: (props)=>{
const customInput = customInputs?.[props.name];
const improvedCustomInput = customInput ? /*#__PURE__*/ (0, external_react_namespaceObject.cloneElement)((0, react19_compat_js_namespaceObject.getClonableElement)(customInput), {
...(0, react19_compat_js_namespaceObject.getClonableElement)(customInput).props,
mode: edit ? "edit" : "create"
}) : void 0;
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(ArrayField_js_default(), {
...props,
customInput: improvedCustomInput
});
},
NullField: NullField_js_default()
}), [
customInputs,
edit
]);
const templates = {
FieldTemplate: (props)=>{
const { id, classNames, style, label, help, required, description, errors, children, schema } = props;
const labelAlias = modelOptions?.aliases?.[id] || (0, tools_js_namespaceObject.formatLabel)(label);
const labelName = t(`model.${resource}.fields.${id}`, {}, labelAlias);
let styleField = modelOptions?.edit?.styles?.[id];
const tooltip = modelOptions?.edit?.fields?.[id]?.tooltip || modelOptions?.edit?.customFields?.[id]?.tooltip;
const sanitizedClassNames = classNames?.split(",").filter((className)=>"null" !== className).join(" ");
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
style: style,
className: external_clsx_default()(sanitizedClassNames, styleField),
children: [
"null" !== schema.type && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("label", {
className: external_clsx_default()("text-nextadmin-content-inverted dark:text-dark-nextadmin-content-inverted mb-2 flex items-center gap-2 text-sm font-medium leading-6"),
htmlFor: id,
children: [
labelName,
required ? "*" : null,
!!tooltip && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Tooltip_js_namespaceObject.TooltipProvider, {
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(Tooltip_js_namespaceObject.TooltipRoot, {
children: [
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Tooltip_js_namespaceObject.TooltipTrigger, {
asChild: true,
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(outline_namespaceObject.InformationCircleIcon, {
className: "text-nextadmin-content-default dark:text-dark-nextadmin-content-default h-4 w-4"
})
}),
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Tooltip_js_namespaceObject.TooltipPortal, {
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Tooltip_js_namespaceObject.TooltipContent, {
side: "right",
className: "px-2 py-1",
sideOffset: 4,
children: tooltip
})
})
]
})
})
]
}),
children,
description,
errors,
help
]
});
},
ObjectFieldTemplate: (props)=>{
const styleForm = modelOptions?.edit?.styles?._form;
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: (0, external_tailwind_merge_namespaceObject.twMerge)("grid gap-4", styleForm),
children: props.properties.map((element)=>element.content)
});
},
BaseInputTemplate: ({ onChange, options, onChangeOverride, uiSchema, readonly, formContext, autofocus, rawErrors, schema, registry, hideError, hideLabel, ...props })=>{
const { setFieldDirty } = (0, FormStateContext_js_namespaceObject.useFormState)();
const onTextChange = ({ target: { value: val } })=>{
setFieldDirty(props.name);
onChange("" === val ? options.emptyValue || "" : val);
};
let customInput = customInputs?.[props.name];
if (customInput) return /*#__PURE__*/ (0, external_react_namespaceObject.cloneElement)((0, react19_compat_js_namespaceObject.getClonableElement)(customInput), {
value: props.value,
onChange: onChangeOverride || onTextChange,
readonly,
rawErrors,
name: props.name,
required: props.required,
disabled: props.disabled,
mode: edit ? "edit" : "create",
item: data
});
if (schema?.format === "json") return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(JsonField_js_default(), {
onChange: onChangeOverride || onTextChange,
readonly: readonly,
rawErrors: rawErrors,
...props
});
if (schema?.format?.startsWith("richtext-")) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_namespaceObject.Suspense, {
fallback: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: "h-48 animate-pulse rounded bg-gray-500"
}),
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(RichTextField, {
onChange: onChangeOverride || onTextChange,
readonly: readonly,
rawErrors: rawErrors,
name: props.name,
value: props.value,
schema: schema,
disabled: props.disabled,
required: props.required
})
});
if ([
"time",
"time-second"
].includes(schema?.format)) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(BaseInput_js_default(), {
type: "time",
onChange: onChangeOverride || onTextChange,
...props,
value: props.value.split(":").slice(0, schema?.format === "time-second" ? 3 : 2).join(":") ?? "",
className: external_clsx_default()({
"ring-red-600 dark:ring-red-400": rawErrors
}),
step: schema?.format === "time-second" ? 1 : void 0
});
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(BaseInput_js_default(), {
onChange: onChangeOverride || onTextChange,
...props,
value: props.value ?? "",
className: external_clsx_default()({
"ring-red-600 dark:ring-red-400": rawErrors
})
});
},
ErrorListTemplate: ()=>null,
FieldErrorTemplate: ({ errors })=>errors ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: "mt-1 text-sm text-red-600 dark:text-red-400",
children: errors.map((error, idx)=>{
if ("string" == typeof error) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_default().Fragment, {
children: t(error)
}, idx);
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_default().Fragment, {
children: error
}, idx);
})
}) : null,
DescriptionFieldTemplate: ({ description, schema })=>description && "null" !== schema.type ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
className: "text-nextadmin-content-emphasis dark:text-dark-nextadmin-content-emphasis text-sm",
children: description
}) : null,
ButtonTemplates: {
SubmitButton: submitButton
}
};
const CustomForm = (0, external_react_namespaceObject.useMemo)(()=>/*#__PURE__*/ (0, external_react_namespaceObject.forwardRef)((props, ref)=>{
const { dirtyFields } = (0, FormStateContext_js_namespaceObject.useFormState)();
const { formData } = (0, FormDataContext_js_namespaceObject.useFormData)();
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("form", {
...props,
ref: ref,
onSubmit: (e)=>{
e.preventDefault();
const formValues = new FormData(e.target);
const data = new FormData();
dirtyFields.forEach((field)=>{
const schemaProperties = schema.properties[field];
const isFieldArrayOfFiles = schemaProperties?.type === "array" && (0, tools_js_namespaceObject.isFileUploadFormat)(schemaProperties.format ?? "");
if (isFieldArrayOfFiles) {
const files = formValues.getAll(field).filter((file)=>"string" == typeof file || file instanceof File && !!file.name);
const values = formData[field];
values.forEach((val)=>{
data.append(field, val);
});
if (files.length > 0) files.forEach((file)=>{
data.append(field, file);
});
else data.append(field, new File([], ""));
return;
}
data.append(field, formValues.get(field));
});
const submitter = e.nativeEvent.submitter;
data.append(submitter.name, submitter.value);
onSubmit(data);
}
});
}), [
onSubmit,
schema
]);
const RjsfFormComponent = (0, external_react_namespaceObject.useMemo)(()=>/*#__PURE__*/ (0, external_react_namespaceObject.forwardRef)((_props, ref)=>{
const { formData } = (0, FormDataContext_js_namespaceObject.useFormData)();
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(core_default(), {
tagName: CustomForm,
idPrefix: "",
idSeparator: "",
...schemas,
onChange: (e)=>{
setFormData(e.formData);
},
formData: formData,
validator: validator_ajv8_default(),
extraErrors: extraErrors,
fields: fields,
disabled: allDisabled,
formContext: {
isPending,
schema
},
templates: templates,
widgets: widgets,
ref: ref,
className: "relative"
});
}), [
submitButton
]);
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: "relative h-full",
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
className: "bg-nextadmin-background-default dark:bg-dark-nextadmin-background-default max-w-full p-4 align-middle sm:p-8",
children: [
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_Message_js_namespaceObject.Message, {
className: "-mt-2 mb-2 sm:-mt-4 sm:mb-4"
}),
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
className: "bg-nextadmin-background-default dark:bg-dark-nextadmin-background-emphasis border-nextadmin-border-default dark:border-dark-nextadmin-border-default max-w-screen-md rounded-lg border p-4 sm:p-8",
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(RjsfFormComponent, {
ref: formRef
})
})
]
})
});
};
const FormWrapper = ({ clientActionsComponents, relationshipsRawData, ...props })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(ClientActionDialogContext_js_default(), {
componentsMap: clientActionsComponents,
children: [
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_FormHeader_js_default(), {
...props
}),
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormDataContext_js_default(), {
data: props.data,
relationshipsRawData: relationshipsRawData,
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormStateContext_js_default(), {
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(Form, {
...props
})
})
})
]
});
const components_Form = FormWrapper;
})();
exports["default"] = __webpack_exports__["default"];
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
"default"
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
Object.defineProperty(exports, '__esModule', {
value: true
});