adminforth 1.2.95 → 1.2.98
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 +2 -1
- package/dist/modules/restApi.js +27 -29
- package/dist/spa/index.html +4 -4
- package/dist/spa/package-lock.json +421 -6
- package/dist/spa/package.json +10 -2
- package/dist/spa/src/App.vue +236 -94
- package/dist/spa/src/assets/base.css +2 -0
- package/dist/spa/src/assets/logo.svg +19 -1
- package/dist/spa/src/components/AcceptModal.vue +3 -10
- package/dist/spa/src/components/Breadcrumbs.vue +3 -2
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +25 -10
- package/dist/spa/src/components/CustomDateRangePicker.vue +14 -5
- package/dist/spa/src/components/Dropdown.vue +19 -5
- package/dist/spa/src/components/Filters.vue +103 -38
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +205 -116
- package/dist/spa/{spa/src → src}/components/ResourceListTable.vue +6 -3
- package/dist/spa/{spa/src → src}/components/Toast.vue +9 -3
- package/dist/spa/src/components/ValueRenderer.vue +30 -8
- package/dist/spa/src/index.scss +2 -1
- package/dist/spa/src/main.ts +2 -2
- package/dist/spa/src/router/index.ts +29 -19
- package/dist/spa/src/stores/core.ts +65 -59
- package/dist/spa/src/stores/modal.ts +13 -3
- package/dist/spa/src/types/AdminForthConfig.ts +1477 -0
- package/dist/spa/src/types/FrontendAPI.ts +121 -0
- package/dist/spa/src/utils.ts +69 -10
- package/dist/spa/src/views/CreateView.vue +69 -16
- package/dist/spa/src/views/EditView.vue +68 -14
- package/dist/spa/src/views/ListView.vue +100 -371
- package/dist/spa/src/views/LoginView.vue +67 -29
- package/dist/spa/src/views/ResourceParent.vue +1 -2
- package/dist/spa/src/views/ShowView.vue +116 -25
- package/dist/spa/tailwind.config.js +8 -3
- package/dist/spa/vite.config.ts +13 -0
- package/index.ts +2 -1
- package/modules/restApi.ts +31 -31
- package/package.json +1 -1
- package/dist/spa/.vscode/extensions.json +0 -6
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/.eslintrc.cjs +0 -14
- package/dist/spa/spa/.vscode/extensions.json +0 -6
- package/dist/spa/spa/README.md +0 -39
- package/dist/spa/spa/env.d.ts +0 -1
- package/dist/spa/spa/index.html +0 -23
- package/dist/spa/spa/package-lock.json +0 -4573
- package/dist/spa/spa/package.json +0 -49
- package/dist/spa/spa/postcss.config.js +0 -6
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/App.vue +0 -314
- package/dist/spa/spa/src/assets/base.css +0 -0
- package/dist/spa/spa/src/assets/logo.svg +0 -19
- package/dist/spa/spa/src/components/AcceptModal.vue +0 -45
- package/dist/spa/spa/src/components/Breadcrumbs.vue +0 -40
- package/dist/spa/spa/src/components/BreadcrumbsWithButtons.vue +0 -26
- package/dist/spa/spa/src/components/CustomDatePicker.vue +0 -174
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +0 -218
- package/dist/spa/spa/src/components/Dropdown.vue +0 -168
- package/dist/spa/spa/src/components/Filters.vue +0 -222
- package/dist/spa/spa/src/components/HelloWorld.vue +0 -17
- package/dist/spa/spa/src/components/MenuLink.vue +0 -24
- package/dist/spa/spa/src/components/ResourceForm.vue +0 -289
- package/dist/spa/spa/src/components/SingleSkeletLoader.vue +0 -13
- package/dist/spa/spa/src/components/ValueRenderer.vue +0 -66
- package/dist/spa/spa/src/components/icons/IconCalendar.vue +0 -5
- package/dist/spa/spa/src/components/icons/IconCommunity.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconDocumentation.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconEcosystem.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconSupport.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconTime.vue +0 -5
- package/dist/spa/spa/src/components/icons/IconTooling.vue +0 -19
- package/dist/spa/spa/src/index.scss +0 -27
- package/dist/spa/spa/src/main.ts +0 -18
- package/dist/spa/spa/src/router/index.ts +0 -63
- package/dist/spa/spa/src/stores/core.ts +0 -144
- package/dist/spa/spa/src/stores/modal.ts +0 -48
- package/dist/spa/spa/src/utils.ts +0 -103
- package/dist/spa/spa/src/views/CreateView.vue +0 -156
- package/dist/spa/spa/src/views/EditView.vue +0 -157
- package/dist/spa/spa/src/views/HomeView.vue +0 -8
- package/dist/spa/spa/src/views/ListView.vue +0 -258
- package/dist/spa/spa/src/views/LoginView.vue +0 -143
- package/dist/spa/spa/src/views/ResourceParent.vue +0 -17
- package/dist/spa/spa/src/views/ShowView.vue +0 -184
- package/dist/spa/spa/tailwind.config.js +0 -17
- package/dist/spa/spa/tsconfig.app.json +0 -14
- package/dist/spa/spa/tsconfig.json +0 -11
- package/dist/spa/spa/tsconfig.node.json +0 -19
- package/dist/spa/spa/vite.config.ts +0 -56
- package/dist/spa/src/views/HomeView.vue +0 -8
- package/dist/types.js +0 -30
- /package/dist/spa/{spa/public → public}/assets/favicon.png +0 -0
- /package/dist/spa/{spa/src → src}/components/CustomRangePicker.vue +0 -0
- /package/dist/spa/{spa/src → src}/components/SkeleteLoader.vue +0 -0
- /package/dist/spa/{spa/src → src}/composables/useFrontendApi.ts +0 -0
- /package/dist/spa/{spa/src → src}/composables/useStores.ts +0 -0
- /package/dist/spa/{spa/src → src}/spa_types/core.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/filters.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/toast.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/user.ts +0 -0
|
@@ -2,20 +2,27 @@
|
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<Teleport to="body">
|
|
4
4
|
<Filters
|
|
5
|
-
:columns="coreStore.
|
|
6
|
-
v-model:filters="filters"
|
|
5
|
+
:columns="coreStore.resource?.columns"
|
|
7
6
|
:columnsMinMax="columnsMinMax" :show="filtersShow"
|
|
8
7
|
@hide="filtersShow = false"
|
|
9
8
|
/>
|
|
10
9
|
</Teleport>
|
|
11
10
|
|
|
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
|
+
|
|
12
19
|
<BreadcrumbsWithButtons>
|
|
13
20
|
<button
|
|
14
21
|
@click="()=>{checkboxes = []}"
|
|
15
22
|
v-if="checkboxes.length"
|
|
16
23
|
data-tooltip-target="tooltip-remove-all"
|
|
17
24
|
data-tooltip-placement="bottom"
|
|
18
|
-
class="flex gap-1 items-center py-1 px-3 me-2
|
|
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-darkListTable dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 rounded-default"
|
|
19
26
|
>
|
|
20
27
|
<IconBanOutline class="w-5 h-5 "/>
|
|
21
28
|
|
|
@@ -27,9 +34,11 @@
|
|
|
27
34
|
</button>
|
|
28
35
|
|
|
29
36
|
<button
|
|
30
|
-
v-if="checkboxes.length"
|
|
37
|
+
v-if="checkboxes.length"
|
|
38
|
+
v-for="(action,i) in coreStore.resource?.options?.bulkActions"
|
|
39
|
+
:key="action.id"
|
|
31
40
|
@click="startBulkAction(action.id)"
|
|
32
|
-
class="flex gap-1 items-center py-1 px-3
|
|
41
|
+
class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default 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"
|
|
33
42
|
: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',
|
|
34
43
|
'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
|
|
35
44
|
}"
|
|
@@ -42,436 +51,147 @@
|
|
|
42
51
|
{{ `${action.label} (${checkboxes.length})` }}
|
|
43
52
|
</button>
|
|
44
53
|
|
|
45
|
-
<RouterLink v-if="allowedActions
|
|
54
|
+
<RouterLink v-if="coreStore.resource?.options?.allowedActions?.create"
|
|
46
55
|
:to="{ name: 'resource-create', params: { resourceId: $route.params.resourceId } }"
|
|
47
|
-
class="flex items-center py-1 px-3
|
|
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 rounded-default"
|
|
48
57
|
>
|
|
49
58
|
<IconPlusOutline class="w-4 h-4 me-2"/>
|
|
50
59
|
Create
|
|
51
60
|
</RouterLink>
|
|
52
61
|
|
|
53
62
|
<button
|
|
54
|
-
class="flex gap-1 items-center py-1 px-3 me-2
|
|
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 rounded-default"
|
|
55
64
|
@click="()=>{filtersShow = !filtersShow}"
|
|
65
|
+
v-if="coreStore.resource?.options?.allowedActions?.filter"
|
|
56
66
|
>
|
|
57
67
|
<IconFilterOutline class="w-4 h-4 me-2"/>
|
|
58
68
|
Filter
|
|
59
69
|
<span
|
|
60
70
|
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"
|
|
61
|
-
v-if="filters.length">
|
|
62
|
-
{{ filters.length }}
|
|
63
|
-
|
|
71
|
+
v-if="filtersStore.filters.length">
|
|
72
|
+
{{ filtersStore.filters.length }}
|
|
73
|
+
</span>
|
|
64
74
|
</button>
|
|
65
75
|
</BreadcrumbsWithButtons>
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
<component
|
|
78
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.afterBreadcrumbs || []"
|
|
79
|
+
:is="getCustomComponent(c)"
|
|
80
|
+
:meta="c.meta"
|
|
81
|
+
:resource="coreStore.resource"
|
|
82
|
+
:adminUser="coreStore.adminUser"
|
|
83
|
+
/>
|
|
84
|
+
|
|
85
|
+
<ResourceListTable
|
|
86
|
+
:resource="coreStore.resource"
|
|
87
|
+
:rows="rows"
|
|
88
|
+
@update:page="page = $event"
|
|
89
|
+
@update:sort="sort = $event"
|
|
90
|
+
@update:checkboxes="checkboxes = $event"
|
|
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
|
+
/>
|
|
81
105
|
|
|
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>
|
|
309
106
|
</div>
|
|
310
107
|
</template>
|
|
311
108
|
|
|
312
109
|
<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';
|
|
318
110
|
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
319
|
-
import
|
|
111
|
+
import ResourceListTable from '@/components/ResourceListTable.vue';
|
|
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'
|
|
320
120
|
|
|
321
121
|
import ValueRenderer from '@/components/ValueRenderer.vue';
|
|
122
|
+
import { getCustomComponent } from '@/utils';
|
|
322
123
|
|
|
323
|
-
import {
|
|
324
|
-
IconChevronDoubleLeftOutline,
|
|
325
|
-
IconChevronDoubleRightOutline,
|
|
326
|
-
IconInboxFullSolid,
|
|
327
|
-
IconInboxOutline,
|
|
328
|
-
IconPlusOutline
|
|
329
|
-
} from '@iconify-prerendered/vue-flowbite';
|
|
330
124
|
|
|
331
125
|
import {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
IconFilterOutline, IconBanOutline
|
|
126
|
+
IconBanOutline,
|
|
127
|
+
IconFilterOutline,
|
|
128
|
+
IconPlusOutline
|
|
336
129
|
} from '@iconify-prerendered/vue-flowbite';
|
|
337
130
|
|
|
338
131
|
import Filters from '@/components/Filters.vue';
|
|
339
132
|
|
|
340
133
|
const filtersShow = ref(false);
|
|
341
134
|
|
|
342
|
-
|
|
343
135
|
const coreStore = useCoreStore();
|
|
344
|
-
const
|
|
136
|
+
const filtersStore = useFiltersStore();
|
|
345
137
|
|
|
346
138
|
const route = useRoute();
|
|
347
|
-
const checkboxes = ref([]);
|
|
348
139
|
|
|
349
140
|
const page = ref(1);
|
|
350
|
-
const filters = ref([]);
|
|
351
141
|
const columnsMinMax = ref({});
|
|
352
142
|
const sort = ref([]);
|
|
353
|
-
const fetchStatus = ref({pending: false, error: null, success: false});
|
|
354
143
|
|
|
355
144
|
const rows = ref(null);
|
|
356
145
|
const totalRows = ref(0);
|
|
357
|
-
const
|
|
358
|
-
const allowedActions = ref({});
|
|
359
|
-
|
|
146
|
+
const checkboxes = ref([]);
|
|
360
147
|
|
|
361
148
|
const DEFAULT_PAGE_SIZE = 10;
|
|
362
149
|
|
|
363
|
-
const columnsListed = computed(() => coreStore.resourceColumns?.filter(c => c.showIn.includes('list')));
|
|
364
150
|
|
|
365
|
-
|
|
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
|
-
}
|
|
151
|
+
const pageSize = computed(() => coreStore.resource?.options?.listPageSize || DEFAULT_PAGE_SIZE);
|
|
376
152
|
|
|
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));
|
|
385
153
|
|
|
386
154
|
watch([page], async () => {
|
|
387
|
-
await
|
|
155
|
+
await getList();
|
|
388
156
|
});
|
|
389
157
|
|
|
390
|
-
watch(
|
|
158
|
+
watch(()=>filtersStore.filters, async () => {
|
|
391
159
|
page.value = 1;
|
|
160
|
+
checkboxes.value = [];
|
|
161
|
+
|
|
392
162
|
await getList();
|
|
393
163
|
}, {deep: true});
|
|
394
164
|
|
|
395
165
|
watch([sort], async () => {
|
|
396
|
-
await
|
|
166
|
+
await getList();
|
|
397
167
|
}, {deep: true});
|
|
398
168
|
|
|
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
|
-
}
|
|
414
169
|
|
|
415
170
|
async function getList() {
|
|
416
171
|
rows.value = null;
|
|
417
|
-
fetchStatus.value.pending = true;
|
|
418
172
|
const data = await callAdminForthApi({
|
|
419
173
|
path: '/get_resource_data',
|
|
420
174
|
method: 'POST',
|
|
421
175
|
body: {
|
|
176
|
+
source: 'list',
|
|
422
177
|
resourceId: route.params.resourceId,
|
|
423
178
|
limit: pageSize.value,
|
|
424
179
|
offset: (page.value - 1) * pageSize.value,
|
|
425
|
-
filters: filters
|
|
180
|
+
filters: filtersStore.filters,
|
|
426
181
|
sort: sort.value,
|
|
427
182
|
}
|
|
428
183
|
});
|
|
429
|
-
|
|
184
|
+
if (data.error) {
|
|
185
|
+
showErrorTost(data.error);
|
|
186
|
+
rows.value = [];
|
|
187
|
+
totalRows.value = 0;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
430
190
|
rows.value = data.data?.map(row => {
|
|
431
|
-
row._primaryKeyValue = row[coreStore.
|
|
191
|
+
row._primaryKeyValue = row[coreStore.resource.columns.find(c => c.primaryKey).name];
|
|
432
192
|
return row;
|
|
433
193
|
});
|
|
434
194
|
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()
|
|
475
195
|
}
|
|
476
196
|
|
|
477
197
|
async function startBulkAction(actionId) {
|
|
@@ -485,25 +205,32 @@ async function startBulkAction(actionId) {
|
|
|
485
205
|
|
|
486
206
|
}
|
|
487
207
|
});
|
|
488
|
-
if (data?.
|
|
208
|
+
if (data?.ok) {
|
|
489
209
|
checkboxes.value = [];
|
|
210
|
+
await getList();
|
|
490
211
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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);
|
|
212
|
+
if (data?.error) {
|
|
213
|
+
showErrorTost(data.error);
|
|
499
214
|
}
|
|
500
215
|
}
|
|
501
216
|
|
|
217
|
+
|
|
218
|
+
|
|
502
219
|
async function init() {
|
|
503
|
-
|
|
220
|
+
|
|
221
|
+
await coreStore.fetchResourceFull({
|
|
504
222
|
resourceId: route.params.resourceId
|
|
505
223
|
});
|
|
506
224
|
|
|
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
|
+
|
|
507
234
|
await getList();
|
|
508
235
|
columnsMinMax.value = await callAdminForthApi({
|
|
509
236
|
path: '/get_min_max_for_columns',
|
|
@@ -515,14 +242,16 @@ async function init() {
|
|
|
515
242
|
}
|
|
516
243
|
|
|
517
244
|
onMounted(async () => {
|
|
245
|
+
initFlowbite();
|
|
246
|
+
|
|
518
247
|
await init();
|
|
248
|
+
|
|
519
249
|
});
|
|
520
250
|
|
|
521
251
|
// on route param change
|
|
522
252
|
watch(() => route.params.resourceId, async () => {
|
|
523
|
-
|
|
253
|
+
filtersStore.setFilters([]);
|
|
524
254
|
checkboxes.value = [];
|
|
525
|
-
sort.value = [];
|
|
526
255
|
await init();
|
|
527
256
|
});
|
|
528
257
|
|