adminforth 2.4.0-next.32 → 2.4.0-next.321
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/callTsProxy.js +14 -4
- package/commands/createApp/templates/api.ts.hbs +10 -0
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +12 -1
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/templates/prisma.config.ts.hbs +8 -0
- package/commands/createApp/templates/schema.prisma.hbs +0 -1
- package/commands/createApp/utils.js +10 -0
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +13 -7
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs +28 -0
- package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
- package/commands/createPlugin/templates/package.json.hbs +1 -1
- package/commands/generateModels.js +30 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +21 -2
- package/dist/auth.js.map +1 -1
- package/dist/dataConnectors/baseConnector.d.ts +1 -1
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +70 -18
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
- package/dist/dataConnectors/clickhouse.js +15 -0
- package/dist/dataConnectors/clickhouse.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +50 -15
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/dataConnectors/mysql.d.ts.map +1 -1
- package/dist/dataConnectors/mysql.js +11 -0
- package/dist/dataConnectors/mysql.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +43 -14
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +11 -0
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -21
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +2 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +62 -6
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts +6 -0
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +202 -25
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +184 -31
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +499 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +555 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +7 -15
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +45 -68
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +40 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/package-lock.json +1208 -708
- package/dist/spa/package.json +34 -34
- package/dist/spa/src/App.vue +61 -173
- package/dist/spa/src/adminforth.ts +42 -18
- package/dist/spa/src/afcl/AreaChart.vue +0 -1
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
- package/dist/spa/src/afcl/Card.vue +25 -0
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +47 -27
- package/dist/spa/src/afcl/Dropzone.vue +145 -48
- package/dist/spa/src/afcl/Input.vue +14 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +3 -3
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +82 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +313 -75
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +28 -18
- package/dist/spa/src/afcl/VerticalTabs.vue +21 -7
- package/dist/spa/src/afcl/index.ts +6 -3
- package/dist/spa/src/components/AcceptModal.vue +48 -14
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/CallActionWrapper.vue +15 -0
- package/dist/spa/src/components/ColumnValueInput.vue +38 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -21
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +195 -132
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +95 -23
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +119 -94
- package/dist/spa/src/components/ResourceListTableVirtual.vue +118 -87
- package/dist/spa/src/components/ShowTable.vue +21 -15
- package/dist/spa/src/components/Sidebar.vue +472 -0
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +3 -3
- package/dist/spa/src/components/ThreeDotsMenu.vue +84 -15
- package/dist/spa/src/components/Toast.vue +40 -29
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +44 -17
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +5 -3
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/router/index.ts +8 -0
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +13 -1
- package/dist/spa/src/stores/core.ts +13 -1
- package/dist/spa/src/stores/filters.ts +33 -2
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/stores/toast.ts +22 -3
- package/dist/spa/src/types/Back.ts +168 -23
- package/dist/spa/src/types/Common.ts +93 -32
- package/dist/spa/src/types/FrontendAPI.ts +31 -5
- package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -4
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +4 -2
- package/dist/spa/src/types/adapters/index.ts +3 -0
- package/dist/spa/src/utils.ts +291 -11
- package/dist/spa/src/views/CreateView.vue +63 -21
- package/dist/spa/src/views/EditView.vue +55 -22
- package/dist/spa/src/views/ListView.vue +144 -87
- package/dist/spa/src/views/LoginView.vue +26 -35
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/SettingsView.vue +121 -0
- package/dist/spa/src/views/ShowView.vue +83 -53
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +45 -2
- package/dist/types/Back.d.ts +151 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js +15 -0
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +108 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +31 -3
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
- package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CaptchaAdapter.js +5 -0
- package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +2 -3
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -1
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.js +2 -0
- package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +2 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -1
- package/dist/types/adapters/index.d.ts +3 -0
- package/dist/types/adapters/index.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/modules/restApi.js
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
import { ADMINFORTH_VERSION, listify } from './utils.js';
|
|
1
|
+
import { ADMINFORTH_VERSION, listify, getLoginPromptHTML } from './utils.js';
|
|
2
2
|
import AdminForthAuth from "../auth.js";
|
|
3
3
|
import { ActionCheckSource, AdminForthDataTypes, AdminForthFilterOperators, AdminForthResourcePages, AllowedActionsEnum } from "../types/Common.js";
|
|
4
4
|
import { filtersTools } from "../modules/filtersTools.js";
|
|
5
|
+
async function resolveBoolOrFn(val, ctx) {
|
|
6
|
+
if (typeof val === 'function') {
|
|
7
|
+
return !!(await (val)(ctx));
|
|
8
|
+
}
|
|
9
|
+
return !!val;
|
|
10
|
+
}
|
|
11
|
+
async function isBackendOnly(col, ctx) {
|
|
12
|
+
return await resolveBoolOrFn(col.backendOnly, ctx);
|
|
13
|
+
}
|
|
14
|
+
async function isShown(col, page, ctx) {
|
|
15
|
+
const s = col.showIn || {};
|
|
16
|
+
if (s[page] !== undefined)
|
|
17
|
+
return await resolveBoolOrFn(s[page], ctx);
|
|
18
|
+
if (s.all !== undefined)
|
|
19
|
+
return await resolveBoolOrFn(s.all, ctx);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
async function isFilledOnCreate(col) {
|
|
23
|
+
const fillOnCreate = !!col.fillOnCreate;
|
|
24
|
+
return fillOnCreate;
|
|
25
|
+
}
|
|
5
26
|
export async function interpretResource(adminUser, resource, meta, source, adminforth) {
|
|
6
27
|
if (process.env.HEAVY_DEBUG) {
|
|
7
28
|
console.log('🪲Interpreting resource', resource.resourceId, source, 'adminUser', adminUser);
|
|
@@ -44,7 +65,7 @@ export default class AdminForthRestAPI {
|
|
|
44
65
|
constructor(adminforth) {
|
|
45
66
|
this.adminforth = adminforth;
|
|
46
67
|
}
|
|
47
|
-
async processLoginCallbacks(adminUser, toReturn, response, extra) {
|
|
68
|
+
async processLoginCallbacks(adminUser, toReturn, response, extra, rememberMeDays) {
|
|
48
69
|
var _a, _b, _c;
|
|
49
70
|
const beforeLoginConfirmation = this.adminforth.config.auth.beforeLoginConfirmation;
|
|
50
71
|
for (const hook of listify(beforeLoginConfirmation)) {
|
|
@@ -53,6 +74,7 @@ export default class AdminForthRestAPI {
|
|
|
53
74
|
response,
|
|
54
75
|
adminforth: this.adminforth,
|
|
55
76
|
extra,
|
|
77
|
+
rememberMeDays
|
|
56
78
|
});
|
|
57
79
|
if (((_a = resp === null || resp === void 0 ? void 0 : resp.body) === null || _a === void 0 ? void 0 : _a.redirectTo) || (resp === null || resp === void 0 ? void 0 : resp.error)) {
|
|
58
80
|
// delete all items from toReturn and add these:
|
|
@@ -109,9 +131,11 @@ export default class AdminForthRestAPI {
|
|
|
109
131
|
pk: userRecord[userResource.columns.find((col) => col.primaryKey).name],
|
|
110
132
|
username,
|
|
111
133
|
};
|
|
112
|
-
|
|
134
|
+
const expireInDays = rememberMe ? this.adminforth.config.auth.rememberMeDays || 30 : 1;
|
|
135
|
+
await this.processLoginCallbacks(adminUser, toReturn, response, {
|
|
136
|
+
body, headers, query, cookies, requestUrl,
|
|
137
|
+
}, expireInDays);
|
|
113
138
|
if (toReturn.allowedLogin) {
|
|
114
|
-
const expireInDays = rememberMe && this.adminforth.config.auth.rememberMeDays;
|
|
115
139
|
this.adminforth.auth.setAuthCookie({
|
|
116
140
|
expireInDays,
|
|
117
141
|
response,
|
|
@@ -142,6 +166,17 @@ export default class AdminForthRestAPI {
|
|
|
142
166
|
return { ok: true };
|
|
143
167
|
},
|
|
144
168
|
});
|
|
169
|
+
server.endpoint({
|
|
170
|
+
noAuth: true,
|
|
171
|
+
method: 'GET',
|
|
172
|
+
path: '/get_login_form_config',
|
|
173
|
+
handler: async ({ tr }) => {
|
|
174
|
+
const loginPromptHTML = await getLoginPromptHTML(this.adminforth.config.auth.loginPromptHTML);
|
|
175
|
+
return {
|
|
176
|
+
loginPromptHTML: await tr(loginPromptHTML, 'system.loginPromptHTML'),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
});
|
|
145
180
|
server.endpoint({
|
|
146
181
|
noAuth: true,
|
|
147
182
|
method: 'GET',
|
|
@@ -161,21 +196,24 @@ export default class AdminForthRestAPI {
|
|
|
161
196
|
usernameFieldName: usernameColumn.label,
|
|
162
197
|
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
|
|
163
198
|
loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
|
|
199
|
+
removeBackgroundBlendMode: this.adminforth.config.auth.removeBackgroundBlendMode,
|
|
164
200
|
title: (_a = this.adminforth.config.customization) === null || _a === void 0 ? void 0 : _a.title,
|
|
165
201
|
demoCredentials: this.adminforth.config.auth.demoCredentials,
|
|
166
|
-
loginPromptHTML: await tr(this.adminforth.config.auth.loginPromptHTML, 'system.loginPromptHTML'),
|
|
167
202
|
loginPageInjections: this.adminforth.config.customization.loginPageInjections,
|
|
168
203
|
globalInjections: {
|
|
169
204
|
everyPageBottom: this.adminforth.config.customization.globalInjections.everyPageBottom,
|
|
205
|
+
sidebarTop: this.adminforth.config.customization.globalInjections.sidebarTop,
|
|
170
206
|
},
|
|
171
207
|
rememberMeDays: this.adminforth.config.auth.rememberMeDays,
|
|
208
|
+
singleTheme: this.adminforth.config.customization.singleTheme,
|
|
209
|
+
customHeadItems: this.adminforth.config.customization.customHeadItems,
|
|
172
210
|
};
|
|
173
211
|
},
|
|
174
212
|
});
|
|
175
213
|
server.endpoint({
|
|
176
214
|
method: 'GET',
|
|
177
215
|
path: '/get_base_config',
|
|
178
|
-
handler: async ({ input, adminUser, cookies, tr }) => {
|
|
216
|
+
handler: async ({ input, adminUser, cookies, tr, response }) => {
|
|
179
217
|
var _a, _b, _c;
|
|
180
218
|
let username = '';
|
|
181
219
|
let userFullName = '';
|
|
@@ -183,6 +221,10 @@ export default class AdminForthRestAPI {
|
|
|
183
221
|
if (!this.adminforth.config.auth) {
|
|
184
222
|
throw new Error('No config.auth defined');
|
|
185
223
|
}
|
|
224
|
+
response.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
225
|
+
response.setHeader('Pragma', 'no-cache');
|
|
226
|
+
response.setHeader('Expires', '0');
|
|
227
|
+
response.setHeader('Surrogate-Control', 'no-store');
|
|
186
228
|
const dbUser = adminUser.dbUser;
|
|
187
229
|
username = dbUser[this.adminforth.config.auth.usernameField];
|
|
188
230
|
userFullName = dbUser[this.adminforth.config.auth.userFullNameField];
|
|
@@ -228,20 +270,31 @@ export default class AdminForthRestAPI {
|
|
|
228
270
|
newMenu.push(newMenuItem);
|
|
229
271
|
}
|
|
230
272
|
const announcementBadge = (_b = (_a = this.adminforth.config.customization).announcementBadge) === null || _b === void 0 ? void 0 : _b.call(_a, adminUser);
|
|
273
|
+
const settingPages = [];
|
|
274
|
+
for (const settingPage of this.adminforth.config.auth.userMenuSettingsPages || []) {
|
|
275
|
+
if (settingPage.isVisible) {
|
|
276
|
+
const isVisible = await settingPage.isVisible(adminUser);
|
|
277
|
+
settingPages.push(Object.assign(Object.assign({}, settingPage), { isVisible }));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
231
280
|
const publicPart = {
|
|
232
281
|
brandName: this.adminforth.config.customization.brandName,
|
|
233
282
|
usernameFieldName: usernameColumn.label,
|
|
234
283
|
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
|
|
235
284
|
loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
|
|
285
|
+
removeBackgroundBlendMode: this.adminforth.config.auth.removeBackgroundBlendMode,
|
|
236
286
|
title: (_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.title,
|
|
237
287
|
demoCredentials: this.adminforth.config.auth.demoCredentials,
|
|
238
|
-
loginPromptHTML: await tr(this.adminforth.config.auth.loginPromptHTML, 'system.loginPromptHTML'),
|
|
239
288
|
loginPageInjections: this.adminforth.config.customization.loginPageInjections,
|
|
240
289
|
rememberMeDays: this.adminforth.config.auth.rememberMeDays,
|
|
290
|
+
singleTheme: this.adminforth.config.customization.singleTheme,
|
|
291
|
+
customHeadItems: this.adminforth.config.customization.customHeadItems,
|
|
241
292
|
};
|
|
242
293
|
const loggedInPart = {
|
|
243
294
|
showBrandNameInSidebar: this.adminforth.config.customization.showBrandNameInSidebar,
|
|
295
|
+
showBrandLogoInSidebar: this.adminforth.config.customization.showBrandLogoInSidebar,
|
|
244
296
|
brandLogo: this.adminforth.config.customization.brandLogo,
|
|
297
|
+
iconOnlySidebar: this.adminforth.config.customization.iconOnlySidebar,
|
|
245
298
|
datesFormat: this.adminforth.config.customization.datesFormat,
|
|
246
299
|
timeFormat: this.adminforth.config.customization.timeFormat,
|
|
247
300
|
auth: this.adminforth.config.auth,
|
|
@@ -251,6 +304,7 @@ export default class AdminForthRestAPI {
|
|
|
251
304
|
announcementBadge,
|
|
252
305
|
globalInjections: this.adminforth.config.customization.globalInjections,
|
|
253
306
|
userFullnameField: this.adminforth.config.auth.userFullNameField,
|
|
307
|
+
settingPages: settingPages,
|
|
254
308
|
};
|
|
255
309
|
// translate menu labels
|
|
256
310
|
const translateRoutines = [];
|
|
@@ -268,19 +322,37 @@ export default class AdminForthRestAPI {
|
|
|
268
322
|
if (menuItem.children) {
|
|
269
323
|
menuItem.children.forEach(processItem);
|
|
270
324
|
}
|
|
325
|
+
if (menuItem.pageLabel) {
|
|
326
|
+
translateRoutines.push((async () => {
|
|
327
|
+
menuItem.pageLabel = await tr(menuItem.pageLabel, `UserMenu.${menuItem.pageLabel}`);
|
|
328
|
+
})());
|
|
329
|
+
}
|
|
271
330
|
};
|
|
272
331
|
newMenu.forEach((menuItem) => {
|
|
273
332
|
processItem(menuItem);
|
|
274
333
|
});
|
|
334
|
+
if (this.adminforth.config.auth.userMenuSettingsPages) {
|
|
335
|
+
this.adminforth.config.auth.userMenuSettingsPages.forEach((page) => {
|
|
336
|
+
processItem(page);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
275
339
|
await Promise.all(translateRoutines);
|
|
276
340
|
// strip all backendOnly fields or not described in adminForth fields from dbUser
|
|
277
341
|
// (when user defines column and does not set backendOnly, we assume it is not backendOnly)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
342
|
+
const ctx = {
|
|
343
|
+
adminUser,
|
|
344
|
+
resource: userResource,
|
|
345
|
+
meta: {},
|
|
346
|
+
source: ActionCheckSource.ShowRequest,
|
|
347
|
+
adminforth: this.adminforth,
|
|
348
|
+
};
|
|
349
|
+
for (const key of Object.keys(adminUser.dbUser)) {
|
|
350
|
+
const col = userResource.columns.find((c) => c.name === key);
|
|
351
|
+
const bo = col ? await isBackendOnly(col, ctx) : true;
|
|
352
|
+
if (!col || bo) {
|
|
281
353
|
delete adminUser.dbUser[key];
|
|
282
354
|
}
|
|
283
|
-
}
|
|
355
|
+
}
|
|
284
356
|
return {
|
|
285
357
|
user: userData,
|
|
286
358
|
resources: this.adminforth.config.resources.map((res) => ({
|
|
@@ -435,7 +507,7 @@ export default class AdminForthRestAPI {
|
|
|
435
507
|
method: 'POST',
|
|
436
508
|
path: '/get_resource_data',
|
|
437
509
|
handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
|
|
438
|
-
var _a, _b, _c, _d, _e;
|
|
510
|
+
var _a, _b, _c, _d, _e, _f;
|
|
439
511
|
const { resourceId, source } = body;
|
|
440
512
|
if (['show', 'list', 'edit'].includes(source) === false) {
|
|
441
513
|
return { error: 'Invalid source, should be list or show' };
|
|
@@ -632,22 +704,38 @@ export default class AdminForthRestAPI {
|
|
|
632
704
|
}
|
|
633
705
|
});
|
|
634
706
|
}));
|
|
707
|
+
const pkField = (_d = resource.columns.find((col) => col.primaryKey)) === null || _d === void 0 ? void 0 : _d.name;
|
|
635
708
|
// remove all columns which are not defined in resources, or defined but backendOnly
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
709
|
+
{
|
|
710
|
+
const ctx = {
|
|
711
|
+
adminUser,
|
|
712
|
+
resource,
|
|
713
|
+
meta,
|
|
714
|
+
source: {
|
|
715
|
+
show: ActionCheckSource.ShowRequest,
|
|
716
|
+
list: ActionCheckSource.ListRequest,
|
|
717
|
+
edit: ActionCheckSource.EditLoadRequest,
|
|
718
|
+
}[source],
|
|
719
|
+
adminforth: this.adminforth,
|
|
720
|
+
};
|
|
721
|
+
for (const item of data.data) {
|
|
722
|
+
for (const key of Object.keys(item)) {
|
|
723
|
+
const col = resource.columns.find((c) => c.name === key);
|
|
724
|
+
const bo = col ? await isBackendOnly(col, ctx) : true;
|
|
725
|
+
if (!col || bo) {
|
|
726
|
+
delete item[key];
|
|
727
|
+
}
|
|
640
728
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
729
|
+
item._label = resource.recordLabel(item);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
644
732
|
if (source === 'list' && resource.options.listTableClickUrl) {
|
|
645
733
|
await Promise.all(data.data.map(async (item) => {
|
|
646
734
|
item._clickUrl = await resource.options.listTableClickUrl(item, adminUser);
|
|
647
735
|
}));
|
|
648
736
|
}
|
|
649
737
|
// only after adminforth made all post processing, give user ability to edit it
|
|
650
|
-
for (const hook of listify((
|
|
738
|
+
for (const hook of listify((_f = (_e = resource.hooks) === null || _e === void 0 ? void 0 : _e[hookSource]) === null || _f === void 0 ? void 0 : _f.afterDatasourceResponse)) {
|
|
651
739
|
const resp = await hook({
|
|
652
740
|
resource,
|
|
653
741
|
query: body,
|
|
@@ -672,7 +760,7 @@ export default class AdminForthRestAPI {
|
|
|
672
760
|
method: 'POST',
|
|
673
761
|
path: '/get_resource_foreign_data',
|
|
674
762
|
handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
|
|
675
|
-
const { resourceId, column } = body;
|
|
763
|
+
const { resourceId, column, search } = body;
|
|
676
764
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
677
765
|
return { error: 'Database discovery not started' };
|
|
678
766
|
}
|
|
@@ -742,6 +830,43 @@ export default class AdminForthRestAPI {
|
|
|
742
830
|
throw new Error(`Wrong filter object value: ${JSON.stringify(filters)}`);
|
|
743
831
|
}
|
|
744
832
|
}
|
|
833
|
+
if (search && search.trim() && columnConfig.foreignResource.searchableFields) {
|
|
834
|
+
const searchableFields = Array.isArray(columnConfig.foreignResource.searchableFields)
|
|
835
|
+
? columnConfig.foreignResource.searchableFields
|
|
836
|
+
: [columnConfig.foreignResource.searchableFields];
|
|
837
|
+
const searchOperator = columnConfig.foreignResource.searchIsCaseSensitive
|
|
838
|
+
? AdminForthFilterOperators.LIKE
|
|
839
|
+
: AdminForthFilterOperators.ILIKE;
|
|
840
|
+
const availableSearchFields = searchableFields.filter((fieldName) => {
|
|
841
|
+
const fieldExists = targetResource.columns.some(col => col.name === fieldName);
|
|
842
|
+
if (!fieldExists) {
|
|
843
|
+
process.env.HEAVY_DEBUG && console.log(`⚠️ Field '${fieldName}' not found in polymorphic target resource '${targetResource.resourceId}', skipping in search filter.`);
|
|
844
|
+
}
|
|
845
|
+
return fieldExists;
|
|
846
|
+
});
|
|
847
|
+
if (availableSearchFields.length === 0) {
|
|
848
|
+
process.env.HEAVY_DEBUG && console.log(`⚠️ No searchable fields available in polymorphic target resource '${targetResource.resourceId}', skipping resource.`);
|
|
849
|
+
resolve({ items: [] });
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
const searchFilters = availableSearchFields.map((fieldName) => {
|
|
853
|
+
const filter = {
|
|
854
|
+
field: fieldName,
|
|
855
|
+
operator: searchOperator,
|
|
856
|
+
value: search.trim(),
|
|
857
|
+
};
|
|
858
|
+
return filter;
|
|
859
|
+
});
|
|
860
|
+
if (searchFilters.length > 1) {
|
|
861
|
+
normalizedFilters.subFilters.push({
|
|
862
|
+
operator: AdminForthFilterOperators.OR,
|
|
863
|
+
subFilters: searchFilters,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
else if (searchFilters.length === 1) {
|
|
867
|
+
normalizedFilters.subFilters.push(searchFilters[0]);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
745
870
|
const dbDataItems = await this.adminforth.connectors[targetResource.dataSource].getData({
|
|
746
871
|
resource: targetResource,
|
|
747
872
|
limit,
|
|
@@ -835,6 +960,7 @@ export default class AdminForthRestAPI {
|
|
|
835
960
|
return { error };
|
|
836
961
|
}
|
|
837
962
|
const { record } = body;
|
|
963
|
+
// todo if showIn.create is function, code below will be buggy (will not detect required fact)
|
|
838
964
|
for (const column of resource.columns) {
|
|
839
965
|
if (((_a = column.required) === null || _a === void 0 ? void 0 : _a.create) &&
|
|
840
966
|
record[column.name] === undefined &&
|
|
@@ -842,11 +968,29 @@ export default class AdminForthRestAPI {
|
|
|
842
968
|
return { error: `Column '${column.name}' is required`, ok: false };
|
|
843
969
|
}
|
|
844
970
|
}
|
|
971
|
+
const ctxCreate = {
|
|
972
|
+
adminUser,
|
|
973
|
+
resource,
|
|
974
|
+
meta: { requestBody: body },
|
|
975
|
+
source: ActionCheckSource.CreateRequest,
|
|
976
|
+
adminforth: this.adminforth,
|
|
977
|
+
};
|
|
978
|
+
for (const column of resource.columns) {
|
|
979
|
+
if ((_b = column.required) === null || _b === void 0 ? void 0 : _b.create) {
|
|
980
|
+
const shown = await isShown(column, 'create', ctxCreate);
|
|
981
|
+
if (shown && record[column.name] === undefined) {
|
|
982
|
+
return { error: `Column '${column.name}' is required`, ok: false };
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
845
986
|
for (const column of resource.columns) {
|
|
846
987
|
const fieldName = column.name;
|
|
847
988
|
if (fieldName in record) {
|
|
848
|
-
|
|
849
|
-
|
|
989
|
+
const shown = await isShown(column, 'create', ctxCreate); //
|
|
990
|
+
const bo = await isBackendOnly(column, ctxCreate);
|
|
991
|
+
const filledOnCreate = await isFilledOnCreate(column);
|
|
992
|
+
if ((!shown && !filledOnCreate) || bo) {
|
|
993
|
+
return { error: `Field "${fieldName}" cannot be modified as it is restricted from creation (backendOnly or showIn.create is false, please set it to true)`, ok: false };
|
|
850
994
|
}
|
|
851
995
|
}
|
|
852
996
|
}
|
|
@@ -890,7 +1034,7 @@ export default class AdminForthRestAPI {
|
|
|
890
1034
|
}
|
|
891
1035
|
const response = await this.adminforth.createResourceRecord({ resource, record, adminUser, extra: { body, query, headers, cookies, requestUrl } });
|
|
892
1036
|
if (response.error) {
|
|
893
|
-
return { error: response.error, ok: false };
|
|
1037
|
+
return { error: response.error, ok: false, newRecordId: response.newRecordId };
|
|
894
1038
|
}
|
|
895
1039
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
896
1040
|
return {
|
|
@@ -903,7 +1047,7 @@ export default class AdminForthRestAPI {
|
|
|
903
1047
|
method: 'POST',
|
|
904
1048
|
path: '/update_record',
|
|
905
1049
|
handler: async ({ body, adminUser, query, headers, cookies, requestUrl }) => {
|
|
906
|
-
var _a, _b
|
|
1050
|
+
var _a, _b;
|
|
907
1051
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
908
1052
|
if (!resource) {
|
|
909
1053
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -921,21 +1065,30 @@ export default class AdminForthRestAPI {
|
|
|
921
1065
|
if (!allowed) {
|
|
922
1066
|
return { error: allowedError };
|
|
923
1067
|
}
|
|
1068
|
+
const ctxEdit = {
|
|
1069
|
+
adminUser,
|
|
1070
|
+
resource,
|
|
1071
|
+
meta: { requestBody: body, newRecord: record, oldRecord, pk: recordId },
|
|
1072
|
+
source: ActionCheckSource.EditRequest,
|
|
1073
|
+
adminforth: this.adminforth,
|
|
1074
|
+
};
|
|
924
1075
|
for (const column of resource.columns) {
|
|
925
1076
|
const fieldName = column.name;
|
|
926
1077
|
if (fieldName in record) {
|
|
927
|
-
|
|
928
|
-
|
|
1078
|
+
const shown = await isShown(column, 'edit', ctxEdit);
|
|
1079
|
+
const bo = await isBackendOnly(column, ctxEdit);
|
|
1080
|
+
if (!shown || column.editReadonly || bo) {
|
|
1081
|
+
return { error: `Field "${fieldName}" cannot be modified as it is restricted from editing (backendOnly or showIn.edit is false, please set it to true)`, ok: false };
|
|
929
1082
|
}
|
|
930
1083
|
}
|
|
931
1084
|
}
|
|
932
1085
|
// for polymorphic foreign resources, we need to find out the value for polymorphicOn column
|
|
933
1086
|
for (const column of resource.columns) {
|
|
934
|
-
if (((
|
|
1087
|
+
if (((_a = column.foreignResource) === null || _a === void 0 ? void 0 : _a.polymorphicOn) && record[column.name] === null) {
|
|
935
1088
|
const systemResource = column.foreignResource.polymorphicResources.find(pr => pr.resourceId === null);
|
|
936
1089
|
record[column.foreignResource.polymorphicOn] = systemResource.whenValue;
|
|
937
1090
|
}
|
|
938
|
-
else if (((
|
|
1091
|
+
else if (((_b = column.foreignResource) === null || _b === void 0 ? void 0 : _b.polymorphicOn) && record[column.name]) {
|
|
939
1092
|
let newPolymorphicOnValue = null;
|
|
940
1093
|
if (record[column.name]) {
|
|
941
1094
|
const targetResources = {};
|
|
@@ -1047,7 +1200,7 @@ export default class AdminForthRestAPI {
|
|
|
1047
1200
|
method: 'POST',
|
|
1048
1201
|
path: '/start_custom_action',
|
|
1049
1202
|
handler: async ({ body, adminUser, tr }) => {
|
|
1050
|
-
const { resourceId, actionId, recordId } = body;
|
|
1203
|
+
const { resourceId, actionId, recordId, extra } = body;
|
|
1051
1204
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
|
|
1052
1205
|
if (!resource) {
|
|
1053
1206
|
return { error: await tr(`Resource {resourceId} not found`, 'errors', { resourceId }) };
|
|
@@ -1071,7 +1224,7 @@ export default class AdminForthRestAPI {
|
|
|
1071
1224
|
redirectUrl: action.url
|
|
1072
1225
|
};
|
|
1073
1226
|
}
|
|
1074
|
-
const response = await action.action({ recordId, adminUser, resource, tr, adminforth: this.adminforth });
|
|
1227
|
+
const response = await action.action({ recordId, adminUser, resource, tr, adminforth: this.adminforth, extra });
|
|
1075
1228
|
return Object.assign({ actionId,
|
|
1076
1229
|
recordId,
|
|
1077
1230
|
resourceId }, response);
|