adminforth 2.4.0-next.31 → 2.4.0-next.310
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/commands/callTsProxy.js +14 -4
- package/commands/createApp/templates/api.ts.hbs +10 -0
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +12 -1
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/templates/prisma.config.ts.hbs +8 -0
- package/commands/createApp/templates/schema.prisma.hbs +0 -1
- package/commands/createApp/utils.js +10 -0
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +13 -7
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs +28 -0
- package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
- package/commands/createPlugin/templates/package.json.hbs +1 -1
- package/commands/generateModels.js +30 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +21 -2
- package/dist/auth.js.map +1 -1
- package/dist/dataConnectors/baseConnector.d.ts +1 -1
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +69 -17
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
- package/dist/dataConnectors/clickhouse.js +15 -0
- package/dist/dataConnectors/clickhouse.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +50 -15
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/dataConnectors/mysql.d.ts.map +1 -1
- package/dist/dataConnectors/mysql.js +11 -0
- package/dist/dataConnectors/mysql.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +43 -14
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +11 -0
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -22
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +2 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +62 -6
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts +6 -0
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +202 -25
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +172 -31
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +499 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +555 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +7 -15
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +45 -68
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +40 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/package-lock.json +1208 -708
- package/dist/spa/package.json +34 -34
- package/dist/spa/src/App.vue +59 -174
- package/dist/spa/src/adminforth.ts +42 -18
- package/dist/spa/src/afcl/AreaChart.vue +0 -1
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
- package/dist/spa/src/afcl/Card.vue +25 -0
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +47 -27
- package/dist/spa/src/afcl/Dropzone.vue +127 -48
- package/dist/spa/src/afcl/Input.vue +14 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +3 -3
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +82 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +315 -73
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +28 -18
- package/dist/spa/src/afcl/VerticalTabs.vue +16 -7
- package/dist/spa/src/afcl/index.ts +6 -3
- package/dist/spa/src/components/AcceptModal.vue +48 -14
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/CallActionWrapper.vue +15 -0
- package/dist/spa/src/components/ColumnValueInput.vue +38 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -21
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +195 -132
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +90 -23
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +115 -85
- package/dist/spa/src/components/ResourceListTableVirtual.vue +114 -80
- package/dist/spa/src/components/ShowTable.vue +21 -15
- package/dist/spa/src/components/Sidebar.vue +470 -0
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +3 -3
- package/dist/spa/src/components/ThreeDotsMenu.vue +84 -15
- package/dist/spa/src/components/Toast.vue +40 -29
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +44 -17
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +5 -3
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/router/index.ts +8 -0
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +13 -1
- package/dist/spa/src/stores/core.ts +13 -1
- package/dist/spa/src/stores/filters.ts +33 -2
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/stores/toast.ts +22 -3
- package/dist/spa/src/types/Back.ts +163 -23
- package/dist/spa/src/types/Common.ts +91 -32
- package/dist/spa/src/types/FrontendAPI.ts +31 -5
- package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -2
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
- package/dist/spa/src/types/adapters/index.ts +8 -0
- package/dist/spa/src/utils.ts +291 -11
- package/dist/spa/src/views/CreateView.vue +63 -21
- package/dist/spa/src/views/EditView.vue +55 -22
- package/dist/spa/src/views/ListView.vue +144 -87
- package/dist/spa/src/views/LoginView.vue +26 -35
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/SettingsView.vue +121 -0
- package/dist/spa/src/views/ShowView.vue +83 -53
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +45 -2
- package/dist/types/Back.d.ts +146 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js +15 -0
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +106 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +31 -3
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
- package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CaptchaAdapter.js +5 -0
- package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +1 -1
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.js +2 -0
- package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +9 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/index.js +2 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/package.json +4 -2
- package/dist/spa/src/types/adapters/index.js +0 -5
|
@@ -6,27 +6,26 @@
|
|
|
6
6
|
<!-- skelet loader -->
|
|
7
7
|
<div role="status" v-if="!resource || !resource.columns"
|
|
8
8
|
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">
|
|
9
|
-
|
|
10
9
|
<div role="status" class="max-w-sm animate-pulse">
|
|
11
|
-
<div class="h-2 bg-
|
|
10
|
+
<div class="h-2 bg-lightListSkeletLoader rounded-full dark:bg-darkListSkeletLoader max-w-[360px]"></div>
|
|
12
11
|
</div>
|
|
13
12
|
</div>
|
|
14
|
-
<table v-else class=" w-full text-sm text-left rtl:text-right text-
|
|
13
|
+
<table v-else class=" w-full text-sm text-left rtl:text-right text-lightListTableText dark:text-darkListTableText rounded-default">
|
|
15
14
|
|
|
16
15
|
<tbody>
|
|
17
16
|
<!-- table header -->
|
|
18
|
-
<tr class="t-header sticky z-
|
|
19
|
-
<td scope="col" class="p-4">
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
</
|
|
17
|
+
<tr class="t-header sticky z-20 top-0 text-xs text-lightListTableHeadingText bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-darkListTableHeadingText">
|
|
18
|
+
<td scope="col" class="p-4 sticky-column bg-lightListTableHeading dark:bg-darkListTableHeading">
|
|
19
|
+
<Checkbox
|
|
20
|
+
:modelValue="allFromThisPageChecked"
|
|
21
|
+
:disabled="!rows || !rows.length"
|
|
22
|
+
@update:modelValue="selectAll"
|
|
23
|
+
>
|
|
24
|
+
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
25
|
+
</Checkbox>
|
|
27
26
|
</td>
|
|
28
27
|
|
|
29
|
-
<td v-for="c in columnsListed" ref="headerRefs" scope="col" class="px-2 md:px-3 lg:px-6 py-3">
|
|
28
|
+
<td v-for="c in columnsListed" ref="headerRefs" scope="col" class="px-2 md:px-3 lg:px-6 py-3" :class="{'sticky-column bg-lightListTableHeading dark:bg-darkListTableHeading': c.listSticky}">
|
|
30
29
|
|
|
31
30
|
<div @click="(evt) => c.sortable && onSortButtonClick(evt, c.name)"
|
|
32
31
|
class="flex items-center " :class="{'cursor-pointer':c.sortable}">
|
|
@@ -48,8 +47,8 @@
|
|
|
48
47
|
</div>
|
|
49
48
|
<span
|
|
50
49
|
class="bg-red-100 text-red-800 text-xs font-medium me-1 px-1 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400"
|
|
51
|
-
v-if="sort.findIndex((s) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
52
|
-
{{ sort.findIndex((s) => s.field === c.name) + 1 }}
|
|
50
|
+
v-if="sort.findIndex((s: any) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
51
|
+
{{ sort.findIndex((s: any) => s.field === c.name) + 1 }}
|
|
53
52
|
</span>
|
|
54
53
|
|
|
55
54
|
</div>
|
|
@@ -65,7 +64,7 @@
|
|
|
65
64
|
<!-- table header end -->
|
|
66
65
|
<SkeleteLoader
|
|
67
66
|
v-if="!rows"
|
|
68
|
-
:columns="resource?.columns.filter(c => c.showIn
|
|
67
|
+
:columns="resource?.columns.filter((c: AdminForthResourceColumnInputCommon) => c.showIn?.list).length + 2"
|
|
69
68
|
:rows="rowHeights.length || 3"
|
|
70
69
|
:row-heights="rowHeights"
|
|
71
70
|
:column-widths="columnWidths"
|
|
@@ -91,23 +90,21 @@
|
|
|
91
90
|
|
|
92
91
|
:class="{'border-b': rowI !== rows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
|
|
93
92
|
>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
</td>
|
|
106
|
-
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
|
|
93
|
+
<td class="w-4 p-4 cursor-default sticky-column bg-lightListTable dark:bg-darkListTable" @click="(e)=>e.stopPropagation()">
|
|
94
|
+
<Checkbox
|
|
95
|
+
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
|
|
96
|
+
@change="(e: any)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
97
|
+
@click="(e: any)=>e.stopPropagation()"
|
|
98
|
+
>
|
|
99
|
+
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
100
|
+
</Checkbox>
|
|
101
|
+
</td>
|
|
102
|
+
|
|
103
|
+
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4" :class="{'sticky-column bg-lightListTable dark:bg-darkListTable': c.listSticky}">
|
|
107
104
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
108
105
|
<component
|
|
109
|
-
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
110
|
-
:meta="c?.components?.list
|
|
106
|
+
:is="c?.components?.list ? getCustomComponent(typeof c.components.list === 'string' ? { file: c.components.list } : c.components.list) : ValueRenderer"
|
|
107
|
+
:meta="typeof c?.components?.list === 'object' ? c.components.list.meta : undefined"
|
|
111
108
|
:column="c"
|
|
112
109
|
:record="row"
|
|
113
110
|
:adminUser="coreStore.adminUser"
|
|
@@ -118,7 +115,7 @@
|
|
|
118
115
|
<div class="flex text-lightPrimary dark:text-darkPrimary items-center">
|
|
119
116
|
<Tooltip>
|
|
120
117
|
<RouterLink
|
|
121
|
-
v-if="resource.options?.allowedActions
|
|
118
|
+
v-if="resource.options?.allowedActions?.show"
|
|
122
119
|
:to="{
|
|
123
120
|
name: 'resource-show',
|
|
124
121
|
params: {
|
|
@@ -138,7 +135,7 @@
|
|
|
138
135
|
|
|
139
136
|
<Tooltip>
|
|
140
137
|
<RouterLink
|
|
141
|
-
v-if="resource.options?.allowedActions
|
|
138
|
+
v-if="resource.options?.allowedActions?.edit"
|
|
142
139
|
:to="{
|
|
143
140
|
name: 'resource-edit',
|
|
144
141
|
params: {
|
|
@@ -156,7 +153,7 @@
|
|
|
156
153
|
|
|
157
154
|
<Tooltip>
|
|
158
155
|
<button
|
|
159
|
-
v-if="resource.options?.allowedActions
|
|
156
|
+
v-if="resource.options?.allowedActions?.delete"
|
|
160
157
|
@click="deleteRecord(row)"
|
|
161
158
|
>
|
|
162
159
|
<IconTrashBinSolid class="af-delete-icon w-5 h-5 me-2"/>
|
|
@@ -175,22 +172,43 @@
|
|
|
175
172
|
:resource="coreStore.resource"
|
|
176
173
|
:adminUser="coreStore.adminUser"
|
|
177
174
|
:record="row"
|
|
175
|
+
:updateRecords="()=>emits('update:records', true)"
|
|
178
176
|
/>
|
|
179
177
|
</template>
|
|
180
178
|
|
|
181
179
|
<template v-if="resource.options?.actions">
|
|
182
|
-
<Tooltip
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
<component
|
|
187
|
-
|
|
188
|
-
|
|
180
|
+
<Tooltip
|
|
181
|
+
v-for="action in resource.options.actions.filter(a => a.showIn?.list)"
|
|
182
|
+
:key="action.id"
|
|
183
|
+
>
|
|
184
|
+
<component
|
|
185
|
+
:is="action.customComponent ? getCustomComponent(action.customComponent) : CallActionWrapper"
|
|
186
|
+
:meta="action.customComponent?.meta"
|
|
187
|
+
:row="row"
|
|
188
|
+
:resource="resource"
|
|
189
|
+
:adminUser="adminUser"
|
|
190
|
+
@callAction="(payload? : Object) => startCustomAction(action.id, payload ?? row)"
|
|
191
|
+
>
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
:disabled="rowActionLoadingStates?.[action.id]"
|
|
195
|
+
@click.stop.prevent
|
|
196
|
+
>
|
|
197
|
+
<component
|
|
198
|
+
v-if="action.icon"
|
|
199
|
+
:is="getIcon(action.icon)"
|
|
200
|
+
class="w-5 h-5 mr-2 text-lightPrimary dark:text-darkPrimary"
|
|
201
|
+
/>
|
|
202
|
+
</button>
|
|
203
|
+
</component>
|
|
204
|
+
|
|
205
|
+
<template #tooltip>
|
|
189
206
|
{{ action.name }}
|
|
190
207
|
</template>
|
|
191
208
|
</Tooltip>
|
|
192
209
|
</template>
|
|
193
210
|
</div>
|
|
211
|
+
|
|
194
212
|
</td>
|
|
195
213
|
</tr>
|
|
196
214
|
</tbody>
|
|
@@ -199,14 +217,14 @@
|
|
|
199
217
|
<!-- pagination
|
|
200
218
|
totalRows in v-if is used to not hide page input during loading when user puts cursor into it and edit directly (rows gets null there during edit)
|
|
201
219
|
-->
|
|
202
|
-
<div class="flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3">
|
|
220
|
+
<div class="af-pagination-container flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3">
|
|
203
221
|
|
|
204
|
-
<div class="inline-flex "
|
|
222
|
+
<div class="af-pagination-buttons-container inline-flex "
|
|
205
223
|
v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
|
|
206
224
|
>
|
|
207
225
|
<!-- Buttons -->
|
|
208
226
|
<button
|
|
209
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
227
|
+
class="af-pagination-prev-button flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightListTablePaginationText focus:outline-none bg-lightListTablePaginationBackgoround border-r-0 rounded-s border border-lightListTablePaginationBorder hover:bg-lightListTablePaginationBackgoroundHover hover:text-lightListTablePaginationTextHover focus:z-10 focus:ring-4 focus:ring-lightListTablePaginationFocusRing dark:focus:ring-darkListTablePaginationFocusRing dark:bg-darkListTablePaginationBackgoround dark:text-darkListTablePaginationText dark:border-darkListTablePaginationBorder dark:hover:text-darkListTablePaginationTextHover dark:hover:bg-darkListTablePaginationBackgoroundHover disabled:opacity-50"
|
|
210
228
|
@click="page--; pageInput = page.toString();" :disabled="page <= 1">
|
|
211
229
|
<svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
212
230
|
viewBox="0 0 14 10">
|
|
@@ -218,14 +236,14 @@
|
|
|
218
236
|
</span>
|
|
219
237
|
</button>
|
|
220
238
|
<button
|
|
221
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
239
|
+
class="af-pagination-first-page-button flex items-center py-1 px-3 text-sm font-medium text-lightListTablePaginationText focus:outline-none bg-lightListTablePaginationBackgoround border-r-0 border border-lightListTablePaginationBorder hover:bg-lightListTablePaginationBackgoroundHover hover:text-lightListTablePaginationTextHover focus:z-10 focus:ring-4 focus:ring-lightListTablePaginationFocusRing dark:focus:ring-darkListTablePaginationFocusRing dark:bg-darkListTablePaginationBackgoround dark:text-darkListTablePaginationText dark:border-darkListTablePaginationBorder dark:hover:text-darkListTablePaginationTextHover dark:hover:bg-darkListTablePaginationBackgoroundHover disabled:opacity-50"
|
|
222
240
|
@click="page = 1; pageInput = page.toString();" :disabled="page <= 1">
|
|
223
241
|
<!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
|
|
224
242
|
1
|
|
225
243
|
</button>
|
|
226
244
|
<div
|
|
227
245
|
contenteditable="true"
|
|
228
|
-
class="min-w-10 outline-none inline-block w-auto
|
|
246
|
+
class="af-pagination-input min-w-10 outline-none inline-block w-auto py-1.5 px-3 text-sm text-center text-lightListTablePaginationCurrentPageText border border-lightListTablePaginationBorder dark:border-darkListTablePaginationBorder dark:text-darkListTablePaginationCurrentPageText dark:bg-darkListTablePaginationBackgoround z-10"
|
|
229
247
|
@keydown="onPageKeydown($event)"
|
|
230
248
|
@input="onPageInput($event)"
|
|
231
249
|
@blur="validatePageInput()"
|
|
@@ -234,14 +252,14 @@
|
|
|
234
252
|
</div>
|
|
235
253
|
|
|
236
254
|
<button
|
|
237
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
255
|
+
class="af-pagination-last-page-button flex items-center py-1 px-3 text-sm font-medium text-lightListTablePaginationText focus:outline-none bg-lightListTablePaginationBackgoround border-l-0 border border-lightListTablePaginationBorder hover:bg-lightListTablePaginationBackgoroundHover hover:text-lightListTablePaginationTextHover focus:z-10 focus:ring-4 focus:ring-lightListTablePaginationFocusRing dark:focus:ring-darkListTablePaginationFocusRing dark:bg-darkListTablePaginationBackgoround dark:text-darkListTablePaginationText dark:border-darkListTablePaginationBorder dark:hover:text-white dark:hover:bg-darkListTablePaginationBackgoroundHover disabled:opacity-50"
|
|
238
256
|
@click="page = totalPages; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
239
257
|
{{ totalPages }}
|
|
240
258
|
|
|
241
259
|
<!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
|
|
242
260
|
</button>
|
|
243
261
|
<button
|
|
244
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
262
|
+
class="af-pagination-next-button flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightListTablePaginationText focus:outline-none bg-lightListTablePaginationBackgoround border-l-0 rounded-e border border-lightListTablePaginationBorder hover:bg-lightListTablePaginationBackgoroundHover hover:text-lightListTablePaginationTextHover focus:z-10 focus:ring-4 focus:ring-lightListTablePaginationFocusRing dark:focus:ring-darkListTablePaginationFocusRing dark:bg-darkListTablePaginationBackgoround dark:text-darkListTablePaginationText dark:border-darkListTablePaginationBorder dark:hover:text-white dark:hover:bg-darkListTablePaginationBackgoroundHover disabled:opacity-50"
|
|
245
263
|
@click="page++; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
246
264
|
<span class="hidden sm:inline">{{ $t('Next') }}</span>
|
|
247
265
|
<svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
@@ -253,11 +271,11 @@
|
|
|
253
271
|
</div>
|
|
254
272
|
|
|
255
273
|
<!-- Help text -->
|
|
256
|
-
<span class="text-sm text-
|
|
257
|
-
<span v-if="((page || 1) - 1) * pageSize + 1 > totalRows">{{ $t('Wrong Page') }} </span>
|
|
258
|
-
<template v-else>
|
|
274
|
+
<span class="ml-4 text-sm text-lightListTablePaginationHelpText dark:text-darkListTablePaginationHelpText">
|
|
275
|
+
<span v-if="((((page || 1) - 1) * pageSize + 1 > totalRows) && totalRows > 0)">{{ $t('Wrong Page') }} </span>
|
|
276
|
+
<template v-else-if="resource && totalRows > 0">
|
|
259
277
|
|
|
260
|
-
<span class="hidden sm:inline">
|
|
278
|
+
<span class="af-pagination-info hidden sm:inline">
|
|
261
279
|
<i18n-t keypath="Showing {from} to {to} of {total} Entries" tag="p" >
|
|
262
280
|
<template v-slot:from>
|
|
263
281
|
<strong>{{ from }}</strong>
|
|
@@ -307,12 +325,13 @@ import {
|
|
|
307
325
|
import {
|
|
308
326
|
IconEyeSolid,
|
|
309
327
|
IconPenSolid,
|
|
310
|
-
IconTrashBinSolid
|
|
328
|
+
IconTrashBinSolid,
|
|
311
329
|
} from '@iconify-prerendered/vue-flowbite';
|
|
312
330
|
import router from '@/router';
|
|
313
331
|
import { Tooltip } from '@/afcl';
|
|
314
|
-
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
332
|
+
import type { AdminForthResourceCommon, AdminForthResourceColumnInputCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
315
333
|
import adminforth from '@/adminforth';
|
|
334
|
+
import Checkbox from '@/afcl/Checkbox.vue';
|
|
316
335
|
|
|
317
336
|
const coreStore = useCoreStore();
|
|
318
337
|
const { t } = useI18n();
|
|
@@ -341,7 +360,7 @@ const emits = defineEmits([
|
|
|
341
360
|
const checkboxesInternal: Ref<any[]> = ref([]);
|
|
342
361
|
const pageInput = ref('1');
|
|
343
362
|
const page = ref(1);
|
|
344
|
-
const sort = ref([]);
|
|
363
|
+
const sort: Ref<Array<{field: string, direction: string}>> = ref([]);
|
|
345
364
|
|
|
346
365
|
|
|
347
366
|
const from = computed(() => ((page.value || 1) - 1) * props.pageSize + 1);
|
|
@@ -350,11 +369,11 @@ const to = computed(() => Math.min((page.value || 1) * props.pageSize, props.tot
|
|
|
350
369
|
watch(() => page.value, (newPage) => {
|
|
351
370
|
emits('update:page', newPage);
|
|
352
371
|
});
|
|
353
|
-
async function onPageKeydown(event) {
|
|
372
|
+
async function onPageKeydown(event: any) {
|
|
354
373
|
// page input should accept only numbers, arrow keys and backspace
|
|
355
374
|
if (['Enter', 'Space'].includes(event.code) ||
|
|
356
375
|
(!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
|
|
357
|
-
&& isNaN(String.fromCharCode(event.keyCode)))) {
|
|
376
|
+
&& isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
|
|
358
377
|
event.preventDefault();
|
|
359
378
|
if (event.code === 'Enter') {
|
|
360
379
|
validatePageInput();
|
|
@@ -375,7 +394,7 @@ watch(() => props.checkboxes, (newCheckboxes) => {
|
|
|
375
394
|
checkboxesInternal.value = newCheckboxes;
|
|
376
395
|
});
|
|
377
396
|
|
|
378
|
-
watch(() => props.sort, (newSort) => {
|
|
397
|
+
watch(() => props.sort, (newSort: any) => {
|
|
379
398
|
sort.value = newSort;
|
|
380
399
|
});
|
|
381
400
|
|
|
@@ -386,17 +405,17 @@ watch(() => props.page, (newPage) => {
|
|
|
386
405
|
page.value = newPage;
|
|
387
406
|
});
|
|
388
407
|
|
|
389
|
-
const rowRefs = useTemplateRef('rowRefs');
|
|
390
|
-
const headerRefs = useTemplateRef('headerRefs');
|
|
391
|
-
const rowHeights = ref([]);
|
|
392
|
-
const columnWidths = ref([]);
|
|
408
|
+
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
|
|
409
|
+
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
|
|
410
|
+
const rowHeights = ref<number[]>([]);
|
|
411
|
+
const columnWidths = ref<number[]>([]);
|
|
393
412
|
watch(() => props.rows, (newRows) => {
|
|
394
413
|
// rows are set to null when new records are loading
|
|
395
|
-
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el) => el.offsetHeight);
|
|
396
|
-
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el) => el.offsetWidth)];
|
|
414
|
+
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
|
|
415
|
+
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el: HTMLElement) => el.offsetWidth)];
|
|
397
416
|
});
|
|
398
417
|
|
|
399
|
-
function addToCheckedValues(id) {
|
|
418
|
+
function addToCheckedValues(id: string) {
|
|
400
419
|
if (checkboxesInternal.value.includes(id)) {
|
|
401
420
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
|
|
402
421
|
} else {
|
|
@@ -405,17 +424,17 @@ function addToCheckedValues(id) {
|
|
|
405
424
|
checkboxesInternal.value = [ ...checkboxesInternal.value ]
|
|
406
425
|
}
|
|
407
426
|
|
|
408
|
-
const columnsListed = computed(() => props.resource?.columns?.filter(c => c.showIn
|
|
427
|
+
const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
|
|
409
428
|
|
|
410
|
-
async function selectAll(
|
|
429
|
+
async function selectAll() {
|
|
411
430
|
if (!allFromThisPageChecked.value) {
|
|
412
|
-
props.rows
|
|
431
|
+
props.rows?.forEach((r) => {
|
|
413
432
|
if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
|
|
414
433
|
checkboxesInternal.value.push(r._primaryKeyValue)
|
|
415
434
|
}
|
|
416
435
|
});
|
|
417
436
|
} else {
|
|
418
|
-
props.rows
|
|
437
|
+
props.rows?.forEach((r) => {
|
|
419
438
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
|
|
420
439
|
});
|
|
421
440
|
}
|
|
@@ -428,15 +447,15 @@ const allFromThisPageChecked = computed(() => {
|
|
|
428
447
|
if (!props.rows || !props.rows.length) return false;
|
|
429
448
|
return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
|
|
430
449
|
});
|
|
431
|
-
const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
|
|
432
|
-
const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
|
|
450
|
+
const ascArr = computed(() => sort.value.filter((s:any) => s.direction === 'asc').map((s: any) => s.field));
|
|
451
|
+
const descArr = computed(() => sort.value.filter((s: any) => s.direction === 'desc').map((s: any) => s.field));
|
|
433
452
|
|
|
434
453
|
|
|
435
|
-
function onSortButtonClick(event, field) {
|
|
454
|
+
function onSortButtonClick(event: any, field: string) {
|
|
436
455
|
// if ctrl key is pressed, add to sort otherwise sort by this field
|
|
437
456
|
// in any case if field is already in sort, toggle direction
|
|
438
457
|
|
|
439
|
-
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
458
|
+
const sortIndex = sort.value.findIndex((s: any) => s.field === field);
|
|
440
459
|
if (sortIndex === -1) {
|
|
441
460
|
// field is not in sort, add it
|
|
442
461
|
if (event.ctrlKey) {
|
|
@@ -447,9 +466,9 @@ function onSortButtonClick(event, field) {
|
|
|
447
466
|
} else {
|
|
448
467
|
const sortField = sort.value[sortIndex];
|
|
449
468
|
if (sortField.direction === 'asc') {
|
|
450
|
-
sort.value = sort.value.map((s) => s.field === field ? {field, direction: 'desc'} : s);
|
|
469
|
+
sort.value = sort.value.map((s: any) => s.field === field ? {field, direction: 'desc'} : s);
|
|
451
470
|
} else {
|
|
452
|
-
sort.value = sort.value.filter((s) => s.field !== field);
|
|
471
|
+
sort.value = sort.value.filter((s: any) => s.field !== field);
|
|
453
472
|
}
|
|
454
473
|
}
|
|
455
474
|
}
|
|
@@ -457,11 +476,11 @@ function onSortButtonClick(event, field) {
|
|
|
457
476
|
|
|
458
477
|
const clickTarget = ref(null);
|
|
459
478
|
|
|
460
|
-
async function onClick(e,row) {
|
|
479
|
+
async function onClick(e: any, row: any) {
|
|
461
480
|
if(clickTarget.value === e.target) return;
|
|
462
481
|
clickTarget.value = e.target;
|
|
463
482
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
464
|
-
if (window.getSelection()
|
|
483
|
+
if (window.getSelection()?.toString()) return;
|
|
465
484
|
else {
|
|
466
485
|
if (row._clickUrl === null) {
|
|
467
486
|
// user asked to nothing on click
|
|
@@ -476,7 +495,7 @@ async function onClick(e,row) {
|
|
|
476
495
|
router.resolve({
|
|
477
496
|
name: 'resource-show',
|
|
478
497
|
params: {
|
|
479
|
-
resourceId: props.resource
|
|
498
|
+
resourceId: props.resource?.resourceId,
|
|
480
499
|
primaryKey: row._primaryKeyValue,
|
|
481
500
|
},
|
|
482
501
|
}).href,
|
|
@@ -494,7 +513,7 @@ async function onClick(e,row) {
|
|
|
494
513
|
router.push({
|
|
495
514
|
name: 'resource-show',
|
|
496
515
|
params: {
|
|
497
|
-
resourceId: props.resource
|
|
516
|
+
resourceId: props.resource?.resourceId,
|
|
498
517
|
primaryKey: row._primaryKeyValue,
|
|
499
518
|
},
|
|
500
519
|
});
|
|
@@ -503,7 +522,7 @@ async function onClick(e,row) {
|
|
|
503
522
|
}
|
|
504
523
|
}
|
|
505
524
|
|
|
506
|
-
async function deleteRecord(row) {
|
|
525
|
+
async function deleteRecord(row: any) {
|
|
507
526
|
const data = await adminforth.confirm({
|
|
508
527
|
message: t('Are you sure you want to delete this item?'),
|
|
509
528
|
yes: t('Delete'),
|
|
@@ -515,7 +534,7 @@ async function deleteRecord(row) {
|
|
|
515
534
|
path: '/delete_record',
|
|
516
535
|
method: 'POST',
|
|
517
536
|
body: {
|
|
518
|
-
resourceId: props.resource
|
|
537
|
+
resourceId: props.resource?.resourceId,
|
|
519
538
|
primaryKey: row._primaryKeyValue,
|
|
520
539
|
}
|
|
521
540
|
});
|
|
@@ -533,16 +552,16 @@ async function deleteRecord(row) {
|
|
|
533
552
|
}
|
|
534
553
|
}
|
|
535
554
|
|
|
536
|
-
const actionLoadingStates = ref({});
|
|
555
|
+
const actionLoadingStates = ref<Record<string | number, boolean>>({});
|
|
537
556
|
|
|
538
|
-
async function startCustomAction(actionId, row) {
|
|
557
|
+
async function startCustomAction(actionId: string, row: any) {
|
|
539
558
|
actionLoadingStates.value[actionId] = true;
|
|
540
559
|
|
|
541
560
|
const data = await callAdminForthApi({
|
|
542
561
|
path: '/start_custom_action',
|
|
543
562
|
method: 'POST',
|
|
544
563
|
body: {
|
|
545
|
-
resourceId: props.resource
|
|
564
|
+
resourceId: props.resource?.resourceId,
|
|
546
565
|
actionId: actionId,
|
|
547
566
|
recordId: row._primaryKeyValue
|
|
548
567
|
}
|
|
@@ -580,7 +599,7 @@ async function startCustomAction(actionId, row) {
|
|
|
580
599
|
}
|
|
581
600
|
}
|
|
582
601
|
|
|
583
|
-
function onPageInput(event) {
|
|
602
|
+
function onPageInput(event: any) {
|
|
584
603
|
pageInput.value = event.target.innerText;
|
|
585
604
|
}
|
|
586
605
|
|
|
@@ -600,4 +619,15 @@ input[type="checkbox"][disabled] {
|
|
|
600
619
|
input[type="checkbox"]:not([disabled]) {
|
|
601
620
|
@apply cursor-pointer;
|
|
602
621
|
}
|
|
622
|
+
td.sticky-column {
|
|
623
|
+
@apply sticky left-0 z-10;
|
|
624
|
+
&:not(:first-child) {
|
|
625
|
+
@apply left-[56px];
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
tr:not(:first-child):hover {
|
|
629
|
+
td.sticky-column {
|
|
630
|
+
@apply bg-lightListTableRowHover dark:bg-darkListTableRowHover;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
603
633
|
</style>
|