adminforth 2.4.0-next.21 → 2.4.0-next.211
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/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +10 -2
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/utils.js +27 -2
- package/commands/createCustomComponent/configLoader.js +3 -0
- 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/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -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 +44 -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 +11 -0
- 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 +20 -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 +52 -8
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +74 -7
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +154 -26
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +503 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +559 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +2 -0
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +16 -0
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +14 -0
- 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 +54 -169
- 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 +44 -27
- package/dist/spa/src/afcl/Dropzone.vue +12 -12
- package/dist/spa/src/afcl/Input.vue +6 -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 +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 +1 -2
- 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 +7 -7
- 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 +78 -80
- package/dist/spa/src/components/ResourceListTableVirtual.vue +71 -73
- package/dist/spa/src/components/ShowTable.vue +17 -12
- package/dist/spa/src/components/Sidebar.vue +448 -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 +70 -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 +1 -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 +137 -22
- package/dist/spa/src/types/Common.ts +67 -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/CompletionAdapter.ts +25 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +27 -0
- package/dist/spa/src/types/adapters/ImageGenerationAdapter.ts +50 -0
- 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/OAuth2Adapter.ts +34 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +73 -0
- package/dist/spa/src/types/adapters/index.ts +8 -0
- package/dist/spa/src/utils.ts +219 -8
- 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 +139 -86
- package/dist/spa/src/views/LoginView.vue +31 -37
- 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 +115 -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 +59 -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/CompletionAdapter.d.ts +20 -0
- package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CompletionAdapter.js +2 -0
- package/dist/types/adapters/CompletionAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +20 -0
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -0
- package/dist/types/adapters/EmailAdapter.js +2 -0
- package/dist/types/adapters/EmailAdapter.js.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts +37 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.js +2 -0
- package/dist/types/adapters/ImageGenerationAdapter.js.map +1 -0
- 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/OAuth2Adapter.d.ts +32 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.js +2 -0
- package/dist/types/adapters/OAuth2Adapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +63 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -0
- package/dist/types/adapters/StorageAdapter.js +2 -0
- package/dist/types/adapters/StorageAdapter.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 +3 -2
- package/dist/spa/src/types/Adapters.ts +0 -213
- package/dist/types/Adapters.d.ts +0 -168
- package/dist/types/Adapters.d.ts.map +0 -1
- package/dist/types/Adapters.js +0 -2
- package/dist/types/Adapters.js.map +0 -1
|
@@ -5,28 +5,28 @@
|
|
|
5
5
|
:style="`height: ${containerHeight}px; will-change: transform;`"
|
|
6
6
|
@scroll="handleScroll"
|
|
7
7
|
ref="containerRef"
|
|
8
|
-
>
|
|
8
|
+
>
|
|
9
9
|
<!-- skelet loader -->
|
|
10
10
|
<div role="status" v-if="!resource || !resource.columns"
|
|
11
11
|
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">
|
|
12
12
|
|
|
13
13
|
<div role="status" class="max-w-sm animate-pulse">
|
|
14
|
-
<div class="h-2 bg-
|
|
14
|
+
<div class="h-2 bg-lightListSkeletLoader rounded-full dark:bg-darkListSkeletLoader max-w-[360px]"></div>
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
17
|
-
<table v-else class=" w-full text-sm text-left rtl:text-right text-
|
|
17
|
+
<table v-else class="h-full w-full text-sm text-left rtl:text-right text-lightListTableText dark:text-darkListTableText rounded-default">
|
|
18
18
|
|
|
19
19
|
<tbody>
|
|
20
20
|
<!-- table header -->
|
|
21
21
|
<tr class="t-header sticky z-10 top-0 text-xs bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-gray-400">
|
|
22
22
|
<td scope="col" class="p-4">
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
</
|
|
23
|
+
<Checkbox
|
|
24
|
+
:modelValue="allFromThisPageChecked"
|
|
25
|
+
:disabled="!rows || !rows.length"
|
|
26
|
+
@update:modelValue="selectAll"
|
|
27
|
+
>
|
|
28
|
+
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
29
|
+
</Checkbox>
|
|
30
30
|
</td>
|
|
31
31
|
|
|
32
32
|
<td v-for="c in columnsListed" ref="headerRefs" scope="col" class="px-2 md:px-3 lg:px-6 py-3">
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
</div>
|
|
52
52
|
<span
|
|
53
53
|
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"
|
|
54
|
-
v-if="sort.findIndex((s) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
55
|
-
{{ sort.findIndex((s) => s.field === c.name) + 1 }}
|
|
54
|
+
v-if="sort.findIndex((s: any) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
55
|
+
{{ sort.findIndex((s: any) => s.field === c.name) + 1 }}
|
|
56
56
|
</span>
|
|
57
57
|
|
|
58
58
|
</div>
|
|
@@ -68,13 +68,13 @@
|
|
|
68
68
|
<!-- table header end -->
|
|
69
69
|
<SkeleteLoader
|
|
70
70
|
v-if="!rows"
|
|
71
|
-
:columns="resource?.columns.filter(c => c.showIn
|
|
71
|
+
:columns="resource?.columns.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list).length + 2"
|
|
72
72
|
:rows="rowHeights.length || 20"
|
|
73
73
|
:row-heights="rowHeights"
|
|
74
74
|
:column-widths="columnWidths"
|
|
75
75
|
/>
|
|
76
76
|
|
|
77
|
-
<tr v-else-if="rows.length === 0" class="bg-lightListTable dark:bg-darkListTable dark:border-darkListTableBorder">
|
|
77
|
+
<tr v-else-if="rows.length === 0" class="h-full bg-lightListTable dark:bg-darkListTable dark:border-darkListTableBorder">
|
|
78
78
|
<td :colspan="resource?.columns.length + 2">
|
|
79
79
|
|
|
80
80
|
<div id="toast-simple"
|
|
@@ -99,25 +99,22 @@
|
|
|
99
99
|
ref="rowRefs"
|
|
100
100
|
class="bg-lightListTable dark:bg-darkListTable border-lightListBorder dark:border-gray-700 hover:bg-lightListTableRowHover dark:hover:bg-darkListTableRowHover"
|
|
101
101
|
:class="{'border-b': rowI !== visibleRows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
|
|
102
|
-
@mounted="(el) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
|
|
102
|
+
@mounted="(el: any) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
|
|
103
103
|
>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
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 cursor-pointer">
|
|
113
|
-
<label for="checkbox-table-search-1" class="sr-only">{{ $t('checkbox') }}</label>
|
|
114
|
-
</div>
|
|
104
|
+
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
|
|
105
|
+
<Checkbox
|
|
106
|
+
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
|
|
107
|
+
@change="(e: any)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
108
|
+
@click="(e: any)=>e.stopPropagation()"
|
|
109
|
+
>
|
|
110
|
+
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
111
|
+
</Checkbox>
|
|
115
112
|
</td>
|
|
116
113
|
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
|
|
117
114
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
118
115
|
<component
|
|
119
|
-
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
120
|
-
:meta="c?.components?.list
|
|
116
|
+
:is="c?.components?.list ? getCustomComponent(typeof c.components.list === 'string' ? { file: c.components.list } : c.components.list) : ValueRenderer"
|
|
117
|
+
:meta="typeof c?.components?.list === 'object' ? c.components.list.meta : undefined"
|
|
121
118
|
:column="c"
|
|
122
119
|
:record="row"
|
|
123
120
|
:adminUser="coreStore.adminUser"
|
|
@@ -128,7 +125,7 @@
|
|
|
128
125
|
<div class="flex text-lightPrimary dark:text-darkPrimary items-center">
|
|
129
126
|
<Tooltip>
|
|
130
127
|
<RouterLink
|
|
131
|
-
v-if="resource.options?.allowedActions
|
|
128
|
+
v-if="resource.options?.allowedActions?.show"
|
|
132
129
|
:to="{
|
|
133
130
|
name: 'resource-show',
|
|
134
131
|
params: {
|
|
@@ -148,7 +145,7 @@
|
|
|
148
145
|
|
|
149
146
|
<Tooltip>
|
|
150
147
|
<RouterLink
|
|
151
|
-
v-if="resource.options?.allowedActions
|
|
148
|
+
v-if="resource.options?.allowedActions?.edit"
|
|
152
149
|
:to="{
|
|
153
150
|
name: 'resource-edit',
|
|
154
151
|
params: {
|
|
@@ -166,7 +163,7 @@
|
|
|
166
163
|
|
|
167
164
|
<Tooltip>
|
|
168
165
|
<button
|
|
169
|
-
v-if="resource.options?.allowedActions
|
|
166
|
+
v-if="resource.options?.allowedActions?.delete"
|
|
170
167
|
@click="deleteRecord(row)"
|
|
171
168
|
>
|
|
172
169
|
<IconTrashBinSolid class="w-5 h-5 me-2"/>
|
|
@@ -216,14 +213,14 @@
|
|
|
216
213
|
<!-- pagination
|
|
217
214
|
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)
|
|
218
215
|
-->
|
|
219
|
-
<div class="flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3"
|
|
220
|
-
v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
|
|
221
|
-
>
|
|
216
|
+
<div class="flex flex-row items-center mt-4 xs:flex-row xs:justify-between xs:items-center gap-3">
|
|
222
217
|
|
|
223
|
-
<div class="inline-flex "
|
|
218
|
+
<div class="inline-flex "
|
|
219
|
+
v-if="(rows || totalRows) && totalRows >= pageSize && totalRows > 0"
|
|
220
|
+
>
|
|
224
221
|
<!-- Buttons -->
|
|
225
222
|
<button
|
|
226
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
223
|
+
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"
|
|
227
224
|
@click="page--; pageInput = page.toString();" :disabled="page <= 1">
|
|
228
225
|
<svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
229
226
|
viewBox="0 0 14 10">
|
|
@@ -235,14 +232,14 @@
|
|
|
235
232
|
</span>
|
|
236
233
|
</button>
|
|
237
234
|
<button
|
|
238
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
235
|
+
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"
|
|
239
236
|
@click="page = 1; pageInput = page.toString();" :disabled="page <= 1">
|
|
240
237
|
<!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
|
|
241
238
|
1
|
|
242
239
|
</button>
|
|
243
240
|
<div
|
|
244
241
|
contenteditable="true"
|
|
245
|
-
class="min-w-10 outline-none inline-block w-auto
|
|
242
|
+
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"
|
|
246
243
|
@keydown="onPageKeydown($event)"
|
|
247
244
|
@input="onPageInput($event)"
|
|
248
245
|
@blur="validatePageInput()"
|
|
@@ -251,14 +248,14 @@
|
|
|
251
248
|
</div>
|
|
252
249
|
|
|
253
250
|
<button
|
|
254
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
251
|
+
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"
|
|
255
252
|
@click="page = totalPages; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
256
253
|
{{ totalPages }}
|
|
257
254
|
|
|
258
255
|
<!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
|
|
259
256
|
</button>
|
|
260
257
|
<button
|
|
261
|
-
class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-
|
|
258
|
+
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"
|
|
262
259
|
@click="page++; pageInput = page.toString();" :disabled="page >= totalPages">
|
|
263
260
|
<span class="hidden sm:inline">{{ $t('Next') }}</span>
|
|
264
261
|
<svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
@@ -270,9 +267,9 @@
|
|
|
270
267
|
</div>
|
|
271
268
|
|
|
272
269
|
<!-- Help text -->
|
|
273
|
-
<span class="text-sm text-
|
|
274
|
-
<span v-if="((page || 1) - 1) * pageSize + 1 > totalRows">{{ $t('Wrong Page') }} </span>
|
|
275
|
-
<template v-else>
|
|
270
|
+
<span class="text-sm text-lightListTablePaginationHelpText dark:text-darkListTablePaginationHelpText">
|
|
271
|
+
<span v-if="((((page || 1) - 1) * pageSize + 1 > totalRows) && totalRows > 0)">{{ $t('Wrong Page') }} </span>
|
|
272
|
+
<template v-else-if="resource && totalRows > 0">
|
|
276
273
|
|
|
277
274
|
<span class="hidden sm:inline">
|
|
278
275
|
<i18n-t keypath="Showing {from} to {to} of {total} Entries" tag="p" >
|
|
@@ -328,8 +325,9 @@ import {
|
|
|
328
325
|
} from '@iconify-prerendered/vue-flowbite';
|
|
329
326
|
import router from '@/router';
|
|
330
327
|
import { Tooltip } from '@/afcl';
|
|
331
|
-
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
328
|
+
import type { AdminForthResourceCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
332
329
|
import adminforth from '@/adminforth';
|
|
330
|
+
import Checkbox from '@/afcl/Checkbox.vue';
|
|
333
331
|
|
|
334
332
|
const coreStore = useCoreStore();
|
|
335
333
|
const { t } = useI18n();
|
|
@@ -361,7 +359,7 @@ const emits = defineEmits([
|
|
|
361
359
|
const checkboxesInternal: Ref<any[]> = ref([]);
|
|
362
360
|
const pageInput = ref('1');
|
|
363
361
|
const page = ref(1);
|
|
364
|
-
const sort = ref([]);
|
|
362
|
+
const sort: Ref<Array<{field: string, direction: string}>> = ref([]);
|
|
365
363
|
|
|
366
364
|
|
|
367
365
|
const from = computed(() => ((page.value || 1) - 1) * props.pageSize + 1);
|
|
@@ -370,11 +368,11 @@ const to = computed(() => Math.min((page.value || 1) * props.pageSize, props.tot
|
|
|
370
368
|
watch(() => page.value, (newPage) => {
|
|
371
369
|
emits('update:page', newPage);
|
|
372
370
|
});
|
|
373
|
-
async function onPageKeydown(event) {
|
|
371
|
+
async function onPageKeydown(event: any) {
|
|
374
372
|
// page input should accept only numbers, arrow keys and backspace
|
|
375
373
|
if (['Enter', 'Space'].includes(event.code) ||
|
|
376
374
|
(!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
|
|
377
|
-
&& isNaN(String.fromCharCode(event.keyCode)))) {
|
|
375
|
+
&& isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
|
|
378
376
|
event.preventDefault();
|
|
379
377
|
if (event.code === 'Enter') {
|
|
380
378
|
validatePageInput();
|
|
@@ -395,7 +393,7 @@ watch(() => props.checkboxes, (newCheckboxes) => {
|
|
|
395
393
|
checkboxesInternal.value = newCheckboxes;
|
|
396
394
|
});
|
|
397
395
|
|
|
398
|
-
watch(() => props.sort, (newSort) => {
|
|
396
|
+
watch(() => props.sort, (newSort: any) => {
|
|
399
397
|
sort.value = newSort;
|
|
400
398
|
});
|
|
401
399
|
|
|
@@ -406,17 +404,17 @@ watch(() => props.page, (newPage) => {
|
|
|
406
404
|
page.value = newPage;
|
|
407
405
|
});
|
|
408
406
|
|
|
409
|
-
const rowRefs = useTemplateRef('rowRefs');
|
|
410
|
-
const headerRefs = useTemplateRef('headerRefs');
|
|
411
|
-
const rowHeights = ref([]);
|
|
412
|
-
const columnWidths = ref([]);
|
|
407
|
+
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
|
|
408
|
+
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
|
|
409
|
+
const rowHeights = ref<number[]>([]);
|
|
410
|
+
const columnWidths = ref<number[]>([]);
|
|
413
411
|
watch(() => props.rows, (newRows) => {
|
|
414
412
|
// rows are set to null when new records are loading
|
|
415
|
-
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el) => el.offsetHeight);
|
|
416
|
-
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el) => el.offsetWidth)];
|
|
413
|
+
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
|
|
414
|
+
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el: HTMLElement) => el.offsetWidth)];
|
|
417
415
|
});
|
|
418
416
|
|
|
419
|
-
function addToCheckedValues(id) {
|
|
417
|
+
function addToCheckedValues(id: any) {
|
|
420
418
|
if (checkboxesInternal.value.includes(id)) {
|
|
421
419
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
|
|
422
420
|
} else {
|
|
@@ -425,17 +423,17 @@ function addToCheckedValues(id) {
|
|
|
425
423
|
checkboxesInternal.value = [ ...checkboxesInternal.value ]
|
|
426
424
|
}
|
|
427
425
|
|
|
428
|
-
const columnsListed = computed(() => props.resource?.columns?.filter(c => c.showIn
|
|
426
|
+
const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
|
|
429
427
|
|
|
430
|
-
async function selectAll(
|
|
428
|
+
async function selectAll() {
|
|
431
429
|
if (!allFromThisPageChecked.value) {
|
|
432
|
-
props.rows
|
|
430
|
+
props.rows?.forEach((r) => {
|
|
433
431
|
if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
|
|
434
432
|
checkboxesInternal.value.push(r._primaryKeyValue)
|
|
435
433
|
}
|
|
436
434
|
});
|
|
437
435
|
} else {
|
|
438
|
-
props.rows
|
|
436
|
+
props.rows?.forEach((r) => {
|
|
439
437
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
|
|
440
438
|
});
|
|
441
439
|
}
|
|
@@ -448,15 +446,15 @@ const allFromThisPageChecked = computed(() => {
|
|
|
448
446
|
if (!props.rows || !props.rows.length) return false;
|
|
449
447
|
return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
|
|
450
448
|
});
|
|
451
|
-
const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
|
|
452
|
-
const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
|
|
449
|
+
const ascArr = computed(() => sort.value.filter((s: any) => s.direction === 'asc').map((s: any) => s.field));
|
|
450
|
+
const descArr = computed(() => sort.value.filter((s: any) => s.direction === 'desc').map((s: any) => s.field));
|
|
453
451
|
|
|
454
452
|
|
|
455
|
-
function onSortButtonClick(event, field) {
|
|
453
|
+
function onSortButtonClick(event: any, field: any) {
|
|
456
454
|
// if ctrl key is pressed, add to sort otherwise sort by this field
|
|
457
455
|
// in any case if field is already in sort, toggle direction
|
|
458
456
|
|
|
459
|
-
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
457
|
+
const sortIndex = sort.value.findIndex((s: any) => s.field === field);
|
|
460
458
|
if (sortIndex === -1) {
|
|
461
459
|
// field is not in sort, add it
|
|
462
460
|
if (event.ctrlKey) {
|
|
@@ -477,11 +475,11 @@ function onSortButtonClick(event, field) {
|
|
|
477
475
|
|
|
478
476
|
const clickTarget = ref(null);
|
|
479
477
|
|
|
480
|
-
async function onClick(e,row) {
|
|
478
|
+
async function onClick(e: any,row: any) {
|
|
481
479
|
if(clickTarget.value === e.target) return;
|
|
482
480
|
clickTarget.value = e.target;
|
|
483
481
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
484
|
-
if (window.getSelection()
|
|
482
|
+
if (window.getSelection()?.toString()) return;
|
|
485
483
|
else {
|
|
486
484
|
if (row._clickUrl === null) {
|
|
487
485
|
// user asked to nothing on click
|
|
@@ -496,7 +494,7 @@ async function onClick(e,row) {
|
|
|
496
494
|
router.resolve({
|
|
497
495
|
name: 'resource-show',
|
|
498
496
|
params: {
|
|
499
|
-
resourceId: props.resource
|
|
497
|
+
resourceId: props.resource?.resourceId,
|
|
500
498
|
primaryKey: row._primaryKeyValue,
|
|
501
499
|
},
|
|
502
500
|
}).href,
|
|
@@ -514,7 +512,7 @@ async function onClick(e,row) {
|
|
|
514
512
|
router.push({
|
|
515
513
|
name: 'resource-show',
|
|
516
514
|
params: {
|
|
517
|
-
resourceId: props.resource
|
|
515
|
+
resourceId: props.resource?.resourceId,
|
|
518
516
|
primaryKey: row._primaryKeyValue,
|
|
519
517
|
},
|
|
520
518
|
});
|
|
@@ -523,7 +521,7 @@ async function onClick(e,row) {
|
|
|
523
521
|
}
|
|
524
522
|
}
|
|
525
523
|
|
|
526
|
-
async function deleteRecord(row) {
|
|
524
|
+
async function deleteRecord(row: any) {
|
|
527
525
|
const data = await adminforth.confirm({
|
|
528
526
|
message: t('Are you sure you want to delete this item?'),
|
|
529
527
|
yes: t('Delete'),
|
|
@@ -535,7 +533,7 @@ async function deleteRecord(row) {
|
|
|
535
533
|
path: '/delete_record',
|
|
536
534
|
method: 'POST',
|
|
537
535
|
body: {
|
|
538
|
-
resourceId: props.resource
|
|
536
|
+
resourceId: props.resource?.resourceId,
|
|
539
537
|
primaryKey: row._primaryKeyValue,
|
|
540
538
|
}
|
|
541
539
|
});
|
|
@@ -553,16 +551,16 @@ async function deleteRecord(row) {
|
|
|
553
551
|
}
|
|
554
552
|
}
|
|
555
553
|
|
|
556
|
-
const actionLoadingStates = ref({});
|
|
554
|
+
const actionLoadingStates = ref<Record<string | number, boolean>>({});
|
|
557
555
|
|
|
558
|
-
async function startCustomAction(actionId, row) {
|
|
556
|
+
async function startCustomAction(actionId: string, row: any) {
|
|
559
557
|
actionLoadingStates.value[actionId] = true;
|
|
560
558
|
|
|
561
559
|
const data = await callAdminForthApi({
|
|
562
560
|
path: '/start_custom_action',
|
|
563
561
|
method: 'POST',
|
|
564
562
|
body: {
|
|
565
|
-
resourceId: props.resource
|
|
563
|
+
resourceId: props.resource?.resourceId,
|
|
566
564
|
actionId: actionId,
|
|
567
565
|
recordId: row._primaryKeyValue
|
|
568
566
|
}
|
|
@@ -600,7 +598,7 @@ async function startCustomAction(actionId, row) {
|
|
|
600
598
|
}
|
|
601
599
|
}
|
|
602
600
|
|
|
603
|
-
function onPageInput(event) {
|
|
601
|
+
function onPageInput(event: any) {
|
|
604
602
|
pageInput.value = event.target.innerText;
|
|
605
603
|
}
|
|
606
604
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
<div class="overflow-x-auto shadow-resourseFormShadow dark:shadow-darkResourseFormShadow"
|
|
3
|
+
:class="{'rounded-default' : isRounded}"
|
|
4
|
+
>
|
|
5
|
+
<div v-if="groupName && !noTitle" class="text-md font-semibold px-6 py-3 flex flex-1 items-center text-lightShowTableHeadingText bg-lightShowTableHeadingBackground dark:bg-darkShowTableHeadingBackground dark:text-darkShowTableHeadingText rounded-t-lg">
|
|
4
6
|
{{ groupName }}
|
|
5
7
|
</div>
|
|
6
|
-
<table class="w-full text-sm text-left rtl:text-right text-
|
|
7
|
-
<thead v-if="!allColumnsHaveCustomComponent" class="text-
|
|
8
|
+
<table class="w-full text-sm text-left rtl:text-right text-lightShowTableBodyText dark:text-darkShowTableBodyText table-fixed">
|
|
9
|
+
<thead v-if="!allColumnsHaveCustomComponent" class="text-lightShowTableUnderHeadingText dark:text-darkShowTableUnderHeadingText bg-lightShowTableUnderHeadingBackground dark:bg-darkShowTableUnderHeadingBackground dark:border-darkFormBorder block md:table-row-group">
|
|
8
10
|
<tr>
|
|
9
11
|
<th scope="col" class="px-6 py-3 text-xs uppercase hidden md:w-52 md:table-cell">
|
|
10
12
|
{{ $t('Field') }}
|
|
@@ -18,8 +20,8 @@
|
|
|
18
20
|
<tr
|
|
19
21
|
v-for="column in columns"
|
|
20
22
|
:key="column.name"
|
|
21
|
-
class="bg-
|
|
22
|
-
dark:bg-
|
|
23
|
+
class="bg-lightShowTablesBodyBackground border-t border-lightShowTableBodyBorder
|
|
24
|
+
dark:bg-darkShowTablesBodyBackground dark:border-darkShowTableBodyBorder block md:table-row"
|
|
23
25
|
>
|
|
24
26
|
<component
|
|
25
27
|
v-if="column.components?.showRow"
|
|
@@ -60,10 +62,11 @@
|
|
|
60
62
|
import { getCustomComponent } from '@/utils';
|
|
61
63
|
import { useCoreStore } from '@/stores/core';
|
|
62
64
|
import { computed } from 'vue';
|
|
63
|
-
|
|
65
|
+
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
66
|
+
const props = withDefaults(defineProps<{
|
|
64
67
|
columns: Array<{
|
|
65
68
|
name: string;
|
|
66
|
-
label
|
|
69
|
+
label?: string;
|
|
67
70
|
components?: {
|
|
68
71
|
show?: {
|
|
69
72
|
file: string;
|
|
@@ -75,13 +78,15 @@
|
|
|
75
78
|
};
|
|
76
79
|
};
|
|
77
80
|
}>;
|
|
78
|
-
source: string;
|
|
79
81
|
groupName?: string | null;
|
|
80
82
|
noTitle?: boolean;
|
|
81
|
-
resource:
|
|
83
|
+
resource: AdminForthResourceCommon | null;
|
|
82
84
|
record: Record<string, any>;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
isRounded?: boolean;
|
|
86
|
+
}>(), {
|
|
87
|
+
isRounded: true
|
|
88
|
+
});
|
|
89
|
+
|
|
85
90
|
const coreStore = useCoreStore();
|
|
86
91
|
const allColumnsHaveCustomComponent = computed(() => {
|
|
87
92
|
return props.columns.every(column => {
|