adminforth 1.2.87 → 1.2.89
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/modules/restApi.js +9 -0
- package/dist/spa/.vscode/extensions.json +6 -0
- package/dist/spa/index.html +4 -4
- package/dist/spa/package-lock.json +6 -421
- package/dist/spa/package.json +2 -10
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/.eslintrc.cjs +14 -0
- package/dist/spa/spa/.vscode/extensions.json +6 -0
- package/dist/spa/spa/README.md +39 -0
- package/dist/spa/spa/env.d.ts +1 -0
- package/dist/spa/spa/index.html +23 -0
- package/dist/spa/spa/package-lock.json +4573 -0
- package/dist/spa/spa/package.json +49 -0
- package/dist/spa/spa/postcss.config.js +6 -0
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/App.vue +314 -0
- package/dist/spa/spa/src/assets/base.css +0 -0
- package/dist/spa/spa/src/assets/logo.svg +19 -0
- package/dist/spa/spa/src/components/AcceptModal.vue +45 -0
- package/dist/spa/spa/src/components/Breadcrumbs.vue +40 -0
- package/dist/spa/spa/src/components/BreadcrumbsWithButtons.vue +26 -0
- package/dist/spa/spa/src/components/CustomDatePicker.vue +174 -0
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +218 -0
- package/dist/spa/spa/src/components/Dropdown.vue +168 -0
- package/dist/spa/spa/src/components/Filters.vue +222 -0
- package/dist/spa/spa/src/components/HelloWorld.vue +17 -0
- package/dist/spa/spa/src/components/MenuLink.vue +24 -0
- package/dist/spa/spa/src/components/ResourceForm.vue +289 -0
- package/dist/spa/{src → spa/src}/components/ResourceListTable.vue +3 -6
- package/dist/spa/spa/src/components/SingleSkeletLoader.vue +13 -0
- package/dist/spa/{src → spa/src}/components/Toast.vue +3 -9
- package/dist/spa/spa/src/components/ValueRenderer.vue +66 -0
- package/dist/spa/spa/src/components/icons/IconCalendar.vue +5 -0
- package/dist/spa/spa/src/components/icons/IconCommunity.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconDocumentation.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconEcosystem.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconSupport.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconTime.vue +5 -0
- package/dist/spa/spa/src/components/icons/IconTooling.vue +19 -0
- package/dist/spa/spa/src/index.scss +27 -0
- package/dist/spa/spa/src/main.ts +18 -0
- package/dist/spa/spa/src/router/index.ts +63 -0
- package/dist/spa/spa/src/stores/core.ts +144 -0
- package/dist/spa/spa/src/stores/modal.ts +48 -0
- package/dist/spa/spa/src/utils.ts +103 -0
- package/dist/spa/spa/src/views/CreateView.vue +156 -0
- package/dist/spa/spa/src/views/EditView.vue +157 -0
- package/dist/spa/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/spa/src/views/ListView.vue +258 -0
- package/dist/spa/spa/src/views/LoginView.vue +143 -0
- package/dist/spa/spa/src/views/ResourceParent.vue +17 -0
- package/dist/spa/spa/src/views/ShowView.vue +184 -0
- package/dist/spa/spa/tailwind.config.js +17 -0
- package/dist/spa/spa/tsconfig.app.json +14 -0
- package/dist/spa/spa/tsconfig.json +11 -0
- package/dist/spa/spa/tsconfig.node.json +19 -0
- package/dist/spa/spa/vite.config.ts +56 -0
- package/dist/spa/src/App.vue +94 -236
- package/dist/spa/src/assets/base.css +0 -2
- package/dist/spa/src/assets/logo.svg +1 -19
- package/dist/spa/src/components/AcceptModal.vue +10 -3
- package/dist/spa/src/components/Breadcrumbs.vue +2 -3
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +10 -25
- package/dist/spa/src/components/CustomDateRangePicker.vue +5 -14
- package/dist/spa/src/components/Dropdown.vue +5 -19
- package/dist/spa/src/components/Filters.vue +38 -103
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +116 -205
- package/dist/spa/src/components/ValueRenderer.vue +8 -30
- package/dist/spa/src/index.scss +1 -2
- package/dist/spa/src/main.ts +2 -2
- package/dist/spa/src/router/index.ts +19 -29
- package/dist/spa/src/stores/core.ts +59 -65
- package/dist/spa/src/stores/modal.ts +3 -13
- package/dist/spa/src/utils.ts +10 -69
- package/dist/spa/src/views/CreateView.vue +16 -69
- package/dist/spa/src/views/EditView.vue +14 -68
- package/dist/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/views/ListView.vue +371 -100
- package/dist/spa/src/views/LoginView.vue +29 -67
- package/dist/spa/src/views/ResourceParent.vue +2 -1
- package/dist/spa/src/views/ShowView.vue +25 -116
- package/dist/spa/tailwind.config.js +3 -8
- package/dist/spa/vite.config.ts +0 -13
- package/dist/types.js +30 -0
- package/modules/restApi.ts +14 -1
- package/package.json +1 -1
- package/spa/src/components/MenuLink.vue +3 -0
- package/types/AdminForthConfig.ts +6 -0
- package/dist/spa/src/types/AdminForthConfig.ts +0 -1477
- package/dist/spa/src/types/FrontendAPI.ts +0 -121
- /package/dist/spa/{public → spa/public}/assets/favicon.png +0 -0
- /package/dist/spa/{src → spa/src}/components/CustomRangePicker.vue +0 -0
- /package/dist/spa/{src → spa/src}/components/SkeleteLoader.vue +0 -0
- /package/dist/spa/{src → spa/src}/composables/useFrontendApi.ts +0 -0
- /package/dist/spa/{src → spa/src}/composables/useStores.ts +0 -0
- /package/dist/spa/{src → spa/src}/spa_types/core.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/filters.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/toast.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/user.ts +0 -0
|
@@ -2,27 +2,20 @@
|
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<Teleport to="body">
|
|
4
4
|
<Filters
|
|
5
|
-
:columns="coreStore.
|
|
5
|
+
:columns="coreStore.resourceColumns"
|
|
6
|
+
v-model:filters="filters"
|
|
6
7
|
:columnsMinMax="columnsMinMax" :show="filtersShow"
|
|
7
8
|
@hide="filtersShow = false"
|
|
8
9
|
/>
|
|
9
10
|
</Teleport>
|
|
10
11
|
|
|
11
|
-
<component
|
|
12
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.beforeBreadcrumbs || []"
|
|
13
|
-
:is="getCustomComponent(c)"
|
|
14
|
-
:meta="c.meta"
|
|
15
|
-
:resource="coreStore.resource"
|
|
16
|
-
:adminUser="coreStore.adminUser"
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
12
|
<BreadcrumbsWithButtons>
|
|
20
13
|
<button
|
|
21
14
|
@click="()=>{checkboxes = []}"
|
|
22
15
|
v-if="checkboxes.length"
|
|
23
16
|
data-tooltip-target="tooltip-remove-all"
|
|
24
17
|
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-
|
|
18
|
+
class="flex gap-1 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"
|
|
26
19
|
>
|
|
27
20
|
<IconBanOutline class="w-5 h-5 "/>
|
|
28
21
|
|
|
@@ -34,11 +27,9 @@
|
|
|
34
27
|
</button>
|
|
35
28
|
|
|
36
29
|
<button
|
|
37
|
-
v-if="checkboxes.length"
|
|
38
|
-
v-for="(action,i) in coreStore.resource?.options?.bulkActions"
|
|
39
|
-
:key="action.id"
|
|
30
|
+
v-if="checkboxes.length" v-for="(action,i) in allCheckedActions" :key="action.id"
|
|
40
31
|
@click="startBulkAction(action.id)"
|
|
41
|
-
class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded
|
|
32
|
+
class="flex gap-1 items-center py-1 px-3 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"
|
|
42
33
|
: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',
|
|
43
34
|
'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
|
|
44
35
|
}"
|
|
@@ -51,147 +42,436 @@
|
|
|
51
42
|
{{ `${action.label} (${checkboxes.length})` }}
|
|
52
43
|
</button>
|
|
53
44
|
|
|
54
|
-
<RouterLink v-if="
|
|
45
|
+
<RouterLink v-if="allowedActions.create"
|
|
55
46
|
:to="{ name: 'resource-create', params: { resourceId: $route.params.resourceId } }"
|
|
56
|
-
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
|
|
47
|
+
class="flex items-center py-1 px-3 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"
|
|
57
48
|
>
|
|
58
49
|
<IconPlusOutline class="w-4 h-4 me-2"/>
|
|
59
50
|
Create
|
|
60
51
|
</RouterLink>
|
|
61
52
|
|
|
62
53
|
<button
|
|
63
|
-
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
|
|
54
|
+
class="flex gap-1 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"
|
|
64
55
|
@click="()=>{filtersShow = !filtersShow}"
|
|
65
|
-
v-if="coreStore.resource?.options?.allowedActions?.filter"
|
|
66
56
|
>
|
|
67
57
|
<IconFilterOutline class="w-4 h-4 me-2"/>
|
|
68
58
|
Filter
|
|
69
59
|
<span
|
|
70
60
|
class="bg-red-100 text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400"
|
|
71
|
-
v-if="
|
|
72
|
-
{{
|
|
73
|
-
|
|
61
|
+
v-if="filters.length">
|
|
62
|
+
{{ filters.length }}
|
|
63
|
+
</span>
|
|
74
64
|
</button>
|
|
75
65
|
</BreadcrumbsWithButtons>
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@update:records="getList"
|
|
92
|
-
:sort="sort"
|
|
93
|
-
:pageSize="pageSize"
|
|
94
|
-
:totalRows="totalRows"
|
|
95
|
-
:checkboxes="checkboxes"
|
|
96
|
-
/>
|
|
97
|
-
|
|
98
|
-
<component
|
|
99
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.bottom || []"
|
|
100
|
-
:is="getCustomComponent(c)"
|
|
101
|
-
:meta="c.meta"
|
|
102
|
-
:resource="coreStore.resource"
|
|
103
|
-
:adminUser="coreStore.adminUser"
|
|
104
|
-
/>
|
|
67
|
+
<!-- table -->
|
|
68
|
+
<div class="relative overflow-x-auto shadow-md sm:rounded-lg dark:shadow-2xl">
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
<!-- skelet loader -->
|
|
72
|
+
<div role="status" v-if="!coreStore.resourceColumns"
|
|
73
|
+
class="max-w p-4 space-y-4 divide-y divide-gray-200 rounded shadow animate-pulse dark:divide-gray-700 md:p-6 dark:border-gray-700">
|
|
74
|
+
<div class="flex items-center justify-between h-16">
|
|
75
|
+
<div>
|
|
76
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
77
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
80
|
+
</div>
|
|
105
81
|
|
|
82
|
+
<div class="flex items-center justify-between h-16 pt-4" v-for="i in new Array(10)">
|
|
83
|
+
<div>
|
|
84
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
85
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
88
|
+
</div>
|
|
89
|
+
<span class="sr-only">Loading...</span>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<table v-else class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
|
93
|
+
<thead class="text-xs text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
|
94
|
+
<tr>
|
|
95
|
+
<th scope="col" class="p-4">
|
|
96
|
+
<div v-if="rows && rows.length" class="flex items-center">
|
|
97
|
+
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
|
|
98
|
+
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">
|
|
99
|
+
<label for="checkbox-all-search" class="sr-only">checkbox</label>
|
|
100
|
+
</div>
|
|
101
|
+
</th>
|
|
102
|
+
|
|
103
|
+
<th v-for="c in columnsListed" scope="col" class="px-6 py-3">
|
|
104
|
+
<div @click="() => c.sortable && onSortButtonClick(c.name)" class="flex items-center " :class="{'cursor-pointer':c.sortable}">
|
|
105
|
+
{{ c.label }}
|
|
106
|
+
|
|
107
|
+
<div v-if="c.sortable"
|
|
108
|
+
:style="{ 'color':ascArr.includes(c.name)?'green':descArr.includes(c.name)?'red':'currentColor'}">
|
|
109
|
+
<svg v-if="ascArr.includes(c.name) || descArr.includes(c.name)" class="w-3 h-3 ms-1.5"
|
|
110
|
+
:class="{'rotate-180':descArr.includes(c.name)}" viewBox="0 0 24 24">
|
|
111
|
+
<path
|
|
112
|
+
d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847"/>
|
|
113
|
+
</svg>
|
|
114
|
+
<svg v-else class="w-3 h-3 ms-1.5 opacity-30" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
|
115
|
+
fill='currentColor'
|
|
116
|
+
viewBox="0 0 24 24">
|
|
117
|
+
<path
|
|
118
|
+
d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 1.086Zm6.852 1.952H8.574a2.072 2.072 0 0 0-1.847 1.087 1.9 1.9 0 0 0 .11 1.985l3.426 5.05a2.123 2.123 0 0 0 3.472 0l3.427-5.05a1.9 1.9 0 0 0 .11-1.985 2.074 2.074 0 0 0-1.846-1.087Z"/>
|
|
119
|
+
</svg>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</th>
|
|
123
|
+
|
|
124
|
+
<th scope="col" class="px-6 py-3">
|
|
125
|
+
Actions
|
|
126
|
+
</th>
|
|
127
|
+
</tr>
|
|
128
|
+
</thead>
|
|
129
|
+
<tbody>
|
|
130
|
+
<tr v-if="!rows" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
|
131
|
+
<td :colspan="coreStore.resourceColumns.length + 2">
|
|
132
|
+
|
|
133
|
+
<div role="status"
|
|
134
|
+
class="max-w p-4 space-y-4 divide-y divide-gray-200 rounded animate-pulse dark:divide-gray-700 md:p-6 dark:border-gray-700">
|
|
135
|
+
<div class="flex items-center justify-between">
|
|
136
|
+
<div>
|
|
137
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
138
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="flex items-center justify-between pt-4">
|
|
143
|
+
<div>
|
|
144
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
145
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="flex items-center justify-between pt-4">
|
|
150
|
+
<div>
|
|
151
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
152
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
155
|
+
</div>
|
|
156
|
+
<div class="flex items-center justify-between pt-4">
|
|
157
|
+
<div>
|
|
158
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
159
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="flex items-center justify-between pt-4">
|
|
164
|
+
<div>
|
|
165
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-600 w-24 mb-2.5"></div>
|
|
166
|
+
<div class="w-32 h-2 bg-gray-200 rounded-full dark:bg-gray-700"></div>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="h-2.5 bg-gray-300 rounded-full dark:bg-gray-700 w-12"></div>
|
|
169
|
+
</div>
|
|
170
|
+
<span class="sr-only">Loading...</span>
|
|
171
|
+
</div>
|
|
172
|
+
</td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr v-else-if="rows.length === 0" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
|
175
|
+
<td :colspan="coreStore.resourceColumns.length + 2">
|
|
176
|
+
|
|
177
|
+
<div id="toast-simple"
|
|
178
|
+
class=" mx-auto my-5 flex items-center w-full max-w-xs p-4 space-x-4 rtl:space-x-reverse text-gray-500 bg-white divide-x rtl:divide-x-reverse divide-gray-200 dark:text-gray-400 dark:divide-gray-700 space-x dark:bg-gray-800"
|
|
179
|
+
role="alert">
|
|
180
|
+
<IconInboxOutline class="w-6 h-6 text-gray-500 dark:text-gray-400"/>
|
|
181
|
+
<div class="ps-4 text-sm font-normal">No items here yet</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
</td>
|
|
185
|
+
</tr>
|
|
186
|
+
|
|
187
|
+
<tr v-else v-for="(row, rowI) in rows" :key="row.id"
|
|
188
|
+
class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
|
|
189
|
+
<td class="w-4 p-4">
|
|
190
|
+
<div class="flex items center">
|
|
191
|
+
<input
|
|
192
|
+
id="checkbox-table-search-1"
|
|
193
|
+
type="checkbox"
|
|
194
|
+
:checked="checkboxes.includes(row.id)"
|
|
195
|
+
@change="(e)=>{addToCheckedValues(row.id)}"
|
|
196
|
+
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">
|
|
197
|
+
<label for="checkbox-table-search-1" class="sr-only">checkbox</label>
|
|
198
|
+
</div>
|
|
199
|
+
</td>
|
|
200
|
+
<td v-for="c in columnsListed" class="px-6 py-4">
|
|
201
|
+
<ValueRenderer :column="c" :row="row"/>
|
|
202
|
+
</td>
|
|
203
|
+
<td class="flex items-center px-6 py-4">
|
|
204
|
+
|
|
205
|
+
<RouterLink
|
|
206
|
+
:to="{ name: 'resource-show', params: { resourceId: $route.params.resourceId, primaryKey: row._primaryKeyValue } }"
|
|
207
|
+
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
|
208
|
+
:data-tooltip-target="`tooltip-show-${rowI}`"
|
|
209
|
+
>
|
|
210
|
+
<IconEyeSolid class="w-5 h-5 me-2"/>
|
|
211
|
+
</RouterLink>
|
|
212
|
+
|
|
213
|
+
<div :id="`tooltip-show-${rowI}`"
|
|
214
|
+
role="tooltip"
|
|
215
|
+
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">
|
|
216
|
+
Show item
|
|
217
|
+
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<RouterLink v-if="allowedActions.edit"
|
|
221
|
+
:to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: row._primaryKeyValue } }"
|
|
222
|
+
class="font-medium text-blue-600 dark:text-blue-500 hover:underline ms-3"
|
|
223
|
+
:data-tooltip-target="`tooltip-edit-${rowI}`"
|
|
224
|
+
>
|
|
225
|
+
<IconPenSolid class="w-5 h-5 me-2"/>
|
|
226
|
+
</RouterLink>
|
|
227
|
+
|
|
228
|
+
<div :id="`tooltip-edit-${rowI}`"
|
|
229
|
+
role="tooltip"
|
|
230
|
+
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">
|
|
231
|
+
Edit
|
|
232
|
+
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<button v-if="allowedActions.delete"
|
|
236
|
+
class="font-medium text-red-600 dark:text-red-500 hover:underline ms-3"
|
|
237
|
+
:data-tooltip-target="`tooltip-delete-${rowI}`"
|
|
238
|
+
@click="showDeleteModal(row)"
|
|
239
|
+
>
|
|
240
|
+
<IconTrashBinSolid class="w-5 h-5 me-2"/>
|
|
241
|
+
</button>
|
|
242
|
+
|
|
243
|
+
<div :id="`tooltip-delete-${rowI}`"
|
|
244
|
+
role="tooltip"
|
|
245
|
+
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">
|
|
246
|
+
Delete
|
|
247
|
+
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
248
|
+
</div>
|
|
249
|
+
</td>
|
|
250
|
+
</tr>
|
|
251
|
+
</tbody>
|
|
252
|
+
</table>
|
|
253
|
+
</div>
|
|
254
|
+
<!-- pagination -->
|
|
255
|
+
<div class="flex flex-col items-center mt-4 xs:flex-row xs:justify-between xs:items-center"
|
|
256
|
+
v-if="rows && totalRows >= pageSize && totalRows > 0"
|
|
257
|
+
>
|
|
258
|
+
<!-- Help text -->
|
|
259
|
+
<span class="text-sm text-gray-700 dark:text-gray-400">
|
|
260
|
+
Showing <span class="font-semibold text-gray-900 dark:text-white">
|
|
261
|
+
{{ (page - 1) * pageSize + 1 }}
|
|
262
|
+
</span> to <span class="font-semibold text-gray-900 dark:text-white">
|
|
263
|
+
{{ Math.min(page * pageSize, totalRows) }}
|
|
264
|
+
</span> of <span class="font-semibold text-gray-900 dark:text-white">{{
|
|
265
|
+
totalRows
|
|
266
|
+
}}</span> Entries
|
|
267
|
+
</span>
|
|
268
|
+
<div class="inline-flex mt-2 xs:mt-0">
|
|
269
|
+
<!-- Buttons -->
|
|
270
|
+
<button
|
|
271
|
+
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 rounded-s 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 disabled:opacity-50"
|
|
272
|
+
@click="page--" :disabled="page <= 1">
|
|
273
|
+
<svg class="w-3.5 h-3.5 me-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
274
|
+
viewBox="0 0 14 10">
|
|
275
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
276
|
+
d="M13 5H1m0 0 4 4M1 5l4-4"/>
|
|
277
|
+
</svg>
|
|
278
|
+
Prev
|
|
279
|
+
</button>
|
|
280
|
+
<button
|
|
281
|
+
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-r-0 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 disabled:opacity-50"
|
|
282
|
+
@click="page = 1" :disabled="page <= 1">
|
|
283
|
+
<!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
|
|
284
|
+
1
|
|
285
|
+
</button>
|
|
286
|
+
<input type="text"
|
|
287
|
+
class="w-10 py-1.5 px-3 text-sm text-center text-gray-700 border border-gray-300 dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800 z-10"
|
|
288
|
+
v-model="page"/>
|
|
289
|
+
|
|
290
|
+
<button
|
|
291
|
+
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 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 disabled:opacity-50"
|
|
292
|
+
@click="page = totalPages" :disabled="page >= totalPages">
|
|
293
|
+
{{ totalPages }}
|
|
294
|
+
<!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
|
|
295
|
+
</button>
|
|
296
|
+
<button
|
|
297
|
+
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white border-l-0 rounded-e 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 disabled:opacity-50"
|
|
298
|
+
|
|
299
|
+
@click="page++" :disabled="page >= totalPages">
|
|
300
|
+
Next
|
|
301
|
+
<svg class="w-3.5 h-3.5 ms-2 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
302
|
+
viewBox="0 0 14 10">
|
|
303
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
304
|
+
d="M1 5h12m0 0L9 1m4 4L9 9"/>
|
|
305
|
+
</svg>
|
|
306
|
+
</button>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
106
309
|
</div>
|
|
107
310
|
</template>
|
|
108
311
|
|
|
109
312
|
<script setup>
|
|
313
|
+
import {ref, onMounted, watch, computed} from 'vue';
|
|
314
|
+
import {callAdminForthApi, getIcon} from '@/utils';
|
|
315
|
+
import {useRoute} from 'vue-router';
|
|
316
|
+
import {useCoreStore} from '@/stores/core';
|
|
317
|
+
import {useModalStore} from '@/stores/modal';
|
|
110
318
|
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
111
|
-
import
|
|
112
|
-
import { useCoreStore } from '@/stores/core';
|
|
113
|
-
import { useModalStore } from '@/stores/modal';
|
|
114
|
-
import { useFiltersStore } from '@/stores/filters';
|
|
115
|
-
import { callAdminForthApi, getIcon } from '@/utils';
|
|
116
|
-
import { initFlowbite } from 'flowbite';
|
|
117
|
-
import { computed, onMounted, ref, watch } from 'vue';
|
|
118
|
-
import { useRoute } from 'vue-router';
|
|
119
|
-
import { showErrorTost } from '@/composables/useFrontendApi'
|
|
319
|
+
import {initFlowbite} from 'flowbite'
|
|
120
320
|
|
|
121
321
|
import ValueRenderer from '@/components/ValueRenderer.vue';
|
|
122
|
-
import { getCustomComponent } from '@/utils';
|
|
123
|
-
|
|
124
322
|
|
|
125
323
|
import {
|
|
126
|
-
|
|
127
|
-
|
|
324
|
+
IconChevronDoubleLeftOutline,
|
|
325
|
+
IconChevronDoubleRightOutline,
|
|
326
|
+
IconInboxFullSolid,
|
|
327
|
+
IconInboxOutline,
|
|
128
328
|
IconPlusOutline
|
|
129
329
|
} from '@iconify-prerendered/vue-flowbite';
|
|
130
330
|
|
|
331
|
+
import {
|
|
332
|
+
IconEyeSolid,
|
|
333
|
+
IconTrashBinSolid,
|
|
334
|
+
IconPenSolid,
|
|
335
|
+
IconFilterOutline, IconBanOutline
|
|
336
|
+
} from '@iconify-prerendered/vue-flowbite';
|
|
337
|
+
|
|
131
338
|
import Filters from '@/components/Filters.vue';
|
|
132
339
|
|
|
133
340
|
const filtersShow = ref(false);
|
|
134
341
|
|
|
342
|
+
|
|
135
343
|
const coreStore = useCoreStore();
|
|
136
|
-
const
|
|
344
|
+
const modalStore = useModalStore();
|
|
137
345
|
|
|
138
346
|
const route = useRoute();
|
|
347
|
+
const checkboxes = ref([]);
|
|
139
348
|
|
|
140
349
|
const page = ref(1);
|
|
350
|
+
const filters = ref([]);
|
|
141
351
|
const columnsMinMax = ref({});
|
|
142
352
|
const sort = ref([]);
|
|
353
|
+
const fetchStatus = ref({pending: false, error: null, success: false});
|
|
143
354
|
|
|
144
355
|
const rows = ref(null);
|
|
145
356
|
const totalRows = ref(0);
|
|
146
|
-
const
|
|
357
|
+
const allCheckedActions = ref([]);
|
|
358
|
+
const allowedActions = ref({});
|
|
359
|
+
|
|
147
360
|
|
|
148
361
|
const DEFAULT_PAGE_SIZE = 10;
|
|
149
362
|
|
|
363
|
+
const columnsListed = computed(() => coreStore.resourceColumns?.filter(c => c.showIn.includes('list')));
|
|
150
364
|
|
|
151
|
-
|
|
365
|
+
async function selectAll(value) {
|
|
366
|
+
console.log('select all');
|
|
367
|
+
rows.value.forEach((r) => {
|
|
368
|
+
if (!checkboxes.value.includes(r.id)) {
|
|
369
|
+
checkboxes.value.push(r.id)
|
|
370
|
+
} else {
|
|
371
|
+
checkboxes.value = checkboxes.value.filter((item) => item !== r.id)
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
// checkboxes.value = rows.value.map((v) => v.id);
|
|
375
|
+
}
|
|
152
376
|
|
|
377
|
+
const pageSize = computed(() => coreStore.resourceById[route.params.resourceId]?.pageSize || DEFAULT_PAGE_SIZE);
|
|
378
|
+
const totalPages = computed(() => Math.ceil(totalRows.value / pageSize.value));
|
|
379
|
+
const allFromThisPageChecked = computed(() => {
|
|
380
|
+
if (!rows.value) return false;
|
|
381
|
+
return rows.value.every((r) => checkboxes.value.includes(r.id));
|
|
382
|
+
});
|
|
383
|
+
const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
|
|
384
|
+
const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
|
|
153
385
|
|
|
154
386
|
watch([page], async () => {
|
|
155
|
-
await
|
|
387
|
+
await init();
|
|
156
388
|
});
|
|
157
389
|
|
|
158
|
-
watch(
|
|
390
|
+
watch([filters], async () => {
|
|
159
391
|
page.value = 1;
|
|
160
|
-
checkboxes.value = [];
|
|
161
|
-
|
|
162
392
|
await getList();
|
|
163
393
|
}, {deep: true});
|
|
164
394
|
|
|
165
395
|
watch([sort], async () => {
|
|
166
|
-
await
|
|
396
|
+
await init();
|
|
167
397
|
}, {deep: true});
|
|
168
398
|
|
|
399
|
+
function onSortButtonClick(field) {
|
|
400
|
+
if (fetchStatus.value.pending) return;
|
|
401
|
+
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
402
|
+
console.log('sortIndex', sortIndex);
|
|
403
|
+
if (sortIndex === -1) {
|
|
404
|
+
sort.value = [{field, direction: 'asc'}, ...sort.value];
|
|
405
|
+
} else {
|
|
406
|
+
const sortField = sort.value[sortIndex];
|
|
407
|
+
if (sortField.direction === 'asc') {
|
|
408
|
+
sort.value[sortIndex].direction = 'desc';
|
|
409
|
+
} else {
|
|
410
|
+
sort.value.splice(sortIndex, 1);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
169
414
|
|
|
170
415
|
async function getList() {
|
|
171
416
|
rows.value = null;
|
|
417
|
+
fetchStatus.value.pending = true;
|
|
172
418
|
const data = await callAdminForthApi({
|
|
173
419
|
path: '/get_resource_data',
|
|
174
420
|
method: 'POST',
|
|
175
421
|
body: {
|
|
176
|
-
source: 'list',
|
|
177
422
|
resourceId: route.params.resourceId,
|
|
178
423
|
limit: pageSize.value,
|
|
179
424
|
offset: (page.value - 1) * pageSize.value,
|
|
180
|
-
filters:
|
|
425
|
+
filters: filters.value,
|
|
181
426
|
sort: sort.value,
|
|
182
427
|
}
|
|
183
428
|
});
|
|
184
|
-
|
|
185
|
-
showErrorTost(data.error);
|
|
186
|
-
rows.value = [];
|
|
187
|
-
totalRows.value = 0;
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
429
|
+
fetchStatus.value.pending = false;
|
|
190
430
|
rows.value = data.data?.map(row => {
|
|
191
|
-
row._primaryKeyValue = row[coreStore.
|
|
431
|
+
row._primaryKeyValue = row[coreStore.resourceColumns.find(c => c.primaryKey).name];
|
|
192
432
|
return row;
|
|
193
433
|
});
|
|
194
434
|
totalRows.value = data.total;
|
|
435
|
+
allCheckedActions.value = data.options?.bulkActions || [];
|
|
436
|
+
allowedActions.value = data.options?.allowedActions;
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
setTimeout(() => {
|
|
440
|
+
initFlowbite();
|
|
441
|
+
console.log('initFlowbite');
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
function showDeleteModal(row) {
|
|
447
|
+
if (!coreStore.config?.deleteConfirmation) {
|
|
448
|
+
return deleteRecord(row);
|
|
449
|
+
}
|
|
450
|
+
modalStore.setModalContent({
|
|
451
|
+
content: 'Are you sure you want to delete this item?',
|
|
452
|
+
acceptText: 'Delete',
|
|
453
|
+
cancelText: 'Cancel',
|
|
454
|
+
});
|
|
455
|
+
modalStore.setOnAcceptFunction(() => {
|
|
456
|
+
return deleteRecord(row)
|
|
457
|
+
})
|
|
458
|
+
console.log('row', row);
|
|
459
|
+
modalStore.togleModal();
|
|
460
|
+
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async function deleteRecord(row) {
|
|
464
|
+
await callAdminForthApi({
|
|
465
|
+
path: '/delete_record',
|
|
466
|
+
method: 'POST',
|
|
467
|
+
body: {
|
|
468
|
+
resourceId: route.params.resourceId,
|
|
469
|
+
primaryKey: row._primaryKeyValue,
|
|
470
|
+
recordId: row.id
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
await getList();
|
|
474
|
+
modalStore.resetmodalState()
|
|
195
475
|
}
|
|
196
476
|
|
|
197
477
|
async function startBulkAction(actionId) {
|
|
@@ -205,32 +485,25 @@ async function startBulkAction(actionId) {
|
|
|
205
485
|
|
|
206
486
|
}
|
|
207
487
|
});
|
|
208
|
-
if (data?.
|
|
488
|
+
if (data?.status === 'success') {
|
|
209
489
|
checkboxes.value = [];
|
|
210
|
-
await getList();
|
|
211
|
-
}
|
|
212
|
-
if (data?.error) {
|
|
213
|
-
showErrorTost(data.error);
|
|
214
490
|
}
|
|
491
|
+
await getList();
|
|
215
492
|
}
|
|
216
493
|
|
|
217
|
-
|
|
494
|
+
function addToCheckedValues(id) {
|
|
495
|
+
if (checkboxes.value.includes(id)) {
|
|
496
|
+
checkboxes.value = checkboxes.value.filter((item) => item !== id);
|
|
497
|
+
} else {
|
|
498
|
+
checkboxes.value.push(id);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
218
501
|
|
|
219
502
|
async function init() {
|
|
220
|
-
|
|
221
|
-
await coreStore.fetchResourceFull({
|
|
503
|
+
await coreStore.fetchColumns({
|
|
222
504
|
resourceId: route.params.resourceId
|
|
223
505
|
});
|
|
224
506
|
|
|
225
|
-
if (coreStore.resource.options?.defaultSort) {
|
|
226
|
-
sort.value = [{
|
|
227
|
-
field: coreStore.resource.options.defaultSort.columnName,
|
|
228
|
-
direction: coreStore.resource.options.defaultSort.direction
|
|
229
|
-
}];
|
|
230
|
-
} else {
|
|
231
|
-
sort.value = [];
|
|
232
|
-
}
|
|
233
|
-
|
|
234
507
|
await getList();
|
|
235
508
|
columnsMinMax.value = await callAdminForthApi({
|
|
236
509
|
path: '/get_min_max_for_columns',
|
|
@@ -242,16 +515,14 @@ async function init() {
|
|
|
242
515
|
}
|
|
243
516
|
|
|
244
517
|
onMounted(async () => {
|
|
245
|
-
initFlowbite();
|
|
246
|
-
|
|
247
518
|
await init();
|
|
248
|
-
|
|
249
519
|
});
|
|
250
520
|
|
|
251
521
|
// on route param change
|
|
252
522
|
watch(() => route.params.resourceId, async () => {
|
|
253
|
-
|
|
523
|
+
filters.value = [];
|
|
254
524
|
checkboxes.value = [];
|
|
525
|
+
sort.value = [];
|
|
255
526
|
await init();
|
|
256
527
|
});
|
|
257
528
|
|