Skip to content

Commit eedd713

Browse files
committed
Initial commit
1 parent eeeea85 commit eedd713

File tree

8 files changed

+3723
-0
lines changed

8 files changed

+3723
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
custom/node_modules
3+
dist

custom/DisableButton.vue

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<template>
2+
<div class="flex items-end justify-start gap-2 cursor-pointer" @click="openDialog()">
3+
<p class="text-justify max-h-[18px] truncate max-w-[60vw] md:max-w-none">Deactivate user</p>
4+
</div>
5+
<Dialog
6+
ref="confirmDialog"
7+
class="w-96"
8+
header="Deactivate user"
9+
:buttons="[
10+
{ label: 'Confirm', onclick: (dialog) => { console.log('Confirmed'); dialog.hide(); } },
11+
{ label: 'Cancel', onclick: (dialog) => dialog.hide() },
12+
]"
13+
>
14+
<div class="space-y-4">
15+
<p>Are you sure you want to deactivate this user?</p>
16+
</div>
17+
</Dialog>
18+
</template>
19+
20+
<script lang="ts" setup>
21+
import { Dialog } from '@/afcl';
22+
import { ref, watch } from 'vue';
23+
import { AdminUser, type AdminForthResourceCommon } from '@/types';
24+
25+
const confirmDialog = ref(null);
26+
27+
function openDialog() {
28+
confirmDialog.value.open()
29+
}
30+
31+
const props = defineProps<{
32+
checkboxes: any,
33+
meta: any,
34+
resource: AdminForthResourceCommon,
35+
adminUser: AdminUser,
36+
updateList: {
37+
type: Function,
38+
required: true
39+
},
40+
clearCheckboxes: {
41+
type: Function
42+
}
43+
}>();
44+
45+
46+
watch(props.checkboxes, (newVal) => {
47+
// Handle checkbox changes
48+
console.log("New checkboxes:", newVal)
49+
});
50+
51+
52+
</script>

custom/tsconfig.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"compilerOptions": {
3+
"baseUrl": ".", // This should point to your project root
4+
"paths": {
5+
"@/*": [
6+
"../node_modules/adminforth/dist/spa/src/*"
7+
],
8+
"*": [
9+
"../node_modules/adminforth/dist/spa/node_modules/*"
10+
],
11+
"@@/*": [
12+
"."
13+
]
14+
}
15+
}
16+
}

index.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { AdminForthPlugin, AdminForthDataTypes, AdminForthResourcePages} from "adminforth";
2+
import type { IAdminForth, IHttpServer, AdminForthResourceColumn, AdminForthResource, IAdminForthHttpResponse, AdminUser, AdminForthComponentDeclaration } from "adminforth";
3+
import type { PluginOptions } from './types.js';
4+
5+
export default class UserSoftDelete extends AdminForthPlugin {
6+
options: PluginOptions;
7+
8+
constructor(options: PluginOptions) {
9+
super(options, import.meta.url);
10+
this.options = options;
11+
}
12+
13+
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
14+
super.modifyResourceConfig(adminforth, resourceConfig);
15+
let allowDisableFunc;
16+
if (this.options.canDeactivate) {
17+
//console.log('Using canDeactivate from plugin options');
18+
allowDisableFunc = this.options.canDeactivate;
19+
} else if (resourceConfig.options.allowedActions.delete && typeof resourceConfig.options.allowedActions.delete === 'function') {
20+
//console.log('Using existing delete permission function from resource config');
21+
allowDisableFunc = resourceConfig.options.allowedActions.delete;
22+
} else if (resourceConfig.options.allowedActions.delete && typeof resourceConfig.options.allowedActions.delete === 'boolean') {
23+
//console.log('Using existing delete permission boolean from resource config:', resourceConfig.options.allowedActions.delete);
24+
allowDisableFunc = async () => resourceConfig.options.allowedActions.delete;
25+
} else {
26+
//console.log('No delete permission function found, defaulting to allow all');
27+
allowDisableFunc = async () => true;
28+
}
29+
30+
resourceConfig.options.allowedActions.delete = false;
31+
32+
resourceConfig.columns.push({
33+
name: this.options.activeFieldName,
34+
label: 'Is Active',
35+
type: AdminForthDataTypes.BOOLEAN,
36+
showIn: {
37+
[AdminForthResourcePages.list]: true,
38+
[AdminForthResourcePages.edit]: true,
39+
[AdminForthResourcePages.create]: false,
40+
[AdminForthResourcePages.filter]: true,
41+
[AdminForthResourcePages.show]: true,
42+
},
43+
filterOptions: {
44+
multiselect: false,
45+
}
46+
});
47+
48+
const beforeLoginConfirmation = this.adminforth.config.auth.beforeLoginConfirmation;
49+
const beforeLoginConfirmationArray = Array.isArray(beforeLoginConfirmation) ? beforeLoginConfirmation : [beforeLoginConfirmation];
50+
beforeLoginConfirmationArray.unshift(
51+
async({ extra, adminUser }: { adminUser: AdminUser, response: IAdminForthHttpResponse, extra?: any} )=> {
52+
const rejectResult = {
53+
body:{
54+
allowedLogin: false,
55+
redirectTo: '/login',
56+
},
57+
ok: true
58+
};
59+
if (adminUser.dbUser[this.options.activeFieldName] === false) {
60+
return rejectResult;
61+
}
62+
}
63+
);
64+
65+
if ( !resourceConfig.options.pageInjections ) {
66+
resourceConfig.options.pageInjections = {};
67+
}
68+
if ( !resourceConfig.options.pageInjections.list ) {
69+
resourceConfig.options.pageInjections.list = {};
70+
}
71+
if ( !resourceConfig.options.pageInjections.list.threeDotsDropdownItems ) {
72+
resourceConfig.options.pageInjections.list.threeDotsDropdownItems = [];
73+
}
74+
(resourceConfig.options.pageInjections.list.threeDotsDropdownItems as AdminForthComponentDeclaration[]).push(
75+
{ file: this.componentPath('DisableButton.vue') }
76+
);
77+
78+
// simply modify resourceConfig or adminforth.config. You can get access to plugin options via this.options;
79+
}
80+
81+
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
82+
// optional method where you can safely check field types after database discovery was performed
83+
}
84+
85+
instanceUniqueRepresentation(pluginOptions: any) : string {
86+
// optional method to return unique string representation of plugin instance.
87+
// Needed if plugin can have multiple instances on one resource
88+
return `single`;
89+
}
90+
91+
setupEndpoints(server: IHttpServer) {
92+
server.endpoint({
93+
method: 'POST',
94+
path: `/plugin/${this.pluginInstanceId}/example`,
95+
handler: async ({ body }) => {
96+
const { name } = body;
97+
return { hey: `Hello ${name}` };
98+
}
99+
});
100+
}
101+
102+
}

0 commit comments

Comments
 (0)