-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
137 lines (113 loc) · 4.83 KB
/
Copy pathindex.ts
File metadata and controls
137 lines (113 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { ActionCheckSource, AdminForthPlugin, interpretResource } from "adminforth";
import type { IAdminForth, IHttpServer, AdminForthResourcePages, AdminForthResourceColumn, AdminForthDataTypes, AdminForthResource } from "adminforth";
import type { PluginOptions } from './types.js';
import { z } from "zod";
const createBodySchema = z.object({
resourceId: z.string(),
record: z.record(z.string(), z.unknown()).nullish(),
}).strict();
export default class InlineCreatePlugin extends AdminForthPlugin {
options: PluginOptions;
constructor(options: PluginOptions) {
super(options, import.meta.url);
this.options = options;
}
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
super.modifyResourceConfig(adminforth, resourceConfig);
if (!resourceConfig.options.pageInjections) {
resourceConfig.options.pageInjections = {};
}
if (!resourceConfig.options.pageInjections.list) {
resourceConfig.options.pageInjections.list = {};
}
if (this.resourceConfig.options.allowedActions.create === false) {
throw new Error(`InlineCreatePlugin cannot be used on resource "${resourceConfig.resourceId}" because create action is disabled`);
}
resourceConfig.options.pageInjections.list.tableBodyStart = [{
file: this.componentPath('InlineCreateForm.vue'),
meta: {
pluginInstanceId: this.pluginInstanceId
}
}];
}
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
// Check each column for potential configuration issues
for (const column of resourceConfig.columns) {
if (column.backendOnly) continue;
const isRequiredForCreate = column.required?.create === true;
const isVisibleInList = column.showIn?.list !== false;
const hasFillOnCreate = column.fillOnCreate !== undefined;
const isVisibleInCreate = column.showIn?.create !== false;
if (isRequiredForCreate && !isVisibleInList && !hasFillOnCreate) {
throw new Error(
`Column "${column.name}" in resource "${resourceConfig.resourceId}" is required for create but not visible in list view. ` +
'Either:\n' +
'1) Set showIn.list: true, or\n' +
'2) Set required.create: false and ensure a database default exists, or\n' +
'3) Add fillOnCreate property and set showIn.create: false'
);
}
if (hasFillOnCreate && isVisibleInCreate) {
throw new Error(
`Column "${column.name}" in resource "${resourceConfig.resourceId}" has fillOnCreate but is still visible in create form. ` +
'When using fillOnCreate, set showIn.create: false'
);
}
}
}
instanceUniqueRepresentation() {
return 'inline-create';
}
setupEndpoints(server: IHttpServer) {
server.endpoint({
method: 'POST',
path: `/plugin/${this.pluginInstanceId}/create`,
request_schema: createBodySchema,
handler: async ({ body, adminUser }) => {
const data = body as z.infer<typeof createBodySchema>;
const { record, resourceId } = data;
if (!record) {
return { error: 'No record provided' };
}
if ( this.resourceConfig.resourceId !== resourceId) {
return { error: 'Resource ID mismatch' };
}
const resource = this.adminforth.config.resources.find(r => r.resourceId === resourceId);
const { allowedActions } = await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons, this.adminforth);
if (!allowedActions.create) {
return { error: 'User does not have permission to create records for this resource' };
}
for (const column of resource.columns) {
if (column.backendOnly) {
if (record[column.name] !== undefined) {
return { error: `Column "${column.name}" is backend-only and cannot be set by the user` };
}
};
}
const cleanRecord = resource.columns.reduce((acc, field) => {
if (record[field.name] !== undefined && record[field.name] !== null) {
acc[field.name] = record[field.name];
}
return acc;
}, {});
const result = await this.adminforth.createResourceRecord({
resource,
record: cleanRecord,
adminUser
});
if (result.error) {
return { error: result.error };
}
const createdRecord = result.createdRecord;
//filter createdRecord to only include columns that are not backendOnly
const safe = {};
for (const col of resource.columns) {
if (col.backendOnly) continue;
if (col.showIn?.list === false && col.showIn?.show === false) continue;
safe[col.name] = result.createdRecord[col.name];
}
return { record: safe };
}
});
}
}