adminforth 2.4.0-next.26 → 2.4.0-next.261
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/cli.js +10 -3
- 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/utils.js +25 -8
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +1 -0
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -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.map +1 -1
- package/dist/dataConnectors/baseConnector.js +46 -15
- 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 +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -9
- 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 +50 -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 +184 -19
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +164 -26
- 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 +5 -4
- package/dist/spa/package.json +1 -1
- package/dist/spa/src/App.vue +58 -173
- package/dist/spa/src/adminforth.ts +42 -18
- 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 +12 -12
- package/dist/spa/src/afcl/Input.vue +5 -5
- 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 +68 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +213 -74
- 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 +26 -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/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 -8
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +85 -39
- 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 +90 -80
- package/dist/spa/src/components/ResourceListTableVirtual.vue +86 -76
- 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 +73 -14
- package/dist/spa/src/components/Toast.vue +27 -9
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +43 -16
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.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 +29 -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 +158 -22
- package/dist/spa/src/types/Common.ts +81 -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 +279 -9
- package/dist/spa/src/views/CreateView.vue +18 -19
- package/dist/spa/src/views/EditView.vue +25 -19
- 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 +59 -39
- 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 +134 -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 +96 -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,6 +172,7 @@
|
|
|
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
|
|
|
@@ -199,14 +197,14 @@
|
|
|
199
197
|
<!-- pagination
|
|
200
198
|
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
199
|
-->
|
|
202
|
-
<div class="flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3"
|
|
203
|
-
v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
|
|
204
|
-
>
|
|
200
|
+
<div class="af-pagination-container flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3">
|
|
205
201
|
|
|
206
|
-
<div class="inline-flex "
|
|
202
|
+
<div class="af-pagination-buttons-container inline-flex "
|
|
203
|
+
v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
|
|
204
|
+
>
|
|
207
205
|
<!-- Buttons -->
|
|
208
206
|
<button
|
|
209
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
207
|
+
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
208
|
@click="page--; pageInput = page.toString();" :disabled="page <= 1">
|
|
211
209
|
<svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
212
210
|
viewBox="0 0 14 10">
|
|
@@ -218,14 +216,14 @@
|
|
|
218
216
|
</span>
|
|
219
217
|
</button>
|
|
220
218
|
<button
|
|
221
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
219
|
+
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
220
|
@click="page = 1; pageInput = page.toString();" :disabled="page <= 1">
|
|
223
221
|
<!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
|
|
224
222
|
1
|
|
225
223
|
</button>
|
|
226
224
|
<div
|
|
227
225
|
contenteditable="true"
|
|
228
|
-
class="min-w-10 outline-none inline-block w-auto
|
|
226
|
+
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
227
|
@keydown="onPageKeydown($event)"
|
|
230
228
|
@input="onPageInput($event)"
|
|
231
229
|
@blur="validatePageInput()"
|
|
@@ -234,14 +232,14 @@
|
|
|
234
232
|
</div>
|
|
235
233
|
|
|
236
234
|
<button
|
|
237
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
235
|
+
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
236
|
@click="page = totalPages; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
239
237
|
{{ totalPages }}
|
|
240
238
|
|
|
241
239
|
<!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
|
|
242
240
|
</button>
|
|
243
241
|
<button
|
|
244
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
242
|
+
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
243
|
@click="page++; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
246
244
|
<span class="hidden sm:inline">{{ $t('Next') }}</span>
|
|
247
245
|
<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 +251,11 @@
|
|
|
253
251
|
</div>
|
|
254
252
|
|
|
255
253
|
<!-- 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>
|
|
254
|
+
<span class="text-sm text-lightListTablePaginationHelpText dark:text-darkListTablePaginationHelpText">
|
|
255
|
+
<span v-if="((((page || 1) - 1) * pageSize + 1 > totalRows) && totalRows > 0)">{{ $t('Wrong Page') }} </span>
|
|
256
|
+
<template v-else-if="resource && totalRows > 0">
|
|
259
257
|
|
|
260
|
-
<span class="hidden sm:inline">
|
|
258
|
+
<span class="af-pagination-info hidden sm:inline">
|
|
261
259
|
<i18n-t keypath="Showing {from} to {to} of {total} Entries" tag="p" >
|
|
262
260
|
<template v-slot:from>
|
|
263
261
|
<strong>{{ from }}</strong>
|
|
@@ -307,12 +305,13 @@ import {
|
|
|
307
305
|
import {
|
|
308
306
|
IconEyeSolid,
|
|
309
307
|
IconPenSolid,
|
|
310
|
-
IconTrashBinSolid
|
|
308
|
+
IconTrashBinSolid,
|
|
311
309
|
} from '@iconify-prerendered/vue-flowbite';
|
|
312
310
|
import router from '@/router';
|
|
313
311
|
import { Tooltip } from '@/afcl';
|
|
314
|
-
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
312
|
+
import type { AdminForthResourceCommon, AdminForthResourceColumnInputCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
315
313
|
import adminforth from '@/adminforth';
|
|
314
|
+
import Checkbox from '@/afcl/Checkbox.vue';
|
|
316
315
|
|
|
317
316
|
const coreStore = useCoreStore();
|
|
318
317
|
const { t } = useI18n();
|
|
@@ -341,7 +340,7 @@ const emits = defineEmits([
|
|
|
341
340
|
const checkboxesInternal: Ref<any[]> = ref([]);
|
|
342
341
|
const pageInput = ref('1');
|
|
343
342
|
const page = ref(1);
|
|
344
|
-
const sort = ref([]);
|
|
343
|
+
const sort: Ref<Array<{field: string, direction: string}>> = ref([]);
|
|
345
344
|
|
|
346
345
|
|
|
347
346
|
const from = computed(() => ((page.value || 1) - 1) * props.pageSize + 1);
|
|
@@ -350,11 +349,11 @@ const to = computed(() => Math.min((page.value || 1) * props.pageSize, props.tot
|
|
|
350
349
|
watch(() => page.value, (newPage) => {
|
|
351
350
|
emits('update:page', newPage);
|
|
352
351
|
});
|
|
353
|
-
async function onPageKeydown(event) {
|
|
352
|
+
async function onPageKeydown(event: any) {
|
|
354
353
|
// page input should accept only numbers, arrow keys and backspace
|
|
355
354
|
if (['Enter', 'Space'].includes(event.code) ||
|
|
356
355
|
(!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
|
|
357
|
-
&& isNaN(String.fromCharCode(event.keyCode)))) {
|
|
356
|
+
&& isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
|
|
358
357
|
event.preventDefault();
|
|
359
358
|
if (event.code === 'Enter') {
|
|
360
359
|
validatePageInput();
|
|
@@ -375,7 +374,7 @@ watch(() => props.checkboxes, (newCheckboxes) => {
|
|
|
375
374
|
checkboxesInternal.value = newCheckboxes;
|
|
376
375
|
});
|
|
377
376
|
|
|
378
|
-
watch(() => props.sort, (newSort) => {
|
|
377
|
+
watch(() => props.sort, (newSort: any) => {
|
|
379
378
|
sort.value = newSort;
|
|
380
379
|
});
|
|
381
380
|
|
|
@@ -386,17 +385,17 @@ watch(() => props.page, (newPage) => {
|
|
|
386
385
|
page.value = newPage;
|
|
387
386
|
});
|
|
388
387
|
|
|
389
|
-
const rowRefs = useTemplateRef('rowRefs');
|
|
390
|
-
const headerRefs = useTemplateRef('headerRefs');
|
|
391
|
-
const rowHeights = ref([]);
|
|
392
|
-
const columnWidths = ref([]);
|
|
388
|
+
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
|
|
389
|
+
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
|
|
390
|
+
const rowHeights = ref<number[]>([]);
|
|
391
|
+
const columnWidths = ref<number[]>([]);
|
|
393
392
|
watch(() => props.rows, (newRows) => {
|
|
394
393
|
// 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)];
|
|
394
|
+
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
|
|
395
|
+
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el: HTMLElement) => el.offsetWidth)];
|
|
397
396
|
});
|
|
398
397
|
|
|
399
|
-
function addToCheckedValues(id) {
|
|
398
|
+
function addToCheckedValues(id: string) {
|
|
400
399
|
if (checkboxesInternal.value.includes(id)) {
|
|
401
400
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
|
|
402
401
|
} else {
|
|
@@ -405,17 +404,17 @@ function addToCheckedValues(id) {
|
|
|
405
404
|
checkboxesInternal.value = [ ...checkboxesInternal.value ]
|
|
406
405
|
}
|
|
407
406
|
|
|
408
|
-
const columnsListed = computed(() => props.resource?.columns?.filter(c => c.showIn
|
|
407
|
+
const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
|
|
409
408
|
|
|
410
|
-
async function selectAll(
|
|
409
|
+
async function selectAll() {
|
|
411
410
|
if (!allFromThisPageChecked.value) {
|
|
412
|
-
props.rows
|
|
411
|
+
props.rows?.forEach((r) => {
|
|
413
412
|
if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
|
|
414
413
|
checkboxesInternal.value.push(r._primaryKeyValue)
|
|
415
414
|
}
|
|
416
415
|
});
|
|
417
416
|
} else {
|
|
418
|
-
props.rows
|
|
417
|
+
props.rows?.forEach((r) => {
|
|
419
418
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
|
|
420
419
|
});
|
|
421
420
|
}
|
|
@@ -428,15 +427,15 @@ const allFromThisPageChecked = computed(() => {
|
|
|
428
427
|
if (!props.rows || !props.rows.length) return false;
|
|
429
428
|
return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
|
|
430
429
|
});
|
|
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));
|
|
430
|
+
const ascArr = computed(() => sort.value.filter((s:any) => s.direction === 'asc').map((s: any) => s.field));
|
|
431
|
+
const descArr = computed(() => sort.value.filter((s: any) => s.direction === 'desc').map((s: any) => s.field));
|
|
433
432
|
|
|
434
433
|
|
|
435
|
-
function onSortButtonClick(event, field) {
|
|
434
|
+
function onSortButtonClick(event: any, field: string) {
|
|
436
435
|
// if ctrl key is pressed, add to sort otherwise sort by this field
|
|
437
436
|
// in any case if field is already in sort, toggle direction
|
|
438
437
|
|
|
439
|
-
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
438
|
+
const sortIndex = sort.value.findIndex((s: any) => s.field === field);
|
|
440
439
|
if (sortIndex === -1) {
|
|
441
440
|
// field is not in sort, add it
|
|
442
441
|
if (event.ctrlKey) {
|
|
@@ -447,9 +446,9 @@ function onSortButtonClick(event, field) {
|
|
|
447
446
|
} else {
|
|
448
447
|
const sortField = sort.value[sortIndex];
|
|
449
448
|
if (sortField.direction === 'asc') {
|
|
450
|
-
sort.value = sort.value.map((s) => s.field === field ? {field, direction: 'desc'} : s);
|
|
449
|
+
sort.value = sort.value.map((s: any) => s.field === field ? {field, direction: 'desc'} : s);
|
|
451
450
|
} else {
|
|
452
|
-
sort.value = sort.value.filter((s) => s.field !== field);
|
|
451
|
+
sort.value = sort.value.filter((s: any) => s.field !== field);
|
|
453
452
|
}
|
|
454
453
|
}
|
|
455
454
|
}
|
|
@@ -457,11 +456,11 @@ function onSortButtonClick(event, field) {
|
|
|
457
456
|
|
|
458
457
|
const clickTarget = ref(null);
|
|
459
458
|
|
|
460
|
-
async function onClick(e,row) {
|
|
459
|
+
async function onClick(e: any, row: any) {
|
|
461
460
|
if(clickTarget.value === e.target) return;
|
|
462
461
|
clickTarget.value = e.target;
|
|
463
462
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
464
|
-
if (window.getSelection()
|
|
463
|
+
if (window.getSelection()?.toString()) return;
|
|
465
464
|
else {
|
|
466
465
|
if (row._clickUrl === null) {
|
|
467
466
|
// user asked to nothing on click
|
|
@@ -476,7 +475,7 @@ async function onClick(e,row) {
|
|
|
476
475
|
router.resolve({
|
|
477
476
|
name: 'resource-show',
|
|
478
477
|
params: {
|
|
479
|
-
resourceId: props.resource
|
|
478
|
+
resourceId: props.resource?.resourceId,
|
|
480
479
|
primaryKey: row._primaryKeyValue,
|
|
481
480
|
},
|
|
482
481
|
}).href,
|
|
@@ -494,7 +493,7 @@ async function onClick(e,row) {
|
|
|
494
493
|
router.push({
|
|
495
494
|
name: 'resource-show',
|
|
496
495
|
params: {
|
|
497
|
-
resourceId: props.resource
|
|
496
|
+
resourceId: props.resource?.resourceId,
|
|
498
497
|
primaryKey: row._primaryKeyValue,
|
|
499
498
|
},
|
|
500
499
|
});
|
|
@@ -503,7 +502,7 @@ async function onClick(e,row) {
|
|
|
503
502
|
}
|
|
504
503
|
}
|
|
505
504
|
|
|
506
|
-
async function deleteRecord(row) {
|
|
505
|
+
async function deleteRecord(row: any) {
|
|
507
506
|
const data = await adminforth.confirm({
|
|
508
507
|
message: t('Are you sure you want to delete this item?'),
|
|
509
508
|
yes: t('Delete'),
|
|
@@ -515,7 +514,7 @@ async function deleteRecord(row) {
|
|
|
515
514
|
path: '/delete_record',
|
|
516
515
|
method: 'POST',
|
|
517
516
|
body: {
|
|
518
|
-
resourceId: props.resource
|
|
517
|
+
resourceId: props.resource?.resourceId,
|
|
519
518
|
primaryKey: row._primaryKeyValue,
|
|
520
519
|
}
|
|
521
520
|
});
|
|
@@ -533,16 +532,16 @@ async function deleteRecord(row) {
|
|
|
533
532
|
}
|
|
534
533
|
}
|
|
535
534
|
|
|
536
|
-
const actionLoadingStates = ref({});
|
|
535
|
+
const actionLoadingStates = ref<Record<string | number, boolean>>({});
|
|
537
536
|
|
|
538
|
-
async function startCustomAction(actionId, row) {
|
|
537
|
+
async function startCustomAction(actionId: string, row: any) {
|
|
539
538
|
actionLoadingStates.value[actionId] = true;
|
|
540
539
|
|
|
541
540
|
const data = await callAdminForthApi({
|
|
542
541
|
path: '/start_custom_action',
|
|
543
542
|
method: 'POST',
|
|
544
543
|
body: {
|
|
545
|
-
resourceId: props.resource
|
|
544
|
+
resourceId: props.resource?.resourceId,
|
|
546
545
|
actionId: actionId,
|
|
547
546
|
recordId: row._primaryKeyValue
|
|
548
547
|
}
|
|
@@ -580,7 +579,7 @@ async function startCustomAction(actionId, row) {
|
|
|
580
579
|
}
|
|
581
580
|
}
|
|
582
581
|
|
|
583
|
-
function onPageInput(event) {
|
|
582
|
+
function onPageInput(event: any) {
|
|
584
583
|
pageInput.value = event.target.innerText;
|
|
585
584
|
}
|
|
586
585
|
|
|
@@ -600,4 +599,15 @@ input[type="checkbox"][disabled] {
|
|
|
600
599
|
input[type="checkbox"]:not([disabled]) {
|
|
601
600
|
@apply cursor-pointer;
|
|
602
601
|
}
|
|
602
|
+
td.sticky-column {
|
|
603
|
+
@apply sticky left-0 z-10;
|
|
604
|
+
&:not(:first-child) {
|
|
605
|
+
@apply left-[56px];
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
tr:not(:first-child):hover {
|
|
609
|
+
td.sticky-column {
|
|
610
|
+
@apply bg-lightListTableRowHover dark:bg-darkListTableRowHover;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
603
613
|
</style>
|