adminforth 2.4.0-next.33 → 2.4.0-next.331
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 +209 -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 +199 -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 +132 -174
- package/dist/spa/src/adminforth.ts +41 -17
- 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 +3 -3
- 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 +99 -51
- package/dist/spa/src/components/ResourceListTable.vue +121 -95
- package/dist/spa/src/components/ResourceListTableVirtual.vue +119 -88
- 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 +15 -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 +109 -32
- package/dist/spa/src/types/FrontendAPI.ts +32 -23
- 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 +88 -22
- 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 +123 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +32 -18
- 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
|
@@ -16,6 +16,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
16
16
|
const record: Ref<any | null> = ref({});
|
|
17
17
|
const resource: Ref<AdminForthResourceCommon | null> = ref(null);
|
|
18
18
|
const userData: Ref<UserData | null> = ref(null);
|
|
19
|
+
const isResourceFetching = ref(false);
|
|
19
20
|
|
|
20
21
|
const resourceColumnsWithFilters = computed(() => {
|
|
21
22
|
if (!resource.value) {
|
|
@@ -118,7 +119,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
118
119
|
item.badge = badge;
|
|
119
120
|
}
|
|
120
121
|
});
|
|
121
|
-
|
|
122
|
+
websocket.unsubscribeAll();
|
|
122
123
|
subscribeToMenuBadges();
|
|
123
124
|
|
|
124
125
|
}
|
|
@@ -172,6 +173,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
172
173
|
// already fetched
|
|
173
174
|
return;
|
|
174
175
|
}
|
|
176
|
+
isResourceFetching.value = true;
|
|
175
177
|
resourceColumnsId.value = resourceId;
|
|
176
178
|
resourceColumnsError.value = '';
|
|
177
179
|
const res = await callAdminForthApi({
|
|
@@ -188,6 +190,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
188
190
|
resource.value = res.resource;
|
|
189
191
|
resourceOptions.value = res.resource.options;
|
|
190
192
|
}
|
|
193
|
+
isResourceFetching.value = false;
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
async function getPublicConfig() {
|
|
@@ -195,9 +198,18 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
195
198
|
path: '/get_public_config',
|
|
196
199
|
method: 'GET',
|
|
197
200
|
});
|
|
201
|
+
console.log('📦 getPublicConfig', res);
|
|
198
202
|
config.value = {...config.value, ...res};
|
|
199
203
|
}
|
|
200
204
|
|
|
205
|
+
async function getLoginFormConfig() {
|
|
206
|
+
const res = await callAdminForthApi({
|
|
207
|
+
path: '/get_login_form_config',
|
|
208
|
+
method: 'GET',
|
|
209
|
+
});
|
|
210
|
+
console.log('📦 getLoginFormConfig', res);
|
|
211
|
+
config.value = {...config.value, ...res};
|
|
212
|
+
}
|
|
201
213
|
|
|
202
214
|
const username = computed(() => {
|
|
203
215
|
const usernameField = config.value?.usernameField;
|
|
@@ -218,6 +230,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
218
230
|
userFullname,
|
|
219
231
|
getPublicConfig,
|
|
220
232
|
fetchMenuAndResource,
|
|
233
|
+
getLoginFormConfig,
|
|
221
234
|
fetchRecord,
|
|
222
235
|
record,
|
|
223
236
|
fetchResourceFull,
|
|
@@ -231,5 +244,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
231
244
|
fetchMenuBadges,
|
|
232
245
|
resetAdminUser,
|
|
233
246
|
resetResource,
|
|
247
|
+
isResourceFetching,
|
|
234
248
|
}
|
|
235
249
|
})
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { ref, type Ref } from 'vue';
|
|
1
|
+
import { ref, computed, type Ref } from 'vue';
|
|
2
2
|
import { defineStore } from 'pinia';
|
|
3
|
+
import { useCoreStore } from './core';
|
|
3
4
|
|
|
4
5
|
export const useFiltersStore = defineStore('filters', () => {
|
|
5
6
|
const filters: Ref<any[]> = ref([]);
|
|
6
7
|
const sort: Ref<any> = ref({});
|
|
8
|
+
const coreStore = useCoreStore();
|
|
7
9
|
|
|
8
10
|
const setSort = (s: any) => {
|
|
9
11
|
sort.value = s;
|
|
@@ -20,8 +22,37 @@ export const useFiltersStore = defineStore('filters', () => {
|
|
|
20
22
|
const getFilters = () => {
|
|
21
23
|
return filters.value;
|
|
22
24
|
}
|
|
25
|
+
const clearFilter = (fieldName: string) => {
|
|
26
|
+
filters.value = filters.value.filter(f => f.field !== fieldName);
|
|
27
|
+
}
|
|
23
28
|
const clearFilters = () => {
|
|
24
29
|
filters.value = [];
|
|
25
30
|
}
|
|
26
|
-
|
|
31
|
+
|
|
32
|
+
const shouldFilterBeHidden = (fieldName: string) => {
|
|
33
|
+
if (coreStore.resource?.columns) {
|
|
34
|
+
const column = coreStore.resource.columns.find((col: any) => col.name === fieldName);
|
|
35
|
+
if (column?.showIn?.filter !== true) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const visibleFiltersCount = computed(() => {
|
|
43
|
+
return filters.value.filter(f => !shouldFilterBeHidden(f.field)).length;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
setFilter,
|
|
48
|
+
getFilters,
|
|
49
|
+
clearFilters,
|
|
50
|
+
filters,
|
|
51
|
+
setFilters,
|
|
52
|
+
setSort,
|
|
53
|
+
getSort,
|
|
54
|
+
visibleFiltersCount,
|
|
55
|
+
shouldFilterBeHidden,
|
|
56
|
+
clearFilter
|
|
57
|
+
}
|
|
27
58
|
})
|
|
@@ -29,7 +29,12 @@ export const useModalStore = defineStore('modal', () => {
|
|
|
29
29
|
onCancelFunction.value = func;
|
|
30
30
|
}
|
|
31
31
|
function setModalContent(content: ModalContentType) {
|
|
32
|
-
modalContent.value =
|
|
32
|
+
modalContent.value = {
|
|
33
|
+
title: content.title || 'title',
|
|
34
|
+
content: content.content || 'content',
|
|
35
|
+
acceptText: content.acceptText || 'acceptText',
|
|
36
|
+
cancelText: content.cancelText || 'cancelText',
|
|
37
|
+
};
|
|
33
38
|
}
|
|
34
39
|
function resetmodalState() {
|
|
35
40
|
isOpened.value = false;
|
|
@@ -12,19 +12,38 @@ export const useToastStore = defineStore('toast', () => {
|
|
|
12
12
|
watch(route, () => {
|
|
13
13
|
// on route change clear all toasts older then 5 seconds
|
|
14
14
|
const now = +new Date();
|
|
15
|
-
toasts.value = toasts.value.filter((t) => now - t.createdAt < 5000);
|
|
15
|
+
toasts.value = toasts.value.filter((t) => t?.timeout === 'unlimited' || now - t.createdAt < 5000);
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
const addToast = (toast: {
|
|
18
|
+
const addToast = (toast: {
|
|
19
|
+
message?: string;
|
|
20
|
+
messageHtml?: string;
|
|
21
|
+
variant: string;
|
|
22
|
+
timeout?: number | 'unlimited';
|
|
23
|
+
buttons?: { value: any; label: string }[];
|
|
24
|
+
onResolve?: (value?: any) => void;
|
|
25
|
+
}): string => {
|
|
19
26
|
const toastId = uuid();
|
|
20
27
|
toasts.value.push({
|
|
21
28
|
...toast,
|
|
22
29
|
id: toastId,
|
|
23
30
|
createdAt: +new Date(),
|
|
24
31
|
});
|
|
32
|
+
return toastId;
|
|
25
33
|
};
|
|
26
34
|
const removeToast = (toast: { id: string }) => {
|
|
27
35
|
toasts.value = toasts.value.filter((t) => t.id !== toast.id);
|
|
28
36
|
};
|
|
29
|
-
|
|
37
|
+
|
|
38
|
+
const resolveToast = (toastId: string, value?: any) => {
|
|
39
|
+
const t = toasts.value.find((x) => x.id === toastId);
|
|
40
|
+
try {
|
|
41
|
+
t?.onResolve?.(value);
|
|
42
|
+
} catch {
|
|
43
|
+
// no-op
|
|
44
|
+
}
|
|
45
|
+
toasts.value = toasts.value.filter((x) => x.id !== toastId);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return { toasts, addToast, removeToast, resolveToast };
|
|
30
49
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Express } from 'express';
|
|
1
|
+
import type { Express, Request } from 'express';
|
|
2
2
|
import type { Writable } from 'stream';
|
|
3
3
|
|
|
4
4
|
import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum,
|
|
@@ -8,12 +8,12 @@ import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections,
|
|
|
8
8
|
type AdminForthBulkActionCommon,
|
|
9
9
|
type AdminForthForeignResourceCommon,
|
|
10
10
|
type AdminForthResourceColumnCommon,
|
|
11
|
-
AdminForthResourceInputCommon,
|
|
12
|
-
AdminForthComponentDeclarationFull,
|
|
13
|
-
AdminForthConfigMenuItem,
|
|
14
|
-
AnnouncementBadgeResponse,
|
|
11
|
+
type AdminForthResourceInputCommon,
|
|
12
|
+
type AdminForthComponentDeclarationFull,
|
|
13
|
+
type AdminForthConfigMenuItem,
|
|
14
|
+
type AnnouncementBadgeResponse,
|
|
15
15
|
AdminForthResourcePages,
|
|
16
|
-
AdminForthResourceColumnInputCommon,
|
|
16
|
+
type AdminForthResourceColumnInputCommon,
|
|
17
17
|
} from './Common.js';
|
|
18
18
|
|
|
19
19
|
export interface ICodeInjector {
|
|
@@ -22,12 +22,13 @@ export interface ICodeInjector {
|
|
|
22
22
|
devServerPort: number;
|
|
23
23
|
|
|
24
24
|
getServeDir(): string;
|
|
25
|
-
|
|
25
|
+
registerCustomComponent(filePath: string): void;
|
|
26
26
|
spaTmpPath(): string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export interface IConfigValidator {
|
|
30
30
|
validateConfig(): void;
|
|
31
|
+
validateAfterPluginsActivation(): void;
|
|
31
32
|
postProcessAfterDiscover(resource: AdminForthResource): void;
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -92,19 +93,36 @@ export interface IExpressHttpServer extends IHttpServer {
|
|
|
92
93
|
* Adds adminUser to request object if user is authorized. Drops request with 401 status if user is not authorized.
|
|
93
94
|
* @param callable : Function which will be called if user is authorized.
|
|
94
95
|
*
|
|
95
|
-
* Example:
|
|
96
96
|
*
|
|
97
|
+
* @example
|
|
97
98
|
* ```ts
|
|
98
|
-
* expressApp.get('/myApi', authorize((req, res) =>
|
|
99
|
+
* expressApp.get('/myApi', authorize((req, res) => {
|
|
99
100
|
* console.log('User is authorized', req.adminUser);
|
|
100
|
-
* res.json(
|
|
101
|
-
*
|
|
102
|
-
*
|
|
101
|
+
* res.json({ message: 'Hello World' });
|
|
102
|
+
* }));
|
|
103
|
+
* ```
|
|
103
104
|
*
|
|
104
|
-
*/
|
|
105
|
+
*/
|
|
105
106
|
authorize(callable: Function): void;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
export interface ITranslateFunction {
|
|
110
|
+
(
|
|
111
|
+
msg: string,
|
|
112
|
+
category: string,
|
|
113
|
+
params: any,
|
|
114
|
+
pluralizationNumber?: number
|
|
115
|
+
): Promise<string>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Omit <Request, 'param'> is used to remove 'param' method from Request type for correct docs generation
|
|
119
|
+
export interface IAdminUserExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
120
|
+
adminUser: AdminUser;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface ITranslateExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
124
|
+
tr: ITranslateFunction;
|
|
125
|
+
}
|
|
108
126
|
|
|
109
127
|
export interface IAdminForthSingleFilter {
|
|
110
128
|
field?: string;
|
|
@@ -113,7 +131,9 @@ export interface IAdminForthSingleFilter {
|
|
|
113
131
|
| AdminForthFilterOperators.LTE | AdminForthFilterOperators.LIKE | AdminForthFilterOperators.ILIKE
|
|
114
132
|
| AdminForthFilterOperators.IN | AdminForthFilterOperators.NIN;
|
|
115
133
|
value?: any;
|
|
134
|
+
rightField?: string;
|
|
116
135
|
insecureRawSQL?: string;
|
|
136
|
+
insecureRawNoSQL?: any;
|
|
117
137
|
}
|
|
118
138
|
export interface IAdminForthAndOrFilter {
|
|
119
139
|
operator: AdminForthFilterOperators.AND | AdminForthFilterOperators.OR;
|
|
@@ -287,6 +307,10 @@ export interface IAdminForthAuth {
|
|
|
287
307
|
|
|
288
308
|
removeCustomCookie({response, name}: {response: any, name: string}): void;
|
|
289
309
|
|
|
310
|
+
setCustomCookie({response, payload}: {response: any, payload: {name: string, value: string, expiry: number, expirySeconds: number, httpOnly: boolean}}): void;
|
|
311
|
+
|
|
312
|
+
getCustomCookie({cookies, name}: {cookies: {key: string, value: string}[], name: string}): string | null;
|
|
313
|
+
|
|
290
314
|
setAuthCookie({expireInDays, response, username, pk,}: {expireInDays?: number, response: any, username: string, pk: string}): void;
|
|
291
315
|
|
|
292
316
|
removeAuthCookie(response: any): void;
|
|
@@ -336,10 +360,11 @@ export interface IAdminForth {
|
|
|
336
360
|
|
|
337
361
|
createResourceRecord(
|
|
338
362
|
params: { resource: AdminForthResource, record: any, adminUser: AdminUser, extra?: HttpExtra }
|
|
339
|
-
): Promise<{ error?: string, createdRecord?: any }>;
|
|
363
|
+
): Promise<{ error?: string, createdRecord?: any, newRecordId?: any }>;
|
|
340
364
|
|
|
341
365
|
updateResourceRecord(
|
|
342
|
-
params: { resource: AdminForthResource, recordId: any, record: any, oldRecord: any, adminUser: AdminUser, extra?: HttpExtra }
|
|
366
|
+
params: { resource: AdminForthResource, recordId: any, record: any, oldRecord: any, adminUser: AdminUser, extra?: HttpExtra, updates?: never }
|
|
367
|
+
| { resource: AdminForthResource, recordId: any, record?: never, oldRecord: any, adminUser: AdminUser, extra?: HttpExtra, updates: any }
|
|
343
368
|
): Promise<{ error?: string }>;
|
|
344
369
|
|
|
345
370
|
deleteResourceRecord(
|
|
@@ -474,7 +499,7 @@ export type BeforeDataSourceRequestFunction = (params: {
|
|
|
474
499
|
requestUrl: string,
|
|
475
500
|
},
|
|
476
501
|
adminforth: IAdminForth,
|
|
477
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
502
|
+
}) => Promise<{ok: boolean, error?: string, newRecordId?: string}>;
|
|
478
503
|
|
|
479
504
|
/**
|
|
480
505
|
* Modify response to change how data is returned after fetching from database.
|
|
@@ -525,7 +550,7 @@ export type BeforeEditSaveFunction = (params: {
|
|
|
525
550
|
oldRecord: any,
|
|
526
551
|
adminforth: IAdminForth,
|
|
527
552
|
extra?: HttpExtra,
|
|
528
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
553
|
+
}) => Promise<{ok: boolean, error?: string | null}>;
|
|
529
554
|
|
|
530
555
|
|
|
531
556
|
|
|
@@ -535,7 +560,7 @@ export type BeforeCreateSaveFunction = (params: {
|
|
|
535
560
|
record: any,
|
|
536
561
|
adminforth: IAdminForth,
|
|
537
562
|
extra?: HttpExtra,
|
|
538
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
563
|
+
}) => Promise<{ok: boolean, error?: string | null, newRecordId?: string}>;
|
|
539
564
|
|
|
540
565
|
export type AfterCreateSaveFunction = (params: {
|
|
541
566
|
resource: AdminForthResource,
|
|
@@ -543,6 +568,7 @@ export type AfterCreateSaveFunction = (params: {
|
|
|
543
568
|
adminUser: AdminUser,
|
|
544
569
|
record: any,
|
|
545
570
|
adminforth: IAdminForth,
|
|
571
|
+
recordWithVirtualColumns?: any,
|
|
546
572
|
extra?: HttpExtra,
|
|
547
573
|
}) => Promise<{ok: boolean, error?: string}>;
|
|
548
574
|
|
|
@@ -579,6 +605,7 @@ export type BeforeLoginConfirmationFunction = (params?: {
|
|
|
579
605
|
response: IAdminForthHttpResponse,
|
|
580
606
|
adminforth: IAdminForth,
|
|
581
607
|
extra?: HttpExtra,
|
|
608
|
+
rememberMeDays?: number,
|
|
582
609
|
}) => Promise<{
|
|
583
610
|
error?: string,
|
|
584
611
|
body: {
|
|
@@ -587,6 +614,19 @@ export type BeforeLoginConfirmationFunction = (params?: {
|
|
|
587
614
|
}
|
|
588
615
|
}>;
|
|
589
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Allow to make extra authorization
|
|
619
|
+
*/
|
|
620
|
+
export type AdminUserAuthorizeFunction = ((params?: {
|
|
621
|
+
adminUser: AdminUser,
|
|
622
|
+
response: IAdminForthHttpResponse,
|
|
623
|
+
adminforth: IAdminForth,
|
|
624
|
+
extra?: HttpExtra,
|
|
625
|
+
}) => Promise<{
|
|
626
|
+
error?: string,
|
|
627
|
+
allowed?: boolean,
|
|
628
|
+
}>);
|
|
629
|
+
|
|
590
630
|
|
|
591
631
|
/**
|
|
592
632
|
* Data source describes database connection which will be used to fetch data for resources.
|
|
@@ -619,12 +659,23 @@ interface AdminForthInputConfigCustomization {
|
|
|
619
659
|
*/
|
|
620
660
|
brandName?: string,
|
|
621
661
|
|
|
662
|
+
/**
|
|
663
|
+
* Whether to use single theme for the app
|
|
664
|
+
*/
|
|
665
|
+
singleTheme?: 'light' | 'dark',
|
|
666
|
+
|
|
622
667
|
/**
|
|
623
668
|
* Whether to show brand name in sidebar
|
|
624
669
|
* default is true
|
|
625
670
|
*/
|
|
626
671
|
showBrandNameInSidebar?: boolean,
|
|
627
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Whether to show brand logo in sidebar
|
|
675
|
+
* default is true
|
|
676
|
+
*/
|
|
677
|
+
showBrandLogoInSidebar?: boolean,
|
|
678
|
+
|
|
628
679
|
/**
|
|
629
680
|
* Path to your app logo
|
|
630
681
|
*
|
|
@@ -638,6 +689,23 @@ interface AdminForthInputConfigCustomization {
|
|
|
638
689
|
*/
|
|
639
690
|
brandLogo?: string,
|
|
640
691
|
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Path to your app logo for icon only sidebar
|
|
695
|
+
*
|
|
696
|
+
* Example:
|
|
697
|
+
* Place file `logo.svg` to `./custom` folder and set this option:
|
|
698
|
+
*
|
|
699
|
+
*/
|
|
700
|
+
iconOnlySidebar?: {
|
|
701
|
+
logo?: string,
|
|
702
|
+
enabled?: boolean,
|
|
703
|
+
/**
|
|
704
|
+
* Width of expanded sidebar (default: '16.5rem')
|
|
705
|
+
*/
|
|
706
|
+
expandedSidebarWidth?: string,
|
|
707
|
+
},
|
|
708
|
+
|
|
641
709
|
/**
|
|
642
710
|
* Path to your app favicon
|
|
643
711
|
*
|
|
@@ -747,6 +815,7 @@ interface AdminForthInputConfigCustomization {
|
|
|
747
815
|
*/
|
|
748
816
|
loginPageInjections?: {
|
|
749
817
|
underInputs?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
818
|
+
underLoginButton?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
750
819
|
panelHeader?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
751
820
|
}
|
|
752
821
|
|
|
@@ -757,8 +826,20 @@ interface AdminForthInputConfigCustomization {
|
|
|
757
826
|
userMenu?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
758
827
|
header?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
759
828
|
sidebar?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
829
|
+
sidebarTop?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
760
830
|
everyPageBottom?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
761
831
|
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Allows adding custom elements (e.g., <link>, <script>, <meta>) to the <head> of the HTML document.
|
|
835
|
+
* Each item must include a tag name and a set of attributes.
|
|
836
|
+
*/
|
|
837
|
+
customHeadItems?: {
|
|
838
|
+
tagName: string;
|
|
839
|
+
attributes: Record<string, string | boolean>;
|
|
840
|
+
innerCode?: string;
|
|
841
|
+
}[];
|
|
842
|
+
|
|
762
843
|
}
|
|
763
844
|
|
|
764
845
|
export interface AdminForthActionInput {
|
|
@@ -787,6 +868,7 @@ export interface AdminForthActionInput {
|
|
|
787
868
|
}>;
|
|
788
869
|
icon?: string;
|
|
789
870
|
id?: string;
|
|
871
|
+
customComponent?: AdminForthComponentDeclaration;
|
|
790
872
|
}
|
|
791
873
|
|
|
792
874
|
export interface AdminForthResourceInput extends Omit<NonNullable<AdminForthResourceInputCommon>, 'columns' | 'hooks' | 'options'> {
|
|
@@ -935,12 +1017,24 @@ export interface AdminForthInputConfig {
|
|
|
935
1017
|
*/
|
|
936
1018
|
loginBackgroundPosition?: 'over' | '1/2' | '1/3' | '2/3' | '3/4' | '2/5' | '3/5',
|
|
937
1019
|
|
|
1020
|
+
/**
|
|
1021
|
+
* If true, background blend mode will be removed from login background image when position is 'over'
|
|
1022
|
+
*
|
|
1023
|
+
* Default: false
|
|
1024
|
+
*/
|
|
1025
|
+
removeBackgroundBlendMode?: boolean,
|
|
1026
|
+
|
|
938
1027
|
/**
|
|
939
1028
|
* Function or functions which will be called before user try to login.
|
|
940
1029
|
* Each function will resive User object as an argument
|
|
941
1030
|
*/
|
|
942
1031
|
beforeLoginConfirmation?: BeforeLoginConfirmationFunction | Array<BeforeLoginConfirmationFunction>,
|
|
943
1032
|
|
|
1033
|
+
/**
|
|
1034
|
+
* Array of functions which will be called before any request to AdminForth API.
|
|
1035
|
+
*/
|
|
1036
|
+
adminUserAuthorize?: AdminUserAuthorizeFunction | Array<AdminUserAuthorizeFunction>,
|
|
1037
|
+
|
|
944
1038
|
/**
|
|
945
1039
|
* Optionally if your users table has a field(column) with full name, you can set it here.
|
|
946
1040
|
* This field will be used to display user name in the top right corner of the admin panel.
|
|
@@ -956,7 +1050,7 @@ export interface AdminForthInputConfig {
|
|
|
956
1050
|
/**
|
|
957
1051
|
* Any prompt to show users on login. Supports HTML.
|
|
958
1052
|
*/
|
|
959
|
-
loginPromptHTML?: string
|
|
1053
|
+
loginPromptHTML?: string | (() => string | void | undefined | Promise<string | void | undefined>) | undefined
|
|
960
1054
|
|
|
961
1055
|
/**
|
|
962
1056
|
* Remember me days for "Remember Me" checkbox on login page.
|
|
@@ -988,6 +1082,17 @@ export interface AdminForthInputConfig {
|
|
|
988
1082
|
* If you are using Cloudflare, set this to 'CF-Connecting-IP'. Case-insensitive.
|
|
989
1083
|
*/
|
|
990
1084
|
clientIpHeader?: string,
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Add custom page to the settings page
|
|
1088
|
+
*/
|
|
1089
|
+
userMenuSettingsPages: {
|
|
1090
|
+
icon?: string,
|
|
1091
|
+
pageLabel: string,
|
|
1092
|
+
slug?: string,
|
|
1093
|
+
component: string,
|
|
1094
|
+
isVisible?: (adminUser: AdminUser) => boolean,
|
|
1095
|
+
}[],
|
|
991
1096
|
},
|
|
992
1097
|
|
|
993
1098
|
/**
|
|
@@ -1055,6 +1160,7 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
|
|
|
1055
1160
|
|
|
1056
1161
|
loginPageInjections: {
|
|
1057
1162
|
underInputs: Array<AdminForthComponentDeclarationFull>,
|
|
1163
|
+
underLoginButton?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
1058
1164
|
panelHeader: Array<AdminForthComponentDeclarationFull>,
|
|
1059
1165
|
},
|
|
1060
1166
|
|
|
@@ -1062,8 +1168,16 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
|
|
|
1062
1168
|
userMenu: Array<AdminForthComponentDeclarationFull>,
|
|
1063
1169
|
header: Array<AdminForthComponentDeclarationFull>,
|
|
1064
1170
|
sidebar: Array<AdminForthComponentDeclarationFull>,
|
|
1171
|
+
sidebarTop: Array<AdminForthComponentDeclarationFull>,
|
|
1065
1172
|
everyPageBottom: Array<AdminForthComponentDeclarationFull>,
|
|
1066
1173
|
},
|
|
1174
|
+
|
|
1175
|
+
customHeadItems?: {
|
|
1176
|
+
tagName: string;
|
|
1177
|
+
attributes: Record<string, string | boolean>;
|
|
1178
|
+
innerCode?: string;
|
|
1179
|
+
}[];
|
|
1180
|
+
|
|
1067
1181
|
}
|
|
1068
1182
|
|
|
1069
1183
|
export interface AdminForthConfig extends Omit<AdminForthInputConfig, 'customization' | 'resources'> {
|
|
@@ -1111,6 +1225,21 @@ export class Filters {
|
|
|
1111
1225
|
static LIKE(field: string, value: any): IAdminForthSingleFilter {
|
|
1112
1226
|
return { field, operator: AdminForthFilterOperators.LIKE, value };
|
|
1113
1227
|
}
|
|
1228
|
+
static ILIKE(field: string, value: any): IAdminForthSingleFilter {
|
|
1229
|
+
return { field, operator: AdminForthFilterOperators.ILIKE, value };
|
|
1230
|
+
}
|
|
1231
|
+
static GT_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter {
|
|
1232
|
+
return { field: leftField, operator: AdminForthFilterOperators.GT, rightField };
|
|
1233
|
+
}
|
|
1234
|
+
static GTE_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter {
|
|
1235
|
+
return { field: leftField, operator: AdminForthFilterOperators.GTE, rightField };
|
|
1236
|
+
}
|
|
1237
|
+
static LT_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter {
|
|
1238
|
+
return { field: leftField, operator: AdminForthFilterOperators.LT, rightField };
|
|
1239
|
+
}
|
|
1240
|
+
static LTE_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter {
|
|
1241
|
+
return { field: leftField, operator: AdminForthFilterOperators.LTE, rightField };
|
|
1242
|
+
}
|
|
1114
1243
|
static AND(
|
|
1115
1244
|
...args: (IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter>)[]
|
|
1116
1245
|
): IAdminForthAndOrFilter {
|
|
@@ -1318,9 +1447,13 @@ export interface AdminForthResource extends Omit<AdminForthResourceInput, 'optio
|
|
|
1318
1447
|
},
|
|
1319
1448
|
create?: {
|
|
1320
1449
|
/**
|
|
1450
|
+
* Should return `ok: true` to continue saving pipeline and allow creating record in database, and `ok: false` to interrupt pipeline and prevent record creation.
|
|
1451
|
+
* If you need to show error on UI, set `error: \<error message\>` in response.
|
|
1452
|
+
*
|
|
1321
1453
|
* Typical use-cases:
|
|
1322
|
-
* -
|
|
1323
|
-
* -
|
|
1454
|
+
* - Create record by custom code (return `{ ok: false, newRecordId: <id of created record from custom code> }`)
|
|
1455
|
+
* - Validate record before saving to database and interrupt execution if validation failed (return `{ ok: false, error: <validation error> }`), though `allowedActions.create` should be preferred in most cases
|
|
1456
|
+
* - fill-in adminUser as creator of record (set `record.<some field> = x; return \{ ok: true \}`)
|
|
1324
1457
|
* - Attach additional data to record before saving to database (mostly fillOnCreate should be used instead)
|
|
1325
1458
|
*/
|
|
1326
1459
|
beforeSave?: Array<BeforeCreateSaveFunction>,
|
|
@@ -1471,15 +1604,27 @@ export type ShowInInput = ShowInModernInput | ShowInLegacyInput;
|
|
|
1471
1604
|
export type ShowIn = {
|
|
1472
1605
|
[key in AdminForthResourcePages]: AllowedActionValue
|
|
1473
1606
|
}
|
|
1607
|
+
export type BackendOnlyInput =
|
|
1608
|
+
| boolean
|
|
1609
|
+
| ((p: {
|
|
1610
|
+
adminUser: AdminUser;
|
|
1611
|
+
resource: AdminForthResource;
|
|
1612
|
+
meta: any;
|
|
1613
|
+
source: ActionCheckSource;
|
|
1614
|
+
adminforth: IAdminForth;
|
|
1615
|
+
}) => boolean | Promise<boolean>);
|
|
1616
|
+
|
|
1474
1617
|
|
|
1475
|
-
export interface AdminForthResourceColumnInput extends Omit<AdminForthResourceColumnInputCommon, 'showIn'> {
|
|
1618
|
+
export interface AdminForthResourceColumnInput extends Omit<AdminForthResourceColumnInputCommon, 'showIn' | 'backendOnly'> {
|
|
1476
1619
|
showIn?: ShowInInput,
|
|
1477
1620
|
foreignResource?: AdminForthForeignResource,
|
|
1621
|
+
backendOnly?: BackendOnlyInput;
|
|
1478
1622
|
}
|
|
1479
1623
|
|
|
1480
|
-
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn'> {
|
|
1624
|
+
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn' | 'backendOnly'> {
|
|
1481
1625
|
showIn?: ShowIn,
|
|
1482
1626
|
foreignResource?: AdminForthForeignResource,
|
|
1627
|
+
backendOnly?: BackendOnlyInput;
|
|
1483
1628
|
}
|
|
1484
1629
|
|
|
1485
1630
|
export interface IWebSocketClient {
|