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.
Files changed (107) hide show
  1. package/commands/createApp/templates/index.ts.hbs +2 -1
  2. package/commands/createCustomComponent/main.js +1 -0
  3. package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
  4. package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
  5. package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
  6. package/dist/dataConnectors/baseConnector.js +33 -15
  7. package/dist/dataConnectors/baseConnector.js.map +1 -1
  8. package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
  9. package/dist/dataConnectors/clickhouse.js +15 -0
  10. package/dist/dataConnectors/clickhouse.js.map +1 -1
  11. package/dist/dataConnectors/mongo.d.ts.map +1 -1
  12. package/dist/dataConnectors/mongo.js +30 -1
  13. package/dist/dataConnectors/mongo.js.map +1 -1
  14. package/dist/dataConnectors/mysql.d.ts.map +1 -1
  15. package/dist/dataConnectors/mysql.js +11 -0
  16. package/dist/dataConnectors/mysql.js.map +1 -1
  17. package/dist/dataConnectors/postgres.d.ts.map +1 -1
  18. package/dist/dataConnectors/postgres.js +11 -0
  19. package/dist/dataConnectors/postgres.js.map +1 -1
  20. package/dist/dataConnectors/sqlite.d.ts.map +1 -1
  21. package/dist/dataConnectors/sqlite.js +11 -0
  22. package/dist/dataConnectors/sqlite.js.map +1 -1
  23. package/dist/modules/codeInjector.d.ts +1 -0
  24. package/dist/modules/codeInjector.d.ts.map +1 -1
  25. package/dist/modules/codeInjector.js +4 -0
  26. package/dist/modules/codeInjector.js.map +1 -1
  27. package/dist/modules/configValidator.d.ts.map +1 -1
  28. package/dist/modules/configValidator.js +6 -2
  29. package/dist/modules/configValidator.js.map +1 -1
  30. package/dist/modules/restApi.d.ts.map +1 -1
  31. package/dist/modules/restApi.js +2 -0
  32. package/dist/modules/restApi.js.map +1 -1
  33. package/dist/modules/styles.d.ts +8 -1
  34. package/dist/modules/styles.d.ts.map +1 -1
  35. package/dist/modules/styles.js +9 -2
  36. package/dist/modules/styles.js.map +1 -1
  37. package/dist/spa/src/App.vue +12 -4
  38. package/dist/spa/src/adminforth.ts +31 -11
  39. package/dist/spa/src/afcl/BarChart.vue +2 -2
  40. package/dist/spa/src/afcl/Checkbox.vue +2 -2
  41. package/dist/spa/src/afcl/Dialog.vue +38 -21
  42. package/dist/spa/src/afcl/Dropzone.vue +2 -2
  43. package/dist/spa/src/afcl/Input.vue +1 -1
  44. package/dist/spa/src/afcl/LinkButton.vue +1 -1
  45. package/dist/spa/src/afcl/PieChart.vue +5 -5
  46. package/dist/spa/src/afcl/Select.vue +17 -12
  47. package/dist/spa/src/afcl/Table.vue +202 -72
  48. package/dist/spa/src/afcl/Textarea.vue +31 -0
  49. package/dist/spa/src/afcl/Toggle.vue +2 -2
  50. package/dist/spa/src/afcl/Tooltip.vue +0 -1
  51. package/dist/spa/src/afcl/index.ts +1 -1
  52. package/dist/spa/src/components/AcceptModal.vue +1 -1
  53. package/dist/spa/src/components/ColumnValueInput.vue +11 -11
  54. package/dist/spa/src/components/ColumnValueInputWrapper.vue +2 -2
  55. package/dist/spa/src/components/CustomRangePicker.vue +5 -5
  56. package/dist/spa/src/components/ErrorMessage.vue +21 -0
  57. package/dist/spa/src/components/Filters.vue +7 -6
  58. package/dist/spa/src/components/GroupsTable.vue +2 -1
  59. package/dist/spa/src/components/MenuLink.vue +3 -3
  60. package/dist/spa/src/components/ResourceForm.vue +35 -27
  61. package/dist/spa/src/components/ResourceListTable.vue +42 -42
  62. package/dist/spa/src/components/ResourceListTableVirtual.vue +41 -41
  63. package/dist/spa/src/components/ShowTable.vue +3 -3
  64. package/dist/spa/src/components/SkeleteLoader.vue +2 -2
  65. package/dist/spa/src/components/ThreeDotsMenu.vue +69 -10
  66. package/dist/spa/src/components/Toast.vue +25 -2
  67. package/dist/spa/src/components/ValueRenderer.vue +39 -12
  68. package/dist/spa/src/i18n.ts +1 -1
  69. package/dist/spa/src/shims-vue.d.ts +5 -0
  70. package/dist/spa/src/spa_types/core.ts +1 -1
  71. package/dist/spa/src/stores/modal.ts +6 -1
  72. package/dist/spa/src/stores/toast.ts +22 -3
  73. package/dist/spa/src/types/Back.ts +31 -6
  74. package/dist/spa/src/types/Common.ts +33 -24
  75. package/dist/spa/src/types/FrontendAPI.ts +21 -5
  76. package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -4
  77. package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
  78. package/dist/spa/src/types/adapters/index.ts +1 -0
  79. package/dist/spa/src/utils.ts +8 -7
  80. package/dist/spa/src/views/CreateView.vue +15 -16
  81. package/dist/spa/src/views/EditView.vue +23 -17
  82. package/dist/spa/src/views/ListView.vue +116 -66
  83. package/dist/spa/src/views/LoginView.vue +2 -9
  84. package/dist/spa/src/views/ResourceParent.vue +1 -1
  85. package/dist/spa/src/views/ShowView.vue +59 -39
  86. package/dist/spa/src/websocket.ts +6 -1
  87. package/dist/spa/tsconfig.app.json +1 -1
  88. package/dist/spa/vite.config.ts +45 -2
  89. package/dist/types/Back.d.ts +16 -1
  90. package/dist/types/Back.d.ts.map +1 -1
  91. package/dist/types/Back.js +15 -0
  92. package/dist/types/Back.js.map +1 -1
  93. package/dist/types/Common.d.ts +27 -22
  94. package/dist/types/Common.d.ts.map +1 -1
  95. package/dist/types/Common.js.map +1 -1
  96. package/dist/types/FrontendAPI.d.ts +21 -3
  97. package/dist/types/FrontendAPI.d.ts.map +1 -1
  98. package/dist/types/FrontendAPI.js.map +1 -1
  99. package/dist/types/adapters/EmailAdapter.d.ts +2 -3
  100. package/dist/types/adapters/EmailAdapter.d.ts.map +1 -1
  101. package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
  102. package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
  103. package/dist/types/adapters/ImageVisionAdapter.js +2 -0
  104. package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
  105. package/dist/types/adapters/index.d.ts +1 -0
  106. package/dist/types/adapters/index.d.ts.map +1 -1
  107. 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
- return error || validateValue(column.isArray.itemType, item, column) ||
146
- (item === null || !item.toString() ? t('Array cannot contain empty items') : null);
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
- return validateValue(column.type, currentValues.value[column.name], column);
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.type) && col.enforceLowerCase) {
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 (mode.value === 'edit' && coreStore.resource.options?.editFieldGroups !== undefined) {
330
- fieldGroupType = coreStore.resource.options.editFieldGroups;
331
- } else if (mode.value === 'create' && coreStore.resource.options?.createFieldGroups !== undefined) {
332
- fieldGroupType = coreStore.resource.options.createFieldGroups;
333
- } else {
334
- fieldGroupType = coreStore.resource.options?.fieldGroups;
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.list).length + 2"
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?.meta"
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.show"
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.edit"
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.delete"
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.list));
406
+ const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
407
407
 
408
- async function selectAll(value) {
408
+ async function selectAll() {
409
409
  if (!allFromThisPageChecked.value) {
410
- props.rows.forEach((r) => {
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.forEach((r) => {
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().toString()) return;
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.resourceId,
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.resourceId,
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.resourceId,
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.resourceId,
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