adminforth 2.7.18 → 2.8.0
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/createApp/templates/index.ts.hbs +2 -1
- 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/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +33 -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 +30 -1
- 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/modules/codeInjector.d.ts +1 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +4 -0
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +6 -2
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +2 -0
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +8 -1
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +9 -2
- package/dist/modules/styles.js.map +1 -1
- package/dist/spa/src/App.vue +12 -4
- package/dist/spa/src/adminforth.ts +31 -11
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Checkbox.vue +2 -2
- package/dist/spa/src/afcl/Dialog.vue +38 -21
- package/dist/spa/src/afcl/Dropzone.vue +2 -2
- package/dist/spa/src/afcl/Input.vue +1 -1
- package/dist/spa/src/afcl/LinkButton.vue +1 -1
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/Select.vue +17 -12
- package/dist/spa/src/afcl/Table.vue +202 -72
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +2 -2
- package/dist/spa/src/afcl/Tooltip.vue +0 -1
- package/dist/spa/src/afcl/index.ts +1 -1
- package/dist/spa/src/components/AcceptModal.vue +1 -1
- package/dist/spa/src/components/ColumnValueInput.vue +11 -11
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +2 -2
- package/dist/spa/src/components/CustomRangePicker.vue +5 -5
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +7 -6
- package/dist/spa/src/components/GroupsTable.vue +2 -1
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +35 -27
- package/dist/spa/src/components/ResourceListTable.vue +42 -42
- package/dist/spa/src/components/ResourceListTableVirtual.vue +41 -41
- package/dist/spa/src/components/ShowTable.vue +3 -3
- package/dist/spa/src/components/SkeleteLoader.vue +2 -2
- package/dist/spa/src/components/ThreeDotsMenu.vue +69 -10
- package/dist/spa/src/components/Toast.vue +25 -2
- package/dist/spa/src/components/ValueRenderer.vue +39 -12
- package/dist/spa/src/i18n.ts +1 -1
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +1 -1
- 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 +31 -6
- package/dist/spa/src/types/Common.ts +33 -24
- package/dist/spa/src/types/FrontendAPI.ts +21 -5
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -4
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/index.ts +1 -0
- package/dist/spa/src/utils.ts +8 -7
- package/dist/spa/src/views/CreateView.vue +15 -16
- package/dist/spa/src/views/EditView.vue +23 -17
- package/dist/spa/src/views/ListView.vue +116 -66
- package/dist/spa/src/views/LoginView.vue +2 -9
- package/dist/spa/src/views/ResourceParent.vue +1 -1
- 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 +16 -1
- 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 +27 -22
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +21 -3
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/EmailAdapter.d.ts +2 -3
- package/dist/types/adapters/EmailAdapter.d.ts.map +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/index.d.ts +1 -0
- package/dist/types/adapters/index.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -65,12 +65,12 @@
|
|
|
65
65
|
|
|
66
66
|
import { applyRegexValidation, callAdminForthApi, loadMoreForeignOptions, searchForeignOptions, createSearchInputHandlers} from '@/utils';
|
|
67
67
|
import { computedAsync } from '@vueuse/core';
|
|
68
|
-
import { computed, onMounted, reactive, ref, watch, provide } from 'vue';
|
|
68
|
+
import { computed, onMounted, reactive, ref, watch, provide, type Ref } from 'vue';
|
|
69
69
|
import { useRouter, useRoute } from 'vue-router';
|
|
70
70
|
import { useCoreStore } from "@/stores/core";
|
|
71
71
|
import GroupsTable from '@/components/GroupsTable.vue';
|
|
72
72
|
import { useI18n } from 'vue-i18n';
|
|
73
|
-
import { type AdminForthResourceCommon } from '@/types/Common';
|
|
73
|
+
import { type AdminForthResourceColumnCommon, type AdminForthResourceCommon } from '@/types/Common';
|
|
74
74
|
|
|
75
75
|
const { t } = useI18n();
|
|
76
76
|
|
|
@@ -91,16 +91,16 @@ const mode = computed(() => route.name === 'resource-create' ? 'create' : 'edit'
|
|
|
91
91
|
|
|
92
92
|
const emit = defineEmits(['update:record', 'update:isValid']);
|
|
93
93
|
|
|
94
|
-
const currentValues = ref(null);
|
|
95
|
-
const customComponentsInValidity = ref({});
|
|
96
|
-
const customComponentsEmptiness = ref({});
|
|
94
|
+
const currentValues = ref<any | any[] | null>(null);
|
|
95
|
+
const customComponentsInValidity: Ref<Record<string, AdminForthResourceColumnCommon>> = ref({});
|
|
96
|
+
const customComponentsEmptiness: Ref<Record<string, AdminForthResourceColumnCommon>> = ref({});
|
|
97
97
|
|
|
98
98
|
const columnOptions = ref<Record<string, any[]>>({});
|
|
99
99
|
const columnLoadingState = reactive<Record<string, { loading: boolean; hasMore: boolean }>>({});
|
|
100
100
|
const columnOffsets = reactive<Record<string, number>>({});
|
|
101
101
|
const columnEmptyResultsCount = reactive<Record<string, number>>({});
|
|
102
102
|
|
|
103
|
-
const columnError = (column) => {
|
|
103
|
+
const columnError = (column: AdminForthResourceColumnCommon) => {
|
|
104
104
|
const val = computed(() => {
|
|
105
105
|
if (!currentValues.value) {
|
|
106
106
|
return null;
|
|
@@ -109,7 +109,7 @@ const columnError = (column) => {
|
|
|
109
109
|
return customComponentsInValidity.value?.[column.name];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
if ( column.required[mode.value] ) {
|
|
112
|
+
if ( column.required?.[mode.value] ) {
|
|
113
113
|
const naturalEmptiness = currentValues.value[column.name] === undefined ||
|
|
114
114
|
currentValues.value[column.name] === null ||
|
|
115
115
|
currentValues.value[column.name] === '' ||
|
|
@@ -136,17 +136,23 @@ const columnError = (column) => {
|
|
|
136
136
|
}
|
|
137
137
|
} else if (column.isArray?.enabled) {
|
|
138
138
|
if (!column.isArray.allowDuplicateItems) {
|
|
139
|
-
if (currentValues.value[column.name].filter((value, index, self) => self.indexOf(value) !== index).length > 0) {
|
|
139
|
+
if (currentValues.value[column.name].filter((value: any, index: any, self: any) => self.indexOf(value) !== index).length > 0) {
|
|
140
140
|
return t('Array cannot contain duplicate items');
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
return currentValues.value[column.name] && currentValues.value[column.name].reduce((error, item) => {
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
return currentValues.value[column.name] && currentValues.value[column.name].reduce((error: any, item: any) => {
|
|
145
|
+
if (column.isArray) {
|
|
146
|
+
return error || validateValue(column.isArray.itemType, item, column) ||
|
|
147
|
+
(item === null || !item.toString() ? t('Array cannot contain empty items') : null);
|
|
148
|
+
} else {
|
|
149
|
+
return error;
|
|
150
|
+
}
|
|
147
151
|
}, null);
|
|
148
152
|
} else {
|
|
149
|
-
|
|
153
|
+
if (column.type) {
|
|
154
|
+
return validateValue(column.type, currentValues.value[column.name], column);
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
return null;
|
|
@@ -154,7 +160,7 @@ const columnError = (column) => {
|
|
|
154
160
|
return val.value;
|
|
155
161
|
};
|
|
156
162
|
|
|
157
|
-
const validateValue = (type, value, column) => {
|
|
163
|
+
const validateValue = (type: string, value: any, column: AdminForthResourceColumnCommon) => {
|
|
158
164
|
if (type === 'string' || type === 'text') {
|
|
159
165
|
if (column.maxLength && value?.length > column.maxLength) {
|
|
160
166
|
return t('This field must be shorter than {maxLength} characters', { maxLength: column.maxLength });
|
|
@@ -162,7 +168,7 @@ const validateValue = (type, value, column) => {
|
|
|
162
168
|
|
|
163
169
|
if (column.minLength && value?.length < column.minLength) {
|
|
164
170
|
// if column.required[mode.value] is false, then we check if the field is empty
|
|
165
|
-
let needToCheckEmpty = column.required[mode.value] || value?.length > 0;
|
|
171
|
+
let needToCheckEmpty = column.required?.[mode.value] || value?.length > 0;
|
|
166
172
|
if (!needToCheckEmpty) {
|
|
167
173
|
return null;
|
|
168
174
|
}
|
|
@@ -191,10 +197,10 @@ const validateValue = (type, value, column) => {
|
|
|
191
197
|
};
|
|
192
198
|
|
|
193
199
|
|
|
194
|
-
const setCurrentValue = (key, value, index = null) => {
|
|
200
|
+
const setCurrentValue = (key: any, value: any, index = null) => {
|
|
195
201
|
const col = props.resource.columns.find((column) => column.name === key);
|
|
196
202
|
// if field is an array, we need to update the array or individual element
|
|
197
|
-
if (col.type === 'json' && col.isArray?.enabled) {
|
|
203
|
+
if (((col?.type && col.type === 'json') && (col?.type && col.isArray?.enabled))) {
|
|
198
204
|
if (index === null) {
|
|
199
205
|
currentValues.value[key] = value;
|
|
200
206
|
} else if (index === currentValues.value[key].length) {
|
|
@@ -209,12 +215,12 @@ const setCurrentValue = (key, value, index = null) => {
|
|
|
209
215
|
} else {
|
|
210
216
|
currentValues.value[key][index] = value;
|
|
211
217
|
}
|
|
212
|
-
if (['text', 'richtext', 'string'].includes(col.isArray.itemType) && col.enforceLowerCase) {
|
|
218
|
+
if (col?.isArray && ['text', 'richtext', 'string'].includes(col.isArray.itemType) && col.enforceLowerCase) {
|
|
213
219
|
currentValues.value[key][index] = currentValues.value[key][index].toLowerCase();
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
} else {
|
|
217
|
-
if (['integer', 'float', 'decimal'].includes(col.type)) {
|
|
223
|
+
if (col?.type && ['integer', 'float', 'decimal'].includes(col.type)) {
|
|
218
224
|
if (value || value === 0) {
|
|
219
225
|
currentValues.value[key] = +value;
|
|
220
226
|
} else {
|
|
@@ -223,7 +229,7 @@ const setCurrentValue = (key, value, index = null) => {
|
|
|
223
229
|
} else {
|
|
224
230
|
currentValues.value[key] = value;
|
|
225
231
|
}
|
|
226
|
-
if (['text', 'richtext', 'string'].includes(col
|
|
232
|
+
if (col?.type && ['text', 'richtext', 'string'].includes(col?.type) && col.enforceLowerCase) {
|
|
227
233
|
currentValues.value[key] = currentValues.value[key].toLowerCase();
|
|
228
234
|
}
|
|
229
235
|
}
|
|
@@ -265,7 +271,7 @@ onMounted(() => {
|
|
|
265
271
|
currentValues.value = Object.assign({}, props.record);
|
|
266
272
|
// json values should transform to string
|
|
267
273
|
props.resource.columns.forEach((column) => {
|
|
268
|
-
if (column.type === 'json') {
|
|
274
|
+
if (column.type === 'json' && currentValues.value) {
|
|
269
275
|
if (column.isArray?.enabled) {
|
|
270
276
|
// if value is null or undefined, we should set it to empty array
|
|
271
277
|
if (!currentValues.value[column.name]) {
|
|
@@ -316,7 +322,7 @@ async function searchOptions(columnName: string, searchTerm: string) {
|
|
|
316
322
|
|
|
317
323
|
|
|
318
324
|
const editableColumns = computed(() => {
|
|
319
|
-
return props.resource?.columns?.filter(column => column.showIn[mode.value]);
|
|
325
|
+
return props.resource?.columns?.filter(column => column.showIn?.[mode.value]);
|
|
320
326
|
});
|
|
321
327
|
|
|
322
328
|
const isValid = computed(() => {
|
|
@@ -326,12 +332,14 @@ const isValid = computed(() => {
|
|
|
326
332
|
|
|
327
333
|
const groups = computed(() => {
|
|
328
334
|
let fieldGroupType;
|
|
329
|
-
if
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
if(coreStore.resource){
|
|
336
|
+
if (mode.value === 'edit' && coreStore.resource.options?.editFieldGroups !== undefined) {
|
|
337
|
+
fieldGroupType = coreStore.resource.options.editFieldGroups;
|
|
338
|
+
} else if (mode.value === 'create' && coreStore.resource.options?.createFieldGroups !== undefined) {
|
|
339
|
+
fieldGroupType = coreStore.resource.options.createFieldGroups;
|
|
340
|
+
} else {
|
|
341
|
+
fieldGroupType = coreStore.resource.options?.fieldGroups;
|
|
342
|
+
}
|
|
335
343
|
}
|
|
336
344
|
return fieldGroupType ?? [];
|
|
337
345
|
});
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
</div>
|
|
48
48
|
<span
|
|
49
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"
|
|
50
|
-
v-if="sort.findIndex((s) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
51
|
-
{{ 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 }}
|
|
52
52
|
</span>
|
|
53
53
|
|
|
54
54
|
</div>
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
<!-- table header end -->
|
|
65
65
|
<SkeleteLoader
|
|
66
66
|
v-if="!rows"
|
|
67
|
-
:columns="resource?.columns.filter(c => c.showIn
|
|
67
|
+
:columns="resource?.columns.filter((c: AdminForthResourceColumnInputCommon) => c.showIn?.list).length + 2"
|
|
68
68
|
:rows="rowHeights.length || 3"
|
|
69
69
|
:row-heights="rowHeights"
|
|
70
70
|
:column-widths="columnWidths"
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
|
|
94
94
|
<Checkbox
|
|
95
95
|
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
|
|
96
|
-
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
97
|
-
@click="(e)=>e.stopPropagation()"
|
|
96
|
+
@change="(e: any)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
97
|
+
@click="(e: any)=>e.stopPropagation()"
|
|
98
98
|
>
|
|
99
99
|
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
100
100
|
</Checkbox>
|
|
@@ -103,8 +103,8 @@
|
|
|
103
103
|
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
|
|
104
104
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
105
105
|
<component
|
|
106
|
-
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
107
|
-
: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"
|
|
108
108
|
:column="c"
|
|
109
109
|
:record="row"
|
|
110
110
|
:adminUser="coreStore.adminUser"
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
<div class="flex text-lightPrimary dark:text-darkPrimary items-center">
|
|
116
116
|
<Tooltip>
|
|
117
117
|
<RouterLink
|
|
118
|
-
v-if="resource.options?.allowedActions
|
|
118
|
+
v-if="resource.options?.allowedActions?.show"
|
|
119
119
|
:to="{
|
|
120
120
|
name: 'resource-show',
|
|
121
121
|
params: {
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
|
|
136
136
|
<Tooltip>
|
|
137
137
|
<RouterLink
|
|
138
|
-
v-if="resource.options?.allowedActions
|
|
138
|
+
v-if="resource.options?.allowedActions?.edit"
|
|
139
139
|
:to="{
|
|
140
140
|
name: 'resource-edit',
|
|
141
141
|
params: {
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
|
|
154
154
|
<Tooltip>
|
|
155
155
|
<button
|
|
156
|
-
v-if="resource.options?.allowedActions
|
|
156
|
+
v-if="resource.options?.allowedActions?.delete"
|
|
157
157
|
@click="deleteRecord(row)"
|
|
158
158
|
>
|
|
159
159
|
<IconTrashBinSolid class="af-delete-icon w-5 h-5 me-2"/>
|
|
@@ -308,7 +308,7 @@ import {
|
|
|
308
308
|
} from '@iconify-prerendered/vue-flowbite';
|
|
309
309
|
import router from '@/router';
|
|
310
310
|
import { Tooltip } from '@/afcl';
|
|
311
|
-
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
311
|
+
import type { AdminForthResourceCommon, AdminForthResourceColumnInputCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
312
312
|
import adminforth from '@/adminforth';
|
|
313
313
|
import Checkbox from '@/afcl/Checkbox.vue';
|
|
314
314
|
|
|
@@ -339,7 +339,7 @@ const emits = defineEmits([
|
|
|
339
339
|
const checkboxesInternal: Ref<any[]> = ref([]);
|
|
340
340
|
const pageInput = ref('1');
|
|
341
341
|
const page = ref(1);
|
|
342
|
-
const sort = ref([]);
|
|
342
|
+
const sort: Ref<Array<{field: string, direction: string}>> = ref([]);
|
|
343
343
|
|
|
344
344
|
|
|
345
345
|
const from = computed(() => ((page.value || 1) - 1) * props.pageSize + 1);
|
|
@@ -348,11 +348,11 @@ const to = computed(() => Math.min((page.value || 1) * props.pageSize, props.tot
|
|
|
348
348
|
watch(() => page.value, (newPage) => {
|
|
349
349
|
emits('update:page', newPage);
|
|
350
350
|
});
|
|
351
|
-
async function onPageKeydown(event) {
|
|
351
|
+
async function onPageKeydown(event: any) {
|
|
352
352
|
// page input should accept only numbers, arrow keys and backspace
|
|
353
353
|
if (['Enter', 'Space'].includes(event.code) ||
|
|
354
354
|
(!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
|
|
355
|
-
&& isNaN(String.fromCharCode(event.keyCode)))) {
|
|
355
|
+
&& isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
|
|
356
356
|
event.preventDefault();
|
|
357
357
|
if (event.code === 'Enter') {
|
|
358
358
|
validatePageInput();
|
|
@@ -373,7 +373,7 @@ watch(() => props.checkboxes, (newCheckboxes) => {
|
|
|
373
373
|
checkboxesInternal.value = newCheckboxes;
|
|
374
374
|
});
|
|
375
375
|
|
|
376
|
-
watch(() => props.sort, (newSort) => {
|
|
376
|
+
watch(() => props.sort, (newSort: any) => {
|
|
377
377
|
sort.value = newSort;
|
|
378
378
|
});
|
|
379
379
|
|
|
@@ -384,17 +384,17 @@ watch(() => props.page, (newPage) => {
|
|
|
384
384
|
page.value = newPage;
|
|
385
385
|
});
|
|
386
386
|
|
|
387
|
-
const rowRefs = useTemplateRef('rowRefs');
|
|
388
|
-
const headerRefs = useTemplateRef('headerRefs');
|
|
389
|
-
const rowHeights = ref([]);
|
|
390
|
-
const columnWidths = ref([]);
|
|
387
|
+
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
|
|
388
|
+
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
|
|
389
|
+
const rowHeights = ref<number[]>([]);
|
|
390
|
+
const columnWidths = ref<number[]>([]);
|
|
391
391
|
watch(() => props.rows, (newRows) => {
|
|
392
392
|
// rows are set to null when new records are loading
|
|
393
|
-
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el) => el.offsetHeight);
|
|
394
|
-
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el) => el.offsetWidth)];
|
|
393
|
+
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
|
|
394
|
+
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el: HTMLElement) => el.offsetWidth)];
|
|
395
395
|
});
|
|
396
396
|
|
|
397
|
-
function addToCheckedValues(id) {
|
|
397
|
+
function addToCheckedValues(id: string) {
|
|
398
398
|
if (checkboxesInternal.value.includes(id)) {
|
|
399
399
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
|
|
400
400
|
} else {
|
|
@@ -403,17 +403,17 @@ function addToCheckedValues(id) {
|
|
|
403
403
|
checkboxesInternal.value = [ ...checkboxesInternal.value ]
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
const columnsListed = computed(() => props.resource?.columns?.filter(c => c.showIn
|
|
406
|
+
const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
|
|
407
407
|
|
|
408
|
-
async function selectAll(
|
|
408
|
+
async function selectAll() {
|
|
409
409
|
if (!allFromThisPageChecked.value) {
|
|
410
|
-
props.rows
|
|
410
|
+
props.rows?.forEach((r) => {
|
|
411
411
|
if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
|
|
412
412
|
checkboxesInternal.value.push(r._primaryKeyValue)
|
|
413
413
|
}
|
|
414
414
|
});
|
|
415
415
|
} else {
|
|
416
|
-
props.rows
|
|
416
|
+
props.rows?.forEach((r) => {
|
|
417
417
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
|
|
418
418
|
});
|
|
419
419
|
}
|
|
@@ -426,15 +426,15 @@ const allFromThisPageChecked = computed(() => {
|
|
|
426
426
|
if (!props.rows || !props.rows.length) return false;
|
|
427
427
|
return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
|
|
428
428
|
});
|
|
429
|
-
const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
|
|
430
|
-
const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
|
|
429
|
+
const ascArr = computed(() => sort.value.filter((s:any) => s.direction === 'asc').map((s: any) => s.field));
|
|
430
|
+
const descArr = computed(() => sort.value.filter((s: any) => s.direction === 'desc').map((s: any) => s.field));
|
|
431
431
|
|
|
432
432
|
|
|
433
|
-
function onSortButtonClick(event, field) {
|
|
433
|
+
function onSortButtonClick(event: any, field: string) {
|
|
434
434
|
// if ctrl key is pressed, add to sort otherwise sort by this field
|
|
435
435
|
// in any case if field is already in sort, toggle direction
|
|
436
436
|
|
|
437
|
-
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
437
|
+
const sortIndex = sort.value.findIndex((s: any) => s.field === field);
|
|
438
438
|
if (sortIndex === -1) {
|
|
439
439
|
// field is not in sort, add it
|
|
440
440
|
if (event.ctrlKey) {
|
|
@@ -445,9 +445,9 @@ function onSortButtonClick(event, field) {
|
|
|
445
445
|
} else {
|
|
446
446
|
const sortField = sort.value[sortIndex];
|
|
447
447
|
if (sortField.direction === 'asc') {
|
|
448
|
-
sort.value = sort.value.map((s) => s.field === field ? {field, direction: 'desc'} : s);
|
|
448
|
+
sort.value = sort.value.map((s: any) => s.field === field ? {field, direction: 'desc'} : s);
|
|
449
449
|
} else {
|
|
450
|
-
sort.value = sort.value.filter((s) => s.field !== field);
|
|
450
|
+
sort.value = sort.value.filter((s: any) => s.field !== field);
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
}
|
|
@@ -455,11 +455,11 @@ function onSortButtonClick(event, field) {
|
|
|
455
455
|
|
|
456
456
|
const clickTarget = ref(null);
|
|
457
457
|
|
|
458
|
-
async function onClick(e,row) {
|
|
458
|
+
async function onClick(e: any, row: any) {
|
|
459
459
|
if(clickTarget.value === e.target) return;
|
|
460
460
|
clickTarget.value = e.target;
|
|
461
461
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
462
|
-
if (window.getSelection()
|
|
462
|
+
if (window.getSelection()?.toString()) return;
|
|
463
463
|
else {
|
|
464
464
|
if (row._clickUrl === null) {
|
|
465
465
|
// user asked to nothing on click
|
|
@@ -474,7 +474,7 @@ async function onClick(e,row) {
|
|
|
474
474
|
router.resolve({
|
|
475
475
|
name: 'resource-show',
|
|
476
476
|
params: {
|
|
477
|
-
resourceId: props.resource
|
|
477
|
+
resourceId: props.resource?.resourceId,
|
|
478
478
|
primaryKey: row._primaryKeyValue,
|
|
479
479
|
},
|
|
480
480
|
}).href,
|
|
@@ -492,7 +492,7 @@ async function onClick(e,row) {
|
|
|
492
492
|
router.push({
|
|
493
493
|
name: 'resource-show',
|
|
494
494
|
params: {
|
|
495
|
-
resourceId: props.resource
|
|
495
|
+
resourceId: props.resource?.resourceId,
|
|
496
496
|
primaryKey: row._primaryKeyValue,
|
|
497
497
|
},
|
|
498
498
|
});
|
|
@@ -501,7 +501,7 @@ async function onClick(e,row) {
|
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
-
async function deleteRecord(row) {
|
|
504
|
+
async function deleteRecord(row: any) {
|
|
505
505
|
const data = await adminforth.confirm({
|
|
506
506
|
message: t('Are you sure you want to delete this item?'),
|
|
507
507
|
yes: t('Delete'),
|
|
@@ -513,7 +513,7 @@ async function deleteRecord(row) {
|
|
|
513
513
|
path: '/delete_record',
|
|
514
514
|
method: 'POST',
|
|
515
515
|
body: {
|
|
516
|
-
resourceId: props.resource
|
|
516
|
+
resourceId: props.resource?.resourceId,
|
|
517
517
|
primaryKey: row._primaryKeyValue,
|
|
518
518
|
}
|
|
519
519
|
});
|
|
@@ -531,16 +531,16 @@ async function deleteRecord(row) {
|
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
-
const actionLoadingStates = ref({});
|
|
534
|
+
const actionLoadingStates = ref<Record<string | number, boolean>>({});
|
|
535
535
|
|
|
536
|
-
async function startCustomAction(actionId, row) {
|
|
536
|
+
async function startCustomAction(actionId: string, row: any) {
|
|
537
537
|
actionLoadingStates.value[actionId] = true;
|
|
538
538
|
|
|
539
539
|
const data = await callAdminForthApi({
|
|
540
540
|
path: '/start_custom_action',
|
|
541
541
|
method: 'POST',
|
|
542
542
|
body: {
|
|
543
|
-
resourceId: props.resource
|
|
543
|
+
resourceId: props.resource?.resourceId,
|
|
544
544
|
actionId: actionId,
|
|
545
545
|
recordId: row._primaryKeyValue
|
|
546
546
|
}
|
|
@@ -578,7 +578,7 @@ async function startCustomAction(actionId, row) {
|
|
|
578
578
|
}
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
-
function onPageInput(event) {
|
|
581
|
+
function onPageInput(event: any) {
|
|
582
582
|
pageInput.value = event.target.innerText;
|
|
583
583
|
}
|
|
584
584
|
|