adminforth 1.1.35 → 1.1.37
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
CHANGED
|
@@ -648,20 +648,24 @@ class AdminForth {
|
|
|
648
648
|
if (process.env.HEAVY_DEBUG) {
|
|
649
649
|
console.log('🪲Interpreting resource', resource.resourceId, source);
|
|
650
650
|
}
|
|
651
|
+
const allowedActions = {};
|
|
651
652
|
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]) {
|
|
652
653
|
if (process.env.HEAVY_DEBUG) {
|
|
653
654
|
console.log('🪲checking for allowed call', key, 'value:', value, 'typeof', typeof value);
|
|
654
655
|
}
|
|
655
656
|
// if callable then call
|
|
656
657
|
if (typeof value === 'function') {
|
|
657
|
-
|
|
658
|
+
allowedActions[key] = yield value({ adminUser, resource, meta, source });
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
allowedActions[key] = value;
|
|
658
662
|
}
|
|
659
663
|
})));
|
|
664
|
+
return { allowedActions };
|
|
660
665
|
});
|
|
661
666
|
}
|
|
662
|
-
function checkAccess(action,
|
|
663
|
-
|
|
664
|
-
const allowed = (_b = resource.options) === null || _b === void 0 ? void 0 : _b.allowedActions[action];
|
|
667
|
+
function checkAccess(action, allowedActions) {
|
|
668
|
+
const allowed = allowedActions[action];
|
|
665
669
|
if (allowed !== true) {
|
|
666
670
|
return { error: typeof allowed === 'string' ? allowed : 'Action is not allowed', allowed: false };
|
|
667
671
|
}
|
|
@@ -682,9 +686,11 @@ class AdminForth {
|
|
|
682
686
|
if (!resource) {
|
|
683
687
|
return { error: `Resource ${resourceId} not found` };
|
|
684
688
|
}
|
|
685
|
-
yield interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
|
|
689
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
|
|
686
690
|
// exclude "plugins" key
|
|
687
|
-
return {
|
|
691
|
+
return {
|
|
692
|
+
resource: Object.assign(Object.assign({}, resource), { plugins: undefined, options: Object.assign(Object.assign({}, resource.options), { allowedActions }) })
|
|
693
|
+
};
|
|
688
694
|
}),
|
|
689
695
|
});
|
|
690
696
|
server.endpoint({
|
|
@@ -706,8 +712,8 @@ class AdminForth {
|
|
|
706
712
|
if (!resource) {
|
|
707
713
|
return { error: `Resource ${resourceId} not found` };
|
|
708
714
|
}
|
|
709
|
-
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
|
|
710
|
-
const { allowed, error } = checkAccess(source,
|
|
715
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
|
|
716
|
+
const { allowed, error } = checkAccess(source, allowedActions);
|
|
711
717
|
if (!allowed) {
|
|
712
718
|
return { error };
|
|
713
719
|
}
|
|
@@ -905,8 +911,8 @@ class AdminForth {
|
|
|
905
911
|
if (!resource) {
|
|
906
912
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
907
913
|
}
|
|
908
|
-
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.CreateRequest);
|
|
909
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.create,
|
|
914
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.CreateRequest);
|
|
915
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.create, allowedActions);
|
|
910
916
|
if (!allowed) {
|
|
911
917
|
return { error };
|
|
912
918
|
}
|
|
@@ -985,8 +991,8 @@ class AdminForth {
|
|
|
985
991
|
return { error: `Record with ${primaryKeyColumn.name} ${recordId} not found` };
|
|
986
992
|
}
|
|
987
993
|
const record = body['record'];
|
|
988
|
-
yield interpretResource(adminUser, resource, { requestBody: body, record, oldRecord }, ActionCheckSource.EditRequest);
|
|
989
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.edit,
|
|
994
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body, record, oldRecord }, ActionCheckSource.EditRequest);
|
|
995
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.edit, allowedActions);
|
|
990
996
|
if (!allowed) {
|
|
991
997
|
return { error };
|
|
992
998
|
}
|
|
@@ -1049,8 +1055,8 @@ class AdminForth {
|
|
|
1049
1055
|
if (resource.options.allowedActions.delete === false) {
|
|
1050
1056
|
return { error: `Resource '${resource.resourceId}' does not allow delete action` };
|
|
1051
1057
|
}
|
|
1052
|
-
yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
|
|
1053
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.delete,
|
|
1058
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
|
|
1059
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.delete, allowedActions);
|
|
1054
1060
|
if (!allowed) {
|
|
1055
1061
|
return { error };
|
|
1056
1062
|
}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<tr>
|
|
29
29
|
<th scope="col" class="p-4">
|
|
30
30
|
<div v-if="rows && rows.length" class="flex items-center">
|
|
31
|
-
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
|
|
31
|
+
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
|
|
32
32
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
|
33
33
|
<label for="checkbox-all-search" class="sr-only">checkbox</label>
|
|
34
34
|
</div>
|
|
@@ -118,11 +118,12 @@
|
|
|
118
118
|
</td>
|
|
119
119
|
</tr>
|
|
120
120
|
|
|
121
|
-
<tr v-else v-for="(row, rowI) in rows" :key="row.id"
|
|
121
|
+
<tr @click="onClick($event,row)" v-else v-for="(row, rowI) in rows" :key="row.id"
|
|
122
122
|
class="bg-list-view-table-bg border-b dark:bg-gray-800 border-list-view-border-color dark:border-gray-700 hover:bg-list-view-table-row-hover dark:hover:bg-gray-600">
|
|
123
123
|
<td class="w-4 p-4">
|
|
124
124
|
<div class="flex items center">
|
|
125
125
|
<input
|
|
126
|
+
@click="(e)=>{e.stopPropagation()}"
|
|
126
127
|
id="checkbox-table-search-1"
|
|
127
128
|
type="checkbox"
|
|
128
129
|
:checked="checkboxesInternal.includes(row.id)"
|
|
@@ -134,6 +135,7 @@
|
|
|
134
135
|
<td v-for="c in columnsListed" class="px-6 py-4">
|
|
135
136
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
136
137
|
<component
|
|
138
|
+
@click="(e)=>{e.stopPropagation()}"
|
|
137
139
|
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
138
140
|
:meta="c?.components?.list.meta"
|
|
139
141
|
:column="c"
|
|
@@ -142,7 +144,7 @@
|
|
|
142
144
|
:resource="resource"
|
|
143
145
|
/>
|
|
144
146
|
</td>
|
|
145
|
-
<td class=" items-center px-6 py-4">
|
|
147
|
+
<td class=" items-center px-6 py-4" @click="(e)=>{e.stopPropagation()}">
|
|
146
148
|
<div class="flex">
|
|
147
149
|
<RouterLink
|
|
148
150
|
v-if="resource.options?.allowedActions.show"
|
|
@@ -291,6 +293,7 @@ IconFilterOutline,
|
|
|
291
293
|
IconPenSolid,
|
|
292
294
|
IconTrashBinSolid
|
|
293
295
|
} from '@iconify-prerendered/vue-flowbite';
|
|
296
|
+
import router from '@/router';
|
|
294
297
|
|
|
295
298
|
const coreStore = useCoreStore();
|
|
296
299
|
|
|
@@ -385,6 +388,31 @@ function onSortButtonClick(field) {
|
|
|
385
388
|
}
|
|
386
389
|
}
|
|
387
390
|
|
|
391
|
+
|
|
392
|
+
const clickTarget = ref(null);
|
|
393
|
+
async function onClick(e,row) {
|
|
394
|
+
console.log(e,row)
|
|
395
|
+
if(clickTarget.value === e.target) return;
|
|
396
|
+
clickTarget.value = e.target;
|
|
397
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
398
|
+
if (window.getSelection().toString()) return;
|
|
399
|
+
else {router.push({
|
|
400
|
+
name: 'resource-show',
|
|
401
|
+
params: {
|
|
402
|
+
resourceId: props.resource.resourceId,
|
|
403
|
+
primaryKey: row._primaryKeyValue,
|
|
404
|
+
},
|
|
405
|
+
})}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
388
416
|
async function deleteRecord(row) {
|
|
389
417
|
const data = await window.adminforth.confirm({
|
|
390
418
|
message: 'Are you sure you want to delete this item?',
|
package/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { AdminForthConfig, AdminForthClass, AdminForthComponentDeclaration, Admi
|
|
|
17
17
|
AfterDataSourceResponseFunction, AllowedActionValue, AdminUser,
|
|
18
18
|
AdminForthResource,
|
|
19
19
|
AllowedActionsEnum,
|
|
20
|
+
AllowedActions,
|
|
20
21
|
ActionCheckSource
|
|
21
22
|
} from './types/AdminForthConfig.js';
|
|
22
23
|
import path from 'path';
|
|
@@ -732,10 +733,11 @@ class AdminForth implements AdminForthClass {
|
|
|
732
733
|
},
|
|
733
734
|
});
|
|
734
735
|
|
|
735
|
-
async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any, source: ActionCheckSource) {
|
|
736
|
+
async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any, source: ActionCheckSource): Promise<{allowedActions: AllowedActions}> {
|
|
736
737
|
if (process.env.HEAVY_DEBUG) {
|
|
737
738
|
console.log('🪲Interpreting resource', resource.resourceId, source);
|
|
738
739
|
}
|
|
740
|
+
const allowedActions = {};
|
|
739
741
|
|
|
740
742
|
await Promise.all(
|
|
741
743
|
Object.entries(resource.options?.allowedActions || {}).map(
|
|
@@ -746,14 +748,18 @@ class AdminForth implements AdminForthClass {
|
|
|
746
748
|
|
|
747
749
|
// if callable then call
|
|
748
750
|
if (typeof value === 'function') {
|
|
749
|
-
|
|
751
|
+
allowedActions[key] = await value({ adminUser, resource, meta, source });
|
|
752
|
+
} else {
|
|
753
|
+
allowedActions[key] = value;
|
|
750
754
|
}
|
|
751
755
|
})
|
|
752
756
|
);
|
|
757
|
+
|
|
758
|
+
return { allowedActions };
|
|
753
759
|
}
|
|
754
760
|
|
|
755
|
-
function checkAccess(action: AllowedActionsEnum,
|
|
756
|
-
const allowed = (
|
|
761
|
+
function checkAccess(action: AllowedActionsEnum, allowedActions: AllowedActions): { allowed: boolean, error?: string } {
|
|
762
|
+
const allowed = (allowedActions[action] as boolean | string | undefined);
|
|
757
763
|
if (allowed !== true) {
|
|
758
764
|
return { error: typeof allowed === 'string' ? allowed : 'Action is not allowed', allowed: false };
|
|
759
765
|
}
|
|
@@ -777,10 +783,19 @@ class AdminForth implements AdminForthClass {
|
|
|
777
783
|
return { error: `Resource ${resourceId} not found` };
|
|
778
784
|
}
|
|
779
785
|
|
|
780
|
-
await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
|
|
786
|
+
const { allowedActions } = await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
|
|
781
787
|
|
|
782
788
|
// exclude "plugins" key
|
|
783
|
-
return {
|
|
789
|
+
return {
|
|
790
|
+
resource: {
|
|
791
|
+
...resource,
|
|
792
|
+
plugins: undefined,
|
|
793
|
+
options: {
|
|
794
|
+
...resource.options,
|
|
795
|
+
allowedActions,
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
};
|
|
784
799
|
},
|
|
785
800
|
});
|
|
786
801
|
server.endpoint({
|
|
@@ -802,9 +817,9 @@ class AdminForth implements AdminForthClass {
|
|
|
802
817
|
return { error: `Resource ${resourceId} not found` };
|
|
803
818
|
}
|
|
804
819
|
|
|
805
|
-
await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
|
|
820
|
+
const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
|
|
806
821
|
|
|
807
|
-
const { allowed, error } = checkAccess(source as AllowedActionsEnum,
|
|
822
|
+
const { allowed, error } = checkAccess(source as AllowedActionsEnum, allowedActions);
|
|
808
823
|
if (!allowed) {
|
|
809
824
|
return { error };
|
|
810
825
|
}
|
|
@@ -1026,9 +1041,9 @@ class AdminForth implements AdminForthClass {
|
|
|
1026
1041
|
if (!resource) {
|
|
1027
1042
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
1028
1043
|
}
|
|
1029
|
-
await interpretResource(adminUser, resource, { requestBody: body}, ActionCheckSource.CreateRequest);
|
|
1044
|
+
const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body}, ActionCheckSource.CreateRequest);
|
|
1030
1045
|
|
|
1031
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.create,
|
|
1046
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.create, allowedActions);
|
|
1032
1047
|
if (!allowed) {
|
|
1033
1048
|
return { error };
|
|
1034
1049
|
}
|
|
@@ -1117,9 +1132,9 @@ class AdminForth implements AdminForthClass {
|
|
|
1117
1132
|
}
|
|
1118
1133
|
const record = body['record'];
|
|
1119
1134
|
|
|
1120
|
-
await interpretResource(adminUser, resource, { requestBody: body, record, oldRecord}, ActionCheckSource.EditRequest);
|
|
1135
|
+
const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body, record, oldRecord}, ActionCheckSource.EditRequest);
|
|
1121
1136
|
|
|
1122
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.edit,
|
|
1137
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.edit, allowedActions);
|
|
1123
1138
|
if (!allowed) {
|
|
1124
1139
|
return { error };
|
|
1125
1140
|
}
|
|
@@ -1188,9 +1203,9 @@ class AdminForth implements AdminForthClass {
|
|
|
1188
1203
|
return { error: `Resource '${resource.resourceId}' does not allow delete action` };
|
|
1189
1204
|
}
|
|
1190
1205
|
|
|
1191
|
-
await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
|
|
1206
|
+
const { allowedActions } = await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
|
|
1192
1207
|
|
|
1193
|
-
const { allowed, error } = checkAccess(AllowedActionsEnum.delete,
|
|
1208
|
+
const { allowed, error } = checkAccess(AllowedActionsEnum.delete, allowedActions);
|
|
1194
1209
|
if (!allowed) {
|
|
1195
1210
|
return { error };
|
|
1196
1211
|
}
|
package/package.json
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<tr>
|
|
29
29
|
<th scope="col" class="p-4">
|
|
30
30
|
<div v-if="rows && rows.length" class="flex items-center">
|
|
31
|
-
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
|
|
31
|
+
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
|
|
32
32
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
|
33
33
|
<label for="checkbox-all-search" class="sr-only">checkbox</label>
|
|
34
34
|
</div>
|
|
@@ -118,11 +118,12 @@
|
|
|
118
118
|
</td>
|
|
119
119
|
</tr>
|
|
120
120
|
|
|
121
|
-
<tr v-else v-for="(row, rowI) in rows" :key="row.id"
|
|
121
|
+
<tr @click="onClick($event,row)" v-else v-for="(row, rowI) in rows" :key="row.id"
|
|
122
122
|
class="bg-list-view-table-bg border-b dark:bg-gray-800 border-list-view-border-color dark:border-gray-700 hover:bg-list-view-table-row-hover dark:hover:bg-gray-600">
|
|
123
123
|
<td class="w-4 p-4">
|
|
124
124
|
<div class="flex items center">
|
|
125
125
|
<input
|
|
126
|
+
@click="(e)=>{e.stopPropagation()}"
|
|
126
127
|
id="checkbox-table-search-1"
|
|
127
128
|
type="checkbox"
|
|
128
129
|
:checked="checkboxesInternal.includes(row.id)"
|
|
@@ -134,6 +135,7 @@
|
|
|
134
135
|
<td v-for="c in columnsListed" class="px-6 py-4">
|
|
135
136
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
136
137
|
<component
|
|
138
|
+
@click="(e)=>{e.stopPropagation()}"
|
|
137
139
|
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
138
140
|
:meta="c?.components?.list.meta"
|
|
139
141
|
:column="c"
|
|
@@ -142,7 +144,7 @@
|
|
|
142
144
|
:resource="resource"
|
|
143
145
|
/>
|
|
144
146
|
</td>
|
|
145
|
-
<td class=" items-center px-6 py-4">
|
|
147
|
+
<td class=" items-center px-6 py-4" @click="(e)=>{e.stopPropagation()}">
|
|
146
148
|
<div class="flex">
|
|
147
149
|
<RouterLink
|
|
148
150
|
v-if="resource.options?.allowedActions.show"
|
|
@@ -291,6 +293,7 @@ IconFilterOutline,
|
|
|
291
293
|
IconPenSolid,
|
|
292
294
|
IconTrashBinSolid
|
|
293
295
|
} from '@iconify-prerendered/vue-flowbite';
|
|
296
|
+
import router from '@/router';
|
|
294
297
|
|
|
295
298
|
const coreStore = useCoreStore();
|
|
296
299
|
|
|
@@ -385,6 +388,31 @@ function onSortButtonClick(field) {
|
|
|
385
388
|
}
|
|
386
389
|
}
|
|
387
390
|
|
|
391
|
+
|
|
392
|
+
const clickTarget = ref(null);
|
|
393
|
+
async function onClick(e,row) {
|
|
394
|
+
console.log(e,row)
|
|
395
|
+
if(clickTarget.value === e.target) return;
|
|
396
|
+
clickTarget.value = e.target;
|
|
397
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
398
|
+
if (window.getSelection().toString()) return;
|
|
399
|
+
else {router.push({
|
|
400
|
+
name: 'resource-show',
|
|
401
|
+
params: {
|
|
402
|
+
resourceId: props.resource.resourceId,
|
|
403
|
+
primaryKey: row._primaryKeyValue,
|
|
404
|
+
},
|
|
405
|
+
})}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
388
416
|
async function deleteRecord(row) {
|
|
389
417
|
const data = await window.adminforth.confirm({
|
|
390
418
|
message: 'Are you sure you want to delete this item?',
|