adminforth 1.1.23 → 1.1.25
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 +12 -12
- package/dist/plugins/AccessControl/index.js +3 -56
- package/dist/plugins/AuditLog/index.js +13 -0
- package/dist/plugins/AuditLog/types.js +1 -0
- package/dist/plugins/plugins/ForeignInlineListPlugin/custom/InlineList.vue +248 -0
- package/dist/spa/index.html +2 -2
- package/dist/spa/package-lock.json +1 -189
- package/dist/spa/package.json +1 -6
- package/dist/spa/spa/src/components/ShowTableItem.vue +14 -0
- package/dist/spa/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/App.vue +57 -76
- package/dist/spa/src/components/AcceptModal.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +3 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +3 -3
- package/dist/spa/src/components/Dropdown.vue +4 -13
- package/dist/spa/src/components/Filters.vue +22 -55
- package/dist/spa/src/components/MenuLink.vue +2 -2
- package/dist/spa/src/components/ResourceForm.vue +99 -157
- package/dist/spa/src/components/ValueRenderer.vue +1 -11
- package/dist/spa/src/router/index.ts +2 -3
- package/dist/spa/src/stores/core.ts +33 -22
- package/dist/spa/src/utils.ts +3 -5
- package/dist/spa/src/views/CreateView.vue +7 -15
- package/dist/spa/src/views/EditView.vue +8 -36
- package/dist/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/views/ListView.vue +23 -35
- package/dist/spa/src/views/LoginView.vue +1 -1
- package/dist/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/src/views/ShowView.vue +9 -20
- package/dist/spa/tailwind.config.js +2 -5
- package/dist/types/AdminForthConfig.js +9 -0
- package/index.ts +16 -18
- package/package.json +1 -1
- package/plugins/AuditLog/index.ts +29 -0
- package/plugins/AuditLog/types.ts +4 -0
- package/types/AdminForthConfig.ts +23 -1
- package/dist/spa/src/components/CustomRangePicker.vue +0 -148
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import ExpressServer from './servers/express.js';
|
|
|
23
23
|
import { v1 as uuid } from 'uuid';
|
|
24
24
|
import fs from 'fs';
|
|
25
25
|
import { ADMINFORTH_VERSION, listify } from './modules/utils.js';
|
|
26
|
-
import { AdminForthFilterOperators, AdminForthDataTypes, AdminForthResourcePages, AllowedActionsEnum } from './types/AdminForthConfig.js';
|
|
26
|
+
import { AdminForthFilterOperators, AdminForthDataTypes, AdminForthResourcePages, AllowedActionsEnum, ActionCheckSource } from './types/AdminForthConfig.js';
|
|
27
27
|
import path from 'path';
|
|
28
28
|
//get array from enum AdminForthResourcePages
|
|
29
29
|
class AdminForth {
|
|
@@ -633,13 +633,13 @@ class AdminForth {
|
|
|
633
633
|
};
|
|
634
634
|
}),
|
|
635
635
|
});
|
|
636
|
-
function interpretResource(adminUser, resource, meta) {
|
|
636
|
+
function interpretResource(adminUser, resource, meta, source) {
|
|
637
637
|
return __awaiter(this, void 0, void 0, function* () {
|
|
638
638
|
var _b;
|
|
639
639
|
yield Promise.all(Object.entries(((_b = resource.options) === null || _b === void 0 ? void 0 : _b.allowedActions) || {}).map((_c) => __awaiter(this, [_c], void 0, function* ([key, value]) {
|
|
640
640
|
// if callable then call
|
|
641
641
|
if (typeof value === 'function') {
|
|
642
|
-
resource.options.allowedActions[key] = yield value(adminUser, resource, meta);
|
|
642
|
+
resource.options.allowedActions[key] = yield value({ adminUser, resource, meta, source });
|
|
643
643
|
}
|
|
644
644
|
})));
|
|
645
645
|
});
|
|
@@ -667,7 +667,7 @@ class AdminForth {
|
|
|
667
667
|
if (!resource) {
|
|
668
668
|
return { error: `Resource ${resourceId} not found` };
|
|
669
669
|
}
|
|
670
|
-
yield interpretResource(adminUser, resource, {});
|
|
670
|
+
yield interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
|
|
671
671
|
// exclude "plugins" key
|
|
672
672
|
return { resource: Object.assign(Object.assign({}, resource), { plugins: undefined }) };
|
|
673
673
|
}),
|
|
@@ -691,7 +691,7 @@ class AdminForth {
|
|
|
691
691
|
if (!resource) {
|
|
692
692
|
return { error: `Resource ${resourceId} not found` };
|
|
693
693
|
}
|
|
694
|
-
yield interpretResource(adminUser, resource, { requestBody: body });
|
|
694
|
+
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
|
|
695
695
|
const { allowed, error } = checkAccess(source, resource);
|
|
696
696
|
console.log('allowed', allowed, error);
|
|
697
697
|
if (!allowed) {
|
|
@@ -891,7 +891,7 @@ class AdminForth {
|
|
|
891
891
|
if (!resource) {
|
|
892
892
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
893
893
|
}
|
|
894
|
-
yield interpretResource(adminUser, resource, { requestBody: body });
|
|
894
|
+
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.CreateRequest);
|
|
895
895
|
const { allowed, error } = checkAccess(AllowedActionsEnum.create, resource);
|
|
896
896
|
if (!allowed) {
|
|
897
897
|
return { error };
|
|
@@ -963,11 +963,6 @@ class AdminForth {
|
|
|
963
963
|
if (!resource) {
|
|
964
964
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
965
965
|
}
|
|
966
|
-
yield interpretResource(adminUser, resource, { requestBody: body });
|
|
967
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
|
|
968
|
-
if (!allowed) {
|
|
969
|
-
return { error };
|
|
970
|
-
}
|
|
971
966
|
const recordId = body['recordId'];
|
|
972
967
|
const connector = this.connectors[resource.dataSource];
|
|
973
968
|
const oldRecord = yield connector.getRecordByPrimaryKey(resource, recordId);
|
|
@@ -976,6 +971,11 @@ class AdminForth {
|
|
|
976
971
|
return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
|
|
977
972
|
}
|
|
978
973
|
const record = body['record'];
|
|
974
|
+
yield interpretResource(adminUser, resource, { requestBody: body, record, oldRecord }, ActionCheckSource.EditRequest);
|
|
975
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
|
|
976
|
+
if (!allowed) {
|
|
977
|
+
return { error };
|
|
978
|
+
}
|
|
979
979
|
// execute hook if needed
|
|
980
980
|
for (const hook of listify((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.edit) === null || _6 === void 0 ? void 0 : _6.beforeSave)) {
|
|
981
981
|
const resp = yield hook({ resource, record, adminUser });
|
|
@@ -1035,7 +1035,7 @@ class AdminForth {
|
|
|
1035
1035
|
if (resource.options.allowedActions.delete === false) {
|
|
1036
1036
|
return { error: `Resource '${resource.resourceId}' does not allow delete action` };
|
|
1037
1037
|
}
|
|
1038
|
-
yield interpretResource(adminUser, resource, { requestBody: body });
|
|
1038
|
+
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
|
|
1039
1039
|
const { allowed, error } = checkAccess(AllowedActionsEnum.delete, resource);
|
|
1040
1040
|
if (!allowed) {
|
|
1041
1041
|
return { error };
|
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { AllowedActionsEnum } from "../../types/AdminForthConfig.js";
|
|
11
1
|
import AdminForthPlugin from "../base.js";
|
|
12
|
-
class
|
|
2
|
+
class AuditLogPlugin extends AdminForthPlugin {
|
|
13
3
|
constructor(options) {
|
|
14
4
|
super(options, import.meta.url);
|
|
15
5
|
this.options = options;
|
|
@@ -17,50 +7,7 @@ class AccessControlPlugin extends AdminForthPlugin {
|
|
|
17
7
|
modifyResourceConfig(adminforth, resourceConfig) {
|
|
18
8
|
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
19
9
|
this.adminforth = adminforth;
|
|
20
|
-
if (!resourceConfig.hooks) {
|
|
21
|
-
resourceConfig.hooks = {};
|
|
22
|
-
}
|
|
23
|
-
const checkAccess = (adminUser, action, meta) => __awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
const hasAccessOrError = yield this.options.hasAccess(adminUser, action, meta);
|
|
25
|
-
if (hasAccessOrError === true) {
|
|
26
|
-
return { ok: true };
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
return { ok: false, error: hasAccessOrError || AccessControlPlugin.defaultError };
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
const bindHookCheck = (action, hookName) => {
|
|
33
|
-
if (!resourceConfig.hooks[action]) {
|
|
34
|
-
resourceConfig.hooks[action] = {};
|
|
35
|
-
}
|
|
36
|
-
if (!resourceConfig.hooks[action][hookName]) {
|
|
37
|
-
resourceConfig.hooks[action][hookName] = [];
|
|
38
|
-
}
|
|
39
|
-
if (hookName === 'beforeDatasourceRequest') {
|
|
40
|
-
resourceConfig.hooks[action][hookName].unshift((_a) => __awaiter(this, [_a], void 0, function* ({ adminUser, query }) {
|
|
41
|
-
return checkAccess(adminUser, action, { query });
|
|
42
|
-
}));
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
resourceConfig.hooks[action][hookName].unshift((_b) => __awaiter(this, [_b], void 0, function* ({ adminUser, record }) {
|
|
46
|
-
return checkAccess(adminUser, action, { record });
|
|
47
|
-
}));
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
// List check
|
|
51
|
-
bindHookCheck(AllowedActionsEnum.list, 'beforeDatasourceRequest');
|
|
52
|
-
// Show check
|
|
53
|
-
bindHookCheck(AllowedActionsEnum.show, 'beforeDatasourceRequest');
|
|
54
|
-
// Edit check
|
|
55
|
-
bindHookCheck(AllowedActionsEnum.edit, 'beforeDatasourceRequest');
|
|
56
|
-
// create check
|
|
57
|
-
bindHookCheck(AllowedActionsEnum.create, 'beforeSave');
|
|
58
|
-
// edit check
|
|
59
|
-
bindHookCheck(AllowedActionsEnum.edit, 'beforeSave');
|
|
60
|
-
// delete check
|
|
61
|
-
bindHookCheck(AllowedActionsEnum.delete, 'beforeSave');
|
|
62
|
-
console.log('resourceConfig', resourceConfig);
|
|
63
10
|
}
|
|
64
11
|
}
|
|
65
|
-
|
|
66
|
-
export default
|
|
12
|
+
AuditLogPlugin.defaultError = 'Sorry, you do not have access to this resource.';
|
|
13
|
+
export default AuditLogPlugin;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import AdminForthPlugin from "../base.js";
|
|
2
|
+
class AuditLogPlugin extends AdminForthPlugin {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
super(options, import.meta.url);
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
modifyResourceConfig(adminforth, resourceConfig) {
|
|
8
|
+
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
9
|
+
this.adminforth = adminforth;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
AuditLogPlugin.defaultError = 'Sorry, you do not have access to this resource.';
|
|
13
|
+
export default AuditLogPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<!-- todo exclude foreign column-->
|
|
4
|
+
<Filters
|
|
5
|
+
v-if="listResource"
|
|
6
|
+
:columns="listResource.columns.filter((c) => c.name !== listResourceRefColumn.name)"
|
|
7
|
+
v-model:filters="filters"
|
|
8
|
+
:columnsMinMax="columnsMinMax"
|
|
9
|
+
:show="filtersShow"
|
|
10
|
+
@hide="filtersShow = false"
|
|
11
|
+
/>
|
|
12
|
+
</Teleport>
|
|
13
|
+
|
|
14
|
+
<td colspan="2">
|
|
15
|
+
<div class="flex items-center gap-1">
|
|
16
|
+
<h4 v-if="listResource"
|
|
17
|
+
class="px-6 py-4"
|
|
18
|
+
>{{ listResource.label }} inline records</h4>
|
|
19
|
+
|
|
20
|
+
<button
|
|
21
|
+
@click="()=>{checkboxes = []}"
|
|
22
|
+
v-if="checkboxes.length"
|
|
23
|
+
data-tooltip-target="tooltip-remove-all"
|
|
24
|
+
data-tooltip-placement="bottom"
|
|
25
|
+
class="flex gap-1 items-center py-1 px-3 me-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"
|
|
26
|
+
>
|
|
27
|
+
<IconBanOutline class="w-5 h-5 "/>
|
|
28
|
+
<div id="tooltip-remove-all" role="tooltip"
|
|
29
|
+
class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
|
30
|
+
Remove selection
|
|
31
|
+
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
32
|
+
</div>
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
<button
|
|
36
|
+
v-if="checkboxes.length"
|
|
37
|
+
v-for="(action,i) in listResource?.options?.bulkActions"
|
|
38
|
+
:key="action.id"
|
|
39
|
+
@click="startBulkAction(action.id)"
|
|
40
|
+
class="flex gap-1 items-center py-1 px-3 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"
|
|
41
|
+
:class="{'bg-red-100 text-red-800 border-red-400 dark:bg-red-700 dark:text-red-400 dark:border-red-400':action.state==='danger', 'bg-green-100 text-green-800 border-green-400 dark:bg-green-700 dark:text-green-400 dark:border-green-400':action.state==='success',
|
|
42
|
+
'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
|
|
43
|
+
}"
|
|
44
|
+
>
|
|
45
|
+
<component
|
|
46
|
+
v-if="action.icon"
|
|
47
|
+
:is="getIcon(action.icon)"
|
|
48
|
+
class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"></component>
|
|
49
|
+
|
|
50
|
+
{{ `${action.label} (${checkboxes.length})` }}
|
|
51
|
+
</button>
|
|
52
|
+
|
|
53
|
+
<RouterLink v-if="listResource?.options?.allowedActions?.create"
|
|
54
|
+
:to="{
|
|
55
|
+
name: 'resource-create',
|
|
56
|
+
params: { resourceId: listResource.resourceId },
|
|
57
|
+
query: {
|
|
58
|
+
values: encodeURIComponent(JSON.stringify({[listResourceRefColumn.name]: props.record[selfPrimaryKeyColumn.name]})),
|
|
59
|
+
returnTo: $route.fullPath,
|
|
60
|
+
},
|
|
61
|
+
}"
|
|
62
|
+
class="flex items-center py-1 px-3 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 rounded-default"
|
|
63
|
+
>
|
|
64
|
+
<IconPlusOutline class="w-4 h-4 me-2"/>
|
|
65
|
+
Create
|
|
66
|
+
</RouterLink>
|
|
67
|
+
|
|
68
|
+
<button
|
|
69
|
+
class="flex gap-1 items-center py-1 px-3 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 rounded-default"
|
|
70
|
+
@click="()=>{filtersShow = !filtersShow}"
|
|
71
|
+
>
|
|
72
|
+
<IconFilterOutline class="w-4 h-4 me-2"/>
|
|
73
|
+
Filter
|
|
74
|
+
<span
|
|
75
|
+
class="bg-red-100 text-red-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400"
|
|
76
|
+
v-if="filters.length">
|
|
77
|
+
{{ filters.length }}
|
|
78
|
+
</span>
|
|
79
|
+
</button>
|
|
80
|
+
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<ResourceListTable
|
|
84
|
+
:resource="listResource"
|
|
85
|
+
:rows="rows"
|
|
86
|
+
@update:page="page = $event"
|
|
87
|
+
@update:sort="sort = $event"
|
|
88
|
+
@update:checkboxes="checkboxes = $event"
|
|
89
|
+
:pageSize="pageSize"
|
|
90
|
+
:totalRows="totalRows"
|
|
91
|
+
:checkboxes="checkboxes"
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
</td>
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<script setup>
|
|
98
|
+
import { callAdminForthApi } from '@/utils';
|
|
99
|
+
import { ref, onMounted, watch, computed } from 'vue';
|
|
100
|
+
import ResourceListTable from '@/components/ResourceListTable.vue';
|
|
101
|
+
import Filters from '@/components/Filters.vue';
|
|
102
|
+
import {
|
|
103
|
+
IconBanOutline,
|
|
104
|
+
IconFilterOutline,
|
|
105
|
+
IconPlusOutline,
|
|
106
|
+
} from '@iconify-prerendered/vue-flowbite';
|
|
107
|
+
|
|
108
|
+
import { getIcon } from '@/utils';
|
|
109
|
+
|
|
110
|
+
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
111
|
+
|
|
112
|
+
const listResource = ref(null);
|
|
113
|
+
const loading = ref(true);
|
|
114
|
+
|
|
115
|
+
const page = ref(1);
|
|
116
|
+
const sort = ref([]);
|
|
117
|
+
const checkboxes = ref([]);
|
|
118
|
+
const pageSize = computed(() => listResource.value?.options?.listPageSize || 10);
|
|
119
|
+
|
|
120
|
+
const rows = ref(null);
|
|
121
|
+
const totalRows = ref(0);
|
|
122
|
+
|
|
123
|
+
const filters = ref([]);
|
|
124
|
+
const filtersShow = ref(false);
|
|
125
|
+
const columnsMinMax = ref(null);
|
|
126
|
+
|
|
127
|
+
const listResourceRefColumn = computed(() => {
|
|
128
|
+
if (!listResource.value) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return listResource.value.columns.find(c => c.foreignResource?.resourceId === props.resource.resourceId);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const selfPrimaryKeyColumn = computed(() => {
|
|
135
|
+
return props.resource.columns.find(c => c.primaryKey);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const endFilters = computed(() => {
|
|
139
|
+
if (!listResource.value) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
// get name of the column that is foreign key
|
|
143
|
+
const refColumn = listResourceRefColumn.value;
|
|
144
|
+
|
|
145
|
+
const primaryKeyColumn = selfPrimaryKeyColumn.value;
|
|
146
|
+
|
|
147
|
+
if (!refColumn) {
|
|
148
|
+
window.adminforth.alert({
|
|
149
|
+
message: `Column with foreignResource.resourceId which is equal to '${props.resource.resourceId}' not found in resource which is specified as foreighResourceId '${listResource.value.resourceId}'`,
|
|
150
|
+
variant: 'danger',
|
|
151
|
+
});
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
return [
|
|
155
|
+
...filters.value,
|
|
156
|
+
{
|
|
157
|
+
field: refColumn.name,
|
|
158
|
+
operator: 'eq',
|
|
159
|
+
value: props.record[primaryKeyColumn.name],
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
watch([page], async () => {
|
|
165
|
+
await getList();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
watch([sort], async () => {
|
|
169
|
+
await getList();
|
|
170
|
+
}, {deep: true});
|
|
171
|
+
|
|
172
|
+
watch([filters], async () => {
|
|
173
|
+
page.value = 1;
|
|
174
|
+
checkboxes.value = [];
|
|
175
|
+
await getList();
|
|
176
|
+
}, {deep: true});
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
async function startBulkAction(actionId) {
|
|
180
|
+
const data = await callAdminForthApi({
|
|
181
|
+
path: '/start_bulk_action',
|
|
182
|
+
method: 'POST',
|
|
183
|
+
body: {
|
|
184
|
+
resourceId: listResource.value.resourceId,
|
|
185
|
+
actionId: actionId,
|
|
186
|
+
recordIds: checkboxes.value
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
if (data?.status === 'success') {
|
|
190
|
+
checkboxes.value = [];
|
|
191
|
+
}
|
|
192
|
+
await getList();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function getList() {
|
|
196
|
+
rows.value = null;
|
|
197
|
+
console.log('getList', listResource.value)
|
|
198
|
+
const data = await callAdminForthApi({
|
|
199
|
+
path: '/get_resource_data',
|
|
200
|
+
method: 'POST',
|
|
201
|
+
body: {
|
|
202
|
+
source: 'list',
|
|
203
|
+
resourceId: listResource.value.resourceId,
|
|
204
|
+
limit: pageSize.value,
|
|
205
|
+
offset: (page.value - 1) * pageSize.value,
|
|
206
|
+
filters: endFilters.value,
|
|
207
|
+
sort: sort.value,
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (data.error) {
|
|
212
|
+
window.adminforth.alert({
|
|
213
|
+
message: data.error,
|
|
214
|
+
variant: 'danger',
|
|
215
|
+
timeout: 'unlimited',
|
|
216
|
+
});
|
|
217
|
+
rows.value = [];
|
|
218
|
+
totalRows.value = 0;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
rows.value = data.data?.map(row => {
|
|
223
|
+
row._primaryKeyValue = row[listResource.value.columns.find(c => c.primaryKey).name];
|
|
224
|
+
return row;
|
|
225
|
+
});
|
|
226
|
+
totalRows.value = data.total;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
onMounted( async () => {
|
|
230
|
+
loading.value = true;
|
|
231
|
+
const foreighResourceId = props.meta.foreignResourceId;
|
|
232
|
+
listResource.value = (await callAdminForthApi({
|
|
233
|
+
path: `/plugin/${props.meta.pluginInstanceId}/get_resource`,
|
|
234
|
+
method: 'POST',
|
|
235
|
+
body: {},
|
|
236
|
+
})).resource;
|
|
237
|
+
columnsMinMax.value = await callAdminForthApi({
|
|
238
|
+
path: '/get_min_max_for_columns',
|
|
239
|
+
method: 'POST',
|
|
240
|
+
body: {
|
|
241
|
+
resourceId: foreighResourceId,
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
loading.value = false;
|
|
245
|
+
await getList();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
</script>
|
package/dist/spa/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
</script> -->
|
|
17
17
|
|
|
18
18
|
</head>
|
|
19
|
-
<body
|
|
20
|
-
<div id="app" class="min-h-screen
|
|
19
|
+
<body>
|
|
20
|
+
<div id="app" class="min-h-screen dark:bg-gray-800"></div>
|
|
21
21
|
<script type="module" src="/src/main.ts"></script>
|
|
22
22
|
</body>
|
|
23
23
|
</html>
|