adminforth 1.1.59 → 1.1.61
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/dist/index.js +68 -63
- package/dist/modules/styleGenerator.js +22 -18
- package/dist/modules/styles.js +44 -36
- package/dist/modules/utils.js +75 -0
- package/dist/plugins/AccessControl/index.js +66 -0
- package/dist/plugins/AccessControl/types.js +1 -0
- package/dist/plugins/AuditLogPlugin/custom/AuditLogView.vue +20 -0
- package/dist/plugins/AuditLogPlugin/index.js +83 -0
- package/dist/plugins/AuditLogPlugin/types.js +1 -0
- package/dist/spa/index.html +2 -2
- package/dist/spa/package-lock.json +4 -17
- package/dist/spa/package.json +1 -2
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/package-lock.json +111 -0
- package/dist/spa/spa/package.json +1 -0
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/App.vue +4 -4
- package/dist/spa/spa/src/components/MenuLink.vue +1 -1
- package/dist/spa/spa/src/components/ResourceForm.vue +2 -2
- package/dist/spa/src/App.vue +45 -125
- package/dist/spa/src/assets/logo.svg +1 -19
- package/dist/spa/src/components/AcceptModal.vue +9 -2
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +3 -16
- package/dist/spa/src/components/CustomDateRangePicker.vue +2 -11
- package/dist/spa/src/components/Dropdown.vue +1 -6
- package/dist/spa/src/components/Filters.vue +19 -40
- package/dist/spa/src/components/ResourceForm.vue +24 -26
- package/dist/spa/src/components/ValueRenderer.vue +8 -14
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/router/index.ts +20 -30
- package/dist/spa/src/stores/core.ts +31 -48
- package/dist/spa/src/stores/modal.ts +3 -13
- package/dist/spa/src/utils.ts +7 -62
- package/dist/spa/src/views/CreateView.vue +15 -67
- package/dist/spa/src/views/EditView.vue +11 -45
- package/dist/spa/src/views/ListView.vue +366 -82
- package/dist/spa/src/views/LoginView.vue +4 -16
- package/dist/spa/src/views/ShowView.vue +21 -105
- package/dist/spa/tailwind.config.js +1 -1
- package/dist/spa/vite.config.ts +0 -6
- package/dist/types.js +30 -0
- package/index.ts +62 -61
- package/modules/styleGenerator.ts +25 -18
- package/modules/styles.ts +46 -36
- package/modules/utils.ts +91 -1
- package/package.json +2 -1
- package/plugins/AuditLogPlugin/custom/AuditLogView.vue +20 -0
- package/plugins/AuditLogPlugin/index.ts +99 -0
- package/plugins/AuditLogPlugin/types.ts +40 -0
- package/spa/package-lock.json +111 -0
- package/spa/package.json +1 -0
- package/spa/src/App.vue +4 -4
- package/spa/src/components/MenuLink.vue +1 -1
- package/spa/src/components/ResourceForm.vue +2 -2
- package/types/AdminForthConfig.ts +6 -1
- package/dist/spa/src/components/ResourceListTable.vue +0 -419
- package/dist/spa/src/components/Toast.vue +0 -66
- package/dist/spa/src/composables/useFrontendApi.ts +0 -26
- package/dist/spa/src/composables/useStores.ts +0 -113
- package/dist/spa/src/spa_types/core.ts +0 -51
- package/dist/spa/src/stores/filters.ts +0 -22
- package/dist/spa/src/stores/toast.ts +0 -15
- package/dist/spa/src/stores/user.ts +0 -54
- package/plugins/AuditLog/index.ts +0 -29
- package/plugins/AuditLog/types.ts +0 -4
- /package/dist/spa/{public/assets → spa/public}/favicon.png +0 -0
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
-
<component
|
|
4
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.beforeBreadcrumbs || []"
|
|
5
|
-
:is="getCustomComponent(c)"
|
|
6
|
-
:meta="c.meta"
|
|
7
|
-
:record="coreStore.record"
|
|
8
|
-
:resource="coreStore.resource"
|
|
9
|
-
:adminUser="coreStore.adminUser"
|
|
10
|
-
/>
|
|
11
3
|
<BreadcrumbsWithButtons>
|
|
12
|
-
<RouterLink
|
|
13
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded
|
|
4
|
+
<RouterLink :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
5
|
+
class="flex items-center py-1 px-3 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
14
6
|
>
|
|
15
7
|
<IconPenSolid class="w-4 h-4" />
|
|
16
8
|
Edit
|
|
17
9
|
</RouterLink>
|
|
18
10
|
|
|
19
|
-
<button
|
|
20
|
-
class="flex items-center py-1 px-3 text-sm font-medium
|
|
11
|
+
<button @click="deleteRecord"
|
|
12
|
+
class="flex items-center py-1 px-3 mb-2 text-sm font-medium text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
21
13
|
>
|
|
22
14
|
<IconTrashBinSolid class="w-4 h-4" />
|
|
23
15
|
Delete
|
|
24
16
|
</button>
|
|
25
17
|
</BreadcrumbsWithButtons>
|
|
26
18
|
|
|
27
|
-
<component
|
|
28
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
29
|
-
:is="getCustomComponent(c)"
|
|
30
|
-
:meta="c.meta"
|
|
31
|
-
:record="coreStore.record"
|
|
32
|
-
:resource="coreStore.resource"
|
|
33
|
-
:adminUser="coreStore.adminUser"
|
|
34
|
-
/>
|
|
35
|
-
|
|
36
19
|
<div v-if="loading" role="status" class="max-w-sm animate-pulse">
|
|
37
20
|
<div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4"></div>
|
|
38
21
|
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
|
|
@@ -46,7 +29,7 @@
|
|
|
46
29
|
v-else
|
|
47
30
|
class="relative overflow-x-auto shadow-resourse-form-shadow "
|
|
48
31
|
>
|
|
49
|
-
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400
|
|
32
|
+
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
|
50
33
|
<thead class="text-xs text-gray-700 uppercase bg-form-view-heading dark:bg-gray-700 dark:text-gray-400">
|
|
51
34
|
<tr>
|
|
52
35
|
<th scope="col" class="px-6 py-3">
|
|
@@ -58,49 +41,23 @@
|
|
|
58
41
|
</tr>
|
|
59
42
|
</thead>
|
|
60
43
|
<tbody>
|
|
61
|
-
<tr v-for="column in coreStore.
|
|
44
|
+
<tr v-for="column in coreStore.resourceColumns?.filter(c => c.showIn.includes('show'))" :key="column.name"
|
|
62
45
|
class="bg-form-view-bg odd:dark:bg-gray-900 even:dark:bg-gray-800 border-b dark:border-gray-700"
|
|
63
46
|
>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
:is="getCustomComponent(column.components.showRow)"
|
|
67
|
-
:meta="column.components.showRow.meta"
|
|
68
|
-
:column="column"
|
|
69
|
-
:resource="coreStore.resource"
|
|
70
|
-
:record="coreStore.record"
|
|
71
|
-
/>
|
|
72
|
-
<template v-else>
|
|
73
|
-
<td class="px-6 py-4 whitespace-nowrap "> <!--align-top-->
|
|
74
|
-
{{ column.label }}
|
|
47
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
48
|
+
{{ column.label }}
|
|
75
49
|
</td>
|
|
76
50
|
<td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
:column="column"
|
|
83
|
-
:record="coreStore.record"
|
|
84
|
-
/>
|
|
85
|
-
<ValueRenderer v-else
|
|
86
|
-
:column="column"
|
|
87
|
-
:record="coreStore.record"
|
|
88
|
-
/>
|
|
51
|
+
<component
|
|
52
|
+
:is="showComponentsPerColumn[column.name] || ValueRenderer"
|
|
53
|
+
:column="column"
|
|
54
|
+
:row="coreStore.record"
|
|
55
|
+
/>
|
|
89
56
|
</td>
|
|
90
|
-
</template>
|
|
91
57
|
</tr>
|
|
58
|
+
|
|
92
59
|
</tbody>
|
|
93
60
|
</table>
|
|
94
|
-
|
|
95
|
-
<component
|
|
96
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
97
|
-
:is="getCustomComponent(c)"
|
|
98
|
-
:meta="c.meta"
|
|
99
|
-
:column="column"
|
|
100
|
-
:record="coreStore.record"
|
|
101
|
-
:resource="coreStore.resource"
|
|
102
|
-
:adminUser="coreStore.adminUser"
|
|
103
|
-
/>
|
|
104
61
|
</div>
|
|
105
62
|
|
|
106
63
|
|
|
@@ -111,78 +68,37 @@
|
|
|
111
68
|
<script setup>
|
|
112
69
|
|
|
113
70
|
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
114
|
-
|
|
115
71
|
import ValueRenderer from '@/components/ValueRenderer.vue';
|
|
116
72
|
import { useCoreStore } from '@/stores/core';
|
|
117
|
-
import {
|
|
118
|
-
import { getCustomComponent, checkAcessByAllowedActions } from '@/utils';
|
|
73
|
+
import { getCustomComponent } from '@/utils';
|
|
119
74
|
import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
|
|
120
75
|
import { onMounted, ref } from 'vue';
|
|
121
|
-
import { useRoute
|
|
122
|
-
import {callAdminForthApi} from '@/utils';
|
|
123
|
-
import {showSuccesTost} from '@/composables/useFrontendApi';
|
|
76
|
+
import { useRoute } from 'vue-router';
|
|
124
77
|
|
|
125
78
|
|
|
126
79
|
const item = ref(null);
|
|
127
80
|
const route = useRoute();
|
|
128
|
-
const router = useRouter();
|
|
129
81
|
const loading = ref(false);
|
|
130
82
|
let showComponentsPerColumn = {};
|
|
131
83
|
|
|
132
|
-
console.log(route.params,'showWiev');
|
|
133
|
-
|
|
134
|
-
|
|
135
84
|
const coreStore = useCoreStore();
|
|
136
|
-
const modalStore = useModalStore();
|
|
137
85
|
|
|
138
86
|
onMounted(async () => {
|
|
139
87
|
loading.value = true;
|
|
140
|
-
await coreStore.
|
|
88
|
+
await coreStore.fetchColumns({
|
|
141
89
|
resourceId: route.params.resourceId
|
|
142
90
|
});
|
|
143
91
|
await coreStore.fetchRecord({
|
|
144
92
|
resourceId: route.params.resourceId,
|
|
145
93
|
primaryKey: route.params.primaryKey,
|
|
146
94
|
});
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (column.components?.show) {
|
|
151
|
-
acc[column.name] = getCustomComponent(column.components.show);
|
|
95
|
+
showComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
|
|
96
|
+
if (column.component?.show) {
|
|
97
|
+
acc[column.name] = getCustomComponent(column.component.show);
|
|
152
98
|
}
|
|
153
99
|
return acc;
|
|
154
|
-
|
|
100
|
+
}, {});
|
|
155
101
|
loading.value = false;
|
|
156
102
|
});
|
|
157
103
|
|
|
158
|
-
async function deleteRecord(row) {
|
|
159
|
-
const data = await window.adminforth.confirm({
|
|
160
|
-
message: 'Are you sure you want to delete this item?',
|
|
161
|
-
yes: 'Delete',
|
|
162
|
-
no: 'Cancel',
|
|
163
|
-
});
|
|
164
|
-
if (data) {
|
|
165
|
-
try {
|
|
166
|
-
const res = await callAdminForthApi({
|
|
167
|
-
path: '/delete_record',
|
|
168
|
-
method: 'POST',
|
|
169
|
-
body: {
|
|
170
|
-
resourceId: route.params.resourceId,
|
|
171
|
-
primaryKey: route.params.primaryKey,
|
|
172
|
-
}});
|
|
173
|
-
if (!res.error){
|
|
174
|
-
router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
|
|
175
|
-
showSuccesTost('Record deleted successfully')
|
|
176
|
-
} else {
|
|
177
|
-
console.error(res.error)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
} catch (e) {
|
|
181
|
-
console.error(e);
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
104
|
</script>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @type {import('tailwindcss').Config} */
|
|
2
2
|
export default {
|
|
3
|
-
content: ["./src/**/*.{vue, js
|
|
3
|
+
content: ["./src/**/*.{vue, js}","./src/*.{vue, js}", "./index.html", "./node_modules/flowbite/**/*.js"],
|
|
4
4
|
theme: {
|
|
5
5
|
extend: {
|
|
6
6
|
/* IMPORTANT:ADMINFORTH TAILWIND STYLES */
|
package/dist/spa/vite.config.ts
CHANGED
package/dist/types.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// typical types which AdminForth supports
|
|
2
|
+
//
|
|
3
|
+
export const AdminForthTypes = {
|
|
4
|
+
STRING: 'string',
|
|
5
|
+
INTEGER: 'integer',
|
|
6
|
+
FLOAT: 'float',
|
|
7
|
+
DECIMAL: 'decimal',
|
|
8
|
+
BOOLEAN: 'boolean',
|
|
9
|
+
DATE: 'date',
|
|
10
|
+
DATETIME: 'datetime',
|
|
11
|
+
TIME: 'time',
|
|
12
|
+
TEXT: 'text',
|
|
13
|
+
JSON: 'json',
|
|
14
|
+
};
|
|
15
|
+
export const AdminForthFilterOperators = {
|
|
16
|
+
EQ: 'eq',
|
|
17
|
+
NE: 'ne',
|
|
18
|
+
GT: 'gt',
|
|
19
|
+
LT: 'lt',
|
|
20
|
+
GTE: 'gte',
|
|
21
|
+
LTE: 'lte',
|
|
22
|
+
LIKE: 'like',
|
|
23
|
+
ILIKE: 'ilike',
|
|
24
|
+
IN: 'in',
|
|
25
|
+
NIN: 'nin',
|
|
26
|
+
};
|
|
27
|
+
export const AdminForthSortDirections = {
|
|
28
|
+
ASC: 'asc',
|
|
29
|
+
DESC: 'desc',
|
|
30
|
+
};
|
package/index.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { AdminForthConfig, AdminForthClass, AdminForthComponentDeclaration, Admi
|
|
|
18
18
|
AdminForthResource,
|
|
19
19
|
AllowedActionsEnum,
|
|
20
20
|
AllowedActions,
|
|
21
|
-
ActionCheckSource
|
|
21
|
+
ActionCheckSource,
|
|
22
22
|
} from './types/AdminForthConfig.js';
|
|
23
23
|
import path from 'path';
|
|
24
24
|
import AdminForthPlugin from './plugins/base.js';
|
|
@@ -555,6 +555,66 @@ class AdminForth implements AdminForthClass {
|
|
|
555
555
|
return users.data[0] || null;
|
|
556
556
|
}
|
|
557
557
|
|
|
558
|
+
async createResourceRecord({ resource, record, adminUser }: { resource: AdminForthResource, record: any, adminUser: AdminUser }) {
|
|
559
|
+
for (const column of resource.columns) {
|
|
560
|
+
if (column.fillOnCreate) {
|
|
561
|
+
if (record[column.name] === undefined) {
|
|
562
|
+
record[column.name] = column.fillOnCreate({
|
|
563
|
+
initialRecord: record, adminUser
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if ((column.required as {create?: boolean, edit?: boolean}) ?.create && record[column.name] === undefined) {
|
|
568
|
+
return { error: `Column '${column.name}' is required` };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (column.isUnique) {
|
|
572
|
+
const existingRecord = await this.connectors[resource.dataSource].getData({
|
|
573
|
+
resource,
|
|
574
|
+
filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value: record[column.name] }],
|
|
575
|
+
limit: 1,
|
|
576
|
+
sort: [],
|
|
577
|
+
offset: 0
|
|
578
|
+
});
|
|
579
|
+
if (existingRecord.data.length > 0) {
|
|
580
|
+
return { error: `Record with ${column.name} ${record[column.name]} already exists` };
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// execute hook if needed
|
|
586
|
+
for (const hook of listify(resource.hooks?.create?.beforeSave as BeforeSaveFunction[])) {
|
|
587
|
+
const resp = await hook({ resource, record, adminUser });
|
|
588
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
589
|
+
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (resp.error) {
|
|
593
|
+
return { error: resp.error };
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// remove virtual columns from record
|
|
598
|
+
for (const column of resource.columns.filter((col) => col.virtual)) {
|
|
599
|
+
if (record[column.name]) {
|
|
600
|
+
delete record[column.name];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const connector = this.connectors[resource.dataSource];
|
|
604
|
+
await connector.createRecord({ resource, record });
|
|
605
|
+
// execute hook if needed
|
|
606
|
+
for (const hook of listify(resource.hooks?.create?.afterSave as AfterSaveFunction[])) {
|
|
607
|
+
const resp = await hook({ resource, record, adminUser });
|
|
608
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
609
|
+
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if (resp.error) {
|
|
613
|
+
return { error: resp.error };
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
558
618
|
setupEndpoints(server: GenericHttpServer) {
|
|
559
619
|
server.endpoint({
|
|
560
620
|
noAuth: true,
|
|
@@ -1029,7 +1089,6 @@ class AdminForth implements AdminForthClass {
|
|
|
1029
1089
|
return item;
|
|
1030
1090
|
},
|
|
1031
1091
|
});
|
|
1032
|
-
|
|
1033
1092
|
server.endpoint({
|
|
1034
1093
|
method: 'POST',
|
|
1035
1094
|
path: '/create_record',
|
|
@@ -1045,66 +1104,8 @@ class AdminForth implements AdminForthClass {
|
|
|
1045
1104
|
return { error };
|
|
1046
1105
|
}
|
|
1047
1106
|
|
|
1048
|
-
|
|
1049
|
-
// execute hook if needed
|
|
1050
|
-
for (const hook of listify(resource.hooks?.create?.beforeSave as BeforeSaveFunction[])) {
|
|
1051
|
-
const resp = await hook({ resource, record, adminUser });
|
|
1052
|
-
if (!resp || (!resp.ok && !resp.error)) {
|
|
1053
|
-
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
if (resp.error) {
|
|
1057
|
-
return { error: resp.error };
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
for (const column of resource.columns) {
|
|
1064
|
-
if (column.fillOnCreate) {
|
|
1065
|
-
if (body['record'][column.name] === undefined) {
|
|
1066
|
-
body['record'][column.name] = column.fillOnCreate({
|
|
1067
|
-
initialRecord: body['record'], adminUser
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
if ((column.required as {create?: boolean, edit?: boolean}) ?.create && body['record'][column.name] === undefined) {
|
|
1072
|
-
return { error: `Column '${column.name}' is required` };
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
if (column.isUnique) {
|
|
1076
|
-
const existingRecord = await this.connectors[resource.dataSource].getData({
|
|
1077
|
-
resource,
|
|
1078
|
-
filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value: body['record'][column.name] }],
|
|
1079
|
-
limit: 1,
|
|
1080
|
-
sort: [],
|
|
1081
|
-
offset: 0
|
|
1082
|
-
});
|
|
1083
|
-
if (existingRecord.data.length > 0) {
|
|
1084
|
-
return { error: `Record with ${column.name} ${body['record'][column.name]} already exists` };
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// remove virtual columns from record
|
|
1090
|
-
for (const column of resource.columns.filter((col) => col.virtual)) {
|
|
1091
|
-
if (record[column.name]) {
|
|
1092
|
-
delete record[column.name];
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1107
|
+
await this.createResourceRecord({ resource, record: body['record'], adminUser });
|
|
1095
1108
|
const connector = this.connectors[resource.dataSource];
|
|
1096
|
-
await connector.createRecord({ resource, record });
|
|
1097
|
-
// execute hook if needed
|
|
1098
|
-
for (const hook of listify(resource.hooks?.create?.afterSave as AfterSaveFunction[])) {
|
|
1099
|
-
const resp = await hook({ resource, record, adminUser });
|
|
1100
|
-
if (!resp || (!resp.ok && !resp.error)) {
|
|
1101
|
-
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
if (resp.error) {
|
|
1105
|
-
return { error: resp.error };
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
1109
|
|
|
1109
1110
|
return {
|
|
1110
1111
|
newRecordId: body['record'][connector.getPrimaryKey(resource)]
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { transformObject,deepMerge } from "./utils.js";
|
|
1
|
+
import { transformObject,deepMerge,createRGBA,parseColorForAliases,darkenRGBA, lightenRGBA } from "./utils.js";
|
|
2
2
|
import { styles } from "./styles.js";
|
|
3
3
|
|
|
4
|
-
const aliasObject ={ lightSidebarText:'lightSidebarIcons',darkSidebarText:'darkSidebarIcons',lightSidebarTextHover:'lightSidebarIconsHover',darkSidebarTextHover:'darkSidebarIconsHover'}
|
|
5
4
|
|
|
6
5
|
export class StylesGenerator {
|
|
7
6
|
styleConfig: any;
|
|
8
7
|
defaultStyles: any;
|
|
9
8
|
|
|
10
9
|
constructor(styleConfig: any) {
|
|
11
|
-
|
|
12
|
-
console.log("No styles provided using default styles.");
|
|
13
|
-
}
|
|
10
|
+
|
|
14
11
|
this.styleConfig = styleConfig;
|
|
15
12
|
this.defaultStyles = styles();
|
|
16
13
|
}
|
|
@@ -24,22 +21,32 @@ export class StylesGenerator {
|
|
|
24
21
|
}
|
|
25
22
|
return plainCustomStyles;
|
|
26
23
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
|
|
25
|
+
private changeAlias(str:any, mergedStyles:any){
|
|
26
|
+
const {aliasMatch,opacityMatch,darkenMatch,lightenMatch} = parseColorForAliases(str);
|
|
27
|
+
if (!aliasMatch) {
|
|
28
|
+
return str;
|
|
29
|
+
} else {
|
|
30
|
+
const alias = aliasMatch[1];
|
|
31
|
+
let opacity = opacityMatch ? parseFloat(opacityMatch[1]) : 1;
|
|
32
|
+
const color = mergedStyles[alias];
|
|
33
|
+
if (darkenMatch) {
|
|
34
|
+
return darkenRGBA(createRGBA(color, opacity))
|
|
35
|
+
}
|
|
36
|
+
if (lightenMatch){
|
|
37
|
+
return lightenRGBA(createRGBA(color, opacity))
|
|
38
|
+
}
|
|
39
|
+
return createRGBA(color, opacity);
|
|
30
40
|
}
|
|
31
|
-
|
|
32
|
-
Object.keys(aliasObject).forEach((aliasName) => {
|
|
33
|
-
if (colors[aliasObject[aliasName]]) return;
|
|
34
|
-
if (!colors[aliasName]) return;
|
|
35
|
-
colors[aliasObject[aliasName]] = colors[aliasName];
|
|
36
|
-
})
|
|
37
|
-
return plateStyles;
|
|
38
|
-
}
|
|
41
|
+
}
|
|
39
42
|
|
|
40
43
|
mergeStyles() {
|
|
41
|
-
let mergedStyles = deepMerge(this.defaultStyles, this.
|
|
44
|
+
let mergedStyles = deepMerge(this.defaultStyles, this.generatePlainStyles(this.styleConfig));
|
|
45
|
+
let colors = mergedStyles.colors;
|
|
46
|
+
Object.entries(colors).forEach(([key,value])=>{
|
|
47
|
+
|
|
48
|
+
colors[key] = this.changeAlias(value,colors)
|
|
49
|
+
})
|
|
42
50
|
return mergedStyles;
|
|
43
51
|
}
|
|
44
|
-
|
|
45
52
|
}
|
package/modules/styles.ts
CHANGED
|
@@ -5,27 +5,23 @@ export const styles = () => ({
|
|
|
5
5
|
lightHtml: "#FFFFFF", // main background
|
|
6
6
|
|
|
7
7
|
lightNavbar: "#FFFFFF", // navbar background
|
|
8
|
-
lightNavbarHover: "#D3D3D3", // in development
|
|
9
|
-
lightNavbarText: "#333333", // in development
|
|
10
|
-
lightNavbarTextHover: "#333333", // in development
|
|
11
|
-
lightNavbarIcons: "#333333", // in development
|
|
12
|
-
lightNavbarIconsHover: "#333333", // in development
|
|
13
|
-
lightNavbarLogo: "#333333", // in development
|
|
14
8
|
lightNavbarBorder: "rgb(229 231 235)", // border
|
|
9
|
+
lightNavbarText: "#111827", // navbar text
|
|
10
|
+
lightNavbarTextHover: "alias:lightNavbarText darken", // navbar text hover
|
|
11
|
+
lightNavbarTextActive: "alias:lightNavbarText darken", // navbar text active
|
|
12
|
+
lightNavbarIcons: "alias:lightNavbarText opacity:0.7", // navbar icons
|
|
15
13
|
|
|
16
14
|
lightSidebar: "#ffffff", // sidebar background
|
|
17
|
-
lightSidebarBorder: "
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
lightSidebarIconsHover: "#333333", // sidebar list item icons hover
|
|
28
|
-
lightSidebarHeading: "#333333", // sidebar heading
|
|
15
|
+
lightSidebarBorder: "alias:lightSidebarText opacity:0.3", // sidebar right border
|
|
16
|
+
lightSidebarItemHover: "alias:lightSidebarText opacity:0.1", // sidebar list item hover
|
|
17
|
+
lightSidebarItemActive: "alias:lightSidebarText opacity:0.4", // sidebar list item active
|
|
18
|
+
lightSidebarText: "#1f2937", // sidebar list item text
|
|
19
|
+
lightSidebarTextHover: "alias:lightSidebarText darken", // sidebar list item text hover
|
|
20
|
+
lightSidebarTextActive: "alias:lightSidebarText darken", // sidebar list item text active
|
|
21
|
+
lightSidebarDevider: "alias:lightSidebarText opacity:0.3", // sidebar devider
|
|
22
|
+
lightSidebarIcons: "alias:lightSidebarText opacity:0.7", // sidebar list item icons
|
|
23
|
+
lightSidebarIconsHover: "alias:lightSidebarText", // sidebar list item icons hover
|
|
24
|
+
lightSidebarHeading: "alias:lightSidebarText opacity:0.3", // sidebar heading
|
|
29
25
|
|
|
30
26
|
lightList: "#FFFFFF", // list view background
|
|
31
27
|
lightListTable: "#FFFFFF", // list view table background
|
|
@@ -35,10 +31,28 @@ export const styles = () => ({
|
|
|
35
31
|
lightListTableRowHover: "rgb(249 250 251)", // list view row hover
|
|
36
32
|
lightListBreadcrumbsText: "#666666", // list view breadcrumbs text
|
|
37
33
|
lightListBorder: "#DDDDDD", // list view rows border
|
|
34
|
+
// lightListButton: "#FFFFFF", // list view button
|
|
35
|
+
// lightListButtonBorder: "#d1d5db", // list view button border
|
|
36
|
+
// lightListButtonHover: "#f3f4f6", // list view button hover
|
|
37
|
+
// lightListButtonBorderHover: "#f3f4f6", // list view button border hover
|
|
38
|
+
// lightListButtonActive: "#f3f4f6", // list view button active
|
|
39
|
+
// lightListButtonDisabled: "#f3f4f6", // list view button disabled
|
|
40
|
+
// lightListButtonDisabledText: "#f3f4f6", // list view button disabled text
|
|
41
|
+
// lightListButtonIcon: "#333333", // list view button icon
|
|
38
42
|
|
|
39
43
|
lightForm: "#FFFFFF", // show view background
|
|
40
44
|
lightFormBorder: "#F5F5F5", // show view rows border
|
|
41
45
|
lightFormHeading: "rgb(249 250 251)", // show view heading
|
|
46
|
+
|
|
47
|
+
lightButtons: "#FFFFFF", // button background
|
|
48
|
+
lightButtonsBorder: "#DDDDDD", // button border
|
|
49
|
+
lightButtonsText: "#111827", // button text
|
|
50
|
+
lightButtonsHover: "#f3f4f6", // button hover
|
|
51
|
+
lightButtonsBorderHover: "#f3f4f6", // button border hover
|
|
52
|
+
lightButtonsActive: "#f3f4f6", // button active
|
|
53
|
+
lightButtonsDisabled: "#f3f4f6", // button disabled
|
|
54
|
+
lightButtonsDisabledText: "#f3f4f6", // button disabled text
|
|
55
|
+
lightButtonsIcon: "#333333", // button icon
|
|
42
56
|
|
|
43
57
|
|
|
44
58
|
|
|
@@ -46,28 +60,24 @@ export const styles = () => ({
|
|
|
46
60
|
darkHtml: "#111827",
|
|
47
61
|
|
|
48
62
|
darkNavbar: "#111827",
|
|
49
|
-
darkNavbarHover: "#444444",
|
|
50
|
-
darkNavbarText: "#FFFFFF",
|
|
51
|
-
darkNavbarTextHover: "#FFFFFF",
|
|
52
|
-
darkNavbarIcons: "#FFFFFF",
|
|
53
|
-
darkNavbarIconsHover: "#FFFFFF",
|
|
54
|
-
darkNavbarLogo: "#FFFFFF",
|
|
55
63
|
darkNavbarBorder: "#e5e7eb",
|
|
64
|
+
darkNavbarText: "#9ca3af",
|
|
65
|
+
darkNavbarTextHover: "alias:darkNavbarText lighten",
|
|
66
|
+
darkNavbarTextActive: "alias:darkNavbarText lighten",
|
|
67
|
+
darkNavbarIcons: "alias:darkNavbarText opacity:0.7",
|
|
56
68
|
|
|
57
69
|
darkSidebar: "#1f2937",
|
|
58
|
-
darkSidebarBorder: "
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
darkSidebarItemHover: "#374151",
|
|
62
|
-
darkSidebarItemActive: "#52525b",
|
|
63
|
-
darkSidebarItemActiveText: "#FFFFFF",
|
|
70
|
+
darkSidebarBorder: "alias:darkSidebarText opacity:0.3",
|
|
71
|
+
darkSidebarItemHover: "alias:darkSidebarText opacity:0.1",
|
|
72
|
+
darkSidebarItemActive: "alias:darkSidebarText opacity:0.4",
|
|
64
73
|
darkSidebarText: "#9ca3af",
|
|
65
|
-
darkSidebarTextHover: "
|
|
66
|
-
darkSidebarTextActive: "
|
|
67
|
-
darkSidebarDevider: "
|
|
68
|
-
darkSidebarIcons: "
|
|
69
|
-
darkSidebarIconsHover: "
|
|
70
|
-
darkSidebarHeading: "
|
|
74
|
+
darkSidebarTextHover: "alias:darkSidebarText lighten",
|
|
75
|
+
darkSidebarTextActive: "alias:darkSidebarText lighten",
|
|
76
|
+
darkSidebarDevider: "alias:darkSidebarText opacity:0.3",
|
|
77
|
+
darkSidebarIcons: "alias:darkSidebarText opacity:0.7",
|
|
78
|
+
darkSidebarIconsHover: "alias:darkSidebarText",
|
|
79
|
+
darkSidebarHeading: "alias:darkSidebarText opacity:0.3",
|
|
80
|
+
|
|
71
81
|
|
|
72
82
|
darkList: "#111111",
|
|
73
83
|
darkListTable: "#1f2937",
|