adminforth 2.4.0-next.13 → 2.4.0-next.130

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 (149) hide show
  1. package/commands/callTsProxy.js +14 -4
  2. package/commands/cli.js +12 -4
  3. package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
  4. package/commands/createApp/templates/index.ts.hbs +10 -2
  5. package/commands/createApp/templates/package.json.hbs +1 -1
  6. package/commands/createApp/utils.js +27 -2
  7. package/commands/createCustomComponent/configLoader.js +3 -0
  8. package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
  9. package/dist/dataConnectors/baseConnector.js +16 -3
  10. package/dist/dataConnectors/baseConnector.js.map +1 -1
  11. package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
  12. package/dist/dataConnectors/clickhouse.js +4 -0
  13. package/dist/dataConnectors/clickhouse.js.map +1 -1
  14. package/dist/dataConnectors/mongo.d.ts.map +1 -1
  15. package/dist/dataConnectors/mongo.js +14 -14
  16. package/dist/dataConnectors/mongo.js.map +1 -1
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +20 -9
  20. package/dist/index.js.map +1 -1
  21. package/dist/modules/codeInjector.d.ts.map +1 -1
  22. package/dist/modules/codeInjector.js +22 -5
  23. package/dist/modules/codeInjector.js.map +1 -1
  24. package/dist/modules/configValidator.d.ts.map +1 -1
  25. package/dist/modules/configValidator.js +53 -2
  26. package/dist/modules/configValidator.js.map +1 -1
  27. package/dist/modules/restApi.d.ts.map +1 -1
  28. package/dist/modules/restApi.js +147 -25
  29. package/dist/modules/restApi.js.map +1 -1
  30. package/dist/modules/styles.d.ts +457 -13
  31. package/dist/modules/styles.d.ts.map +1 -1
  32. package/dist/modules/styles.js +513 -31
  33. package/dist/modules/styles.js.map +1 -1
  34. package/dist/modules/utils.d.ts +1 -0
  35. package/dist/modules/utils.d.ts.map +1 -1
  36. package/dist/modules/utils.js +9 -0
  37. package/dist/modules/utils.js.map +1 -1
  38. package/dist/spa/index.html +1 -1
  39. package/dist/spa/src/App.vue +33 -15
  40. package/dist/spa/src/adminforth.ts +15 -6
  41. package/dist/spa/src/afcl/BarChart.vue +2 -2
  42. package/dist/spa/src/afcl/Button.vue +6 -6
  43. package/dist/spa/src/afcl/Checkbox.vue +21 -13
  44. package/dist/spa/src/afcl/CountryFlag.vue +4 -1
  45. package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
  46. package/dist/spa/src/afcl/Dialog.vue +44 -27
  47. package/dist/spa/src/afcl/Dropzone.vue +12 -12
  48. package/dist/spa/src/afcl/Input.vue +9 -7
  49. package/dist/spa/src/afcl/JsonViewer.vue +25 -0
  50. package/dist/spa/src/afcl/Link.vue +1 -1
  51. package/dist/spa/src/afcl/LinkButton.vue +2 -2
  52. package/dist/spa/src/afcl/PieChart.vue +5 -5
  53. package/dist/spa/src/afcl/ProgressBar.vue +7 -7
  54. package/dist/spa/src/afcl/Select.vue +68 -34
  55. package/dist/spa/src/afcl/Skeleton.vue +6 -6
  56. package/dist/spa/src/afcl/Table.vue +130 -39
  57. package/dist/spa/src/afcl/Textarea.vue +31 -0
  58. package/dist/spa/src/afcl/Toggle.vue +32 -0
  59. package/dist/spa/src/afcl/Tooltip.vue +2 -3
  60. package/dist/spa/src/afcl/VerticalTabs.vue +3 -3
  61. package/dist/spa/src/afcl/index.ts +4 -3
  62. package/dist/spa/src/components/AcceptModal.vue +7 -7
  63. package/dist/spa/src/components/Breadcrumbs.vue +5 -5
  64. package/dist/spa/src/components/ColumnValueInput.vue +37 -18
  65. package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
  66. package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
  67. package/dist/spa/src/components/CustomRangePicker.vue +37 -8
  68. package/dist/spa/src/components/Filters.vue +83 -37
  69. package/dist/spa/src/components/GroupsTable.vue +9 -8
  70. package/dist/spa/src/components/MenuLink.vue +3 -3
  71. package/dist/spa/src/components/ResourceForm.vue +94 -51
  72. package/dist/spa/src/components/ResourceListTable.vue +78 -80
  73. package/dist/spa/src/components/ResourceListTableVirtual.vue +70 -72
  74. package/dist/spa/src/components/ShowTable.vue +17 -12
  75. package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
  76. package/dist/spa/src/components/SkeleteLoader.vue +3 -3
  77. package/dist/spa/src/components/ThreeDotsMenu.vue +73 -14
  78. package/dist/spa/src/components/Toast.vue +2 -7
  79. package/dist/spa/src/components/ValueRenderer.vue +43 -16
  80. package/dist/spa/src/controls/BoolToggle.vue +34 -0
  81. package/dist/spa/src/i18n.ts +1 -1
  82. package/dist/spa/src/shims-vue.d.ts +5 -0
  83. package/dist/spa/src/spa_types/core.ts +8 -1
  84. package/dist/spa/src/stores/core.ts +1 -1
  85. package/dist/spa/src/stores/modal.ts +6 -1
  86. package/dist/spa/src/types/Back.ts +93 -21
  87. package/dist/spa/src/types/Common.ts +44 -31
  88. package/dist/spa/src/types/FrontendAPI.ts +8 -0
  89. package/dist/spa/src/types/adapters/CompletionAdapter.ts +25 -0
  90. package/dist/spa/src/types/adapters/EmailAdapter.ts +27 -0
  91. package/dist/spa/src/types/adapters/ImageGenerationAdapter.ts +50 -0
  92. package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
  93. package/dist/spa/src/types/adapters/OAuth2Adapter.ts +34 -0
  94. package/dist/spa/src/types/adapters/StorageAdapter.ts +73 -0
  95. package/dist/spa/src/types/adapters/index.ts +6 -0
  96. package/dist/spa/src/utils.ts +217 -7
  97. package/dist/spa/src/views/CreateView.vue +18 -19
  98. package/dist/spa/src/views/EditView.vue +25 -19
  99. package/dist/spa/src/views/ListView.vue +117 -79
  100. package/dist/spa/src/views/LoginView.vue +34 -35
  101. package/dist/spa/src/views/ResourceParent.vue +1 -1
  102. package/dist/spa/src/views/ShowView.vue +59 -39
  103. package/dist/spa/src/websocket.ts +6 -1
  104. package/dist/spa/tsconfig.app.json +1 -1
  105. package/dist/spa/vite.config.ts +45 -2
  106. package/dist/types/Back.d.ts +69 -14
  107. package/dist/types/Back.d.ts.map +1 -1
  108. package/dist/types/Back.js +3 -0
  109. package/dist/types/Back.js.map +1 -1
  110. package/dist/types/Common.d.ts +37 -28
  111. package/dist/types/Common.d.ts.map +1 -1
  112. package/dist/types/Common.js.map +1 -1
  113. package/dist/types/FrontendAPI.d.ts +7 -0
  114. package/dist/types/FrontendAPI.d.ts.map +1 -1
  115. package/dist/types/FrontendAPI.js.map +1 -1
  116. package/dist/types/adapters/CompletionAdapter.d.ts +20 -0
  117. package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -0
  118. package/dist/types/adapters/CompletionAdapter.js +2 -0
  119. package/dist/types/adapters/CompletionAdapter.js.map +1 -0
  120. package/dist/types/adapters/EmailAdapter.d.ts +20 -0
  121. package/dist/types/adapters/EmailAdapter.d.ts.map +1 -0
  122. package/dist/types/adapters/EmailAdapter.js +2 -0
  123. package/dist/types/adapters/EmailAdapter.js.map +1 -0
  124. package/dist/types/adapters/ImageGenerationAdapter.d.ts +37 -0
  125. package/dist/types/adapters/ImageGenerationAdapter.d.ts.map +1 -0
  126. package/dist/types/adapters/ImageGenerationAdapter.js +2 -0
  127. package/dist/types/adapters/ImageGenerationAdapter.js.map +1 -0
  128. package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
  129. package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
  130. package/dist/types/adapters/ImageVisionAdapter.js +2 -0
  131. package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
  132. package/dist/types/adapters/OAuth2Adapter.d.ts +32 -0
  133. package/dist/types/adapters/OAuth2Adapter.d.ts.map +1 -0
  134. package/dist/types/adapters/OAuth2Adapter.js +2 -0
  135. package/dist/types/adapters/OAuth2Adapter.js.map +1 -0
  136. package/dist/types/adapters/StorageAdapter.d.ts +63 -0
  137. package/dist/types/adapters/StorageAdapter.d.ts.map +1 -0
  138. package/dist/types/adapters/StorageAdapter.js +2 -0
  139. package/dist/types/adapters/StorageAdapter.js.map +1 -0
  140. package/dist/types/adapters/index.d.ts +7 -0
  141. package/dist/types/adapters/index.d.ts.map +1 -0
  142. package/dist/types/adapters/index.js +2 -0
  143. package/dist/types/adapters/index.js.map +1 -0
  144. package/package.json +2 -2
  145. package/dist/spa/src/types/Adapters.ts +0 -213
  146. package/dist/types/Adapters.d.ts +0 -168
  147. package/dist/types/Adapters.d.ts.map +0 -1
  148. package/dist/types/Adapters.js +0 -2
  149. package/dist/types/Adapters.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
 
3
- <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
4
- <table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
5
- <thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
3
+ <div class="afcl-table-container relative overflow-x-auto shadow-md sm:rounded-lg">
4
+ <table class="afcl-table w-full text-sm text-left rtl:text-right text-lightTableText dark:text-darkTableText">
5
+ <thead class="afcl-table-thread text-xs text-lightTableHeadingText uppercase bg-lightTableHeadingBackground dark:bg-darkTableHeadingBackground dark:text-darkTableHeadingText">
6
6
  <tr>
7
- <th scope="col" class="px-6 py-3"
7
+ <th scope="col" class="px-6 py-3" ref="headerRefs"
8
8
  v-for="column in columns"
9
9
  >
10
10
  <slot v-if="$slots[`header:${column.fieldName}`]" :name="`header:${column.fieldName}`" :column="column" />
@@ -16,11 +16,20 @@
16
16
  </tr>
17
17
  </thead>
18
18
  <tbody>
19
+ <SkeleteLoader
20
+ v-if="isLoading"
21
+ :rows="pageSize"
22
+ :columns="columns.length"
23
+ :row-heights="rowHeights"
24
+ :column-widths="columnWidths"
25
+ />
19
26
  <tr
27
+ v-else="!isLoading"
20
28
  v-for="(item, index) in dataPage"
29
+ ref="rowRefs"
21
30
  :class="{
22
- 'odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800': evenHighlights,
23
- 'border-b dark:border-gray-700': index !== dataPage.length - 1 || totalPages > 1,
31
+ 'afcl-table-body odd:bg-lightTableOddBackground odd:dark:bg-darkTableOddBackground even:bg-lightTableEvenBackground even:dark:bg-darkTableEvenBackground': evenHighlights,
32
+ 'border-b border-lightTableBorder dark:border-darkTableBorder': index !== dataPage.length - 1 || totalPages > 1,
24
33
  }"
25
34
  >
26
35
  <td class="px-6 py-4"
@@ -31,40 +40,74 @@
31
40
  :item="item" :column="column"
32
41
  >
33
42
  </slot>
34
- <span v-else>
43
+ <span v-else-if="!isLoading" >
35
44
  {{ item[column.fieldName] }}
36
45
  </span>
46
+ <div v-else>
47
+ <div class=" w-full">
48
+ <Skeleton class="h-4" />
49
+ </div>
50
+ </div>
37
51
  </td>
38
52
  </tr>
39
53
  </tbody>
40
54
  </table>
41
- <nav class="flex items-center flex-column flex-wrap md:flex-row justify-between p-4"
55
+ <nav class="afcl-table-pagination-container bg-lightTableBackground dark:bg-darkTableBackground mt-2 flex flex-col gap-2 items-center sm:flex-row justify-center sm:justify-between px-4 pb-4"
42
56
  v-if="totalPages > 1"
43
57
  :aria-label="$t('Table navigation')">
44
- <i18n-t
45
- keypath="Showing {from} to {to} of {total}" tag="span" class="text-sm font-normal text-gray-500 dark:text-gray-400 mb-4 md:mb-0 block w-full md:inline md:w-auto"
46
- >
47
- <template #from><span class="font-semibold text-gray-900 dark:text-white">{{ Math.min((currentPage - 1) * props.pageSize + 1, props.data.length) }}</span></template>
48
- <template #to><span class="font-semibold text-gray-900 dark:text-white">{{ Math.min(currentPage * props.pageSize, props.data.length) }}</span></template>
49
- <template #total><span class="font-semibold text-gray-900 dark:text-white">{{ props.data.length }}</span></template>
50
- </i18n-t>
51
-
52
- <ul class="inline-flex -space-x-px rtl:space-x-reverse text-sm h-8">
53
- <li v-for="page in totalPages" :key="page">
54
- <a href="#"
55
- @click.prevent="switchPage(page)"
56
- :aria-current="page === page ? 'page' : undefined"
57
- :class='{
58
- "text-blue-600 bg-lightPrimary text-lightPrimaryContrast dark:bg-darkPrimary dark:text-darkPrimaryContrast hover:opacity-90": page === currentPage,
59
- "text-gray-500 border bg-white border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white": page !== currentPage,
60
- "rounded-s-lg ms-0": page === 1,
61
- "rounded-e-lg": page === totalPages,
62
- }'
63
- class="flex items-center justify-center px-3 h-8 leading-tight ">
64
- {{ page }}
65
- </a>
66
- </li>
67
- </ul>
58
+ <i18n-t
59
+ keypath="Showing {from} to {to} of {total}" tag="span" class="afcl-table-pagination-text text-sm font-normal text-center text-lightTablePaginationText dark:text-darkTablePaginationText sm:mb-4 md:mb-0 block w-full md:inline md:w-auto"
60
+ >
61
+ <template #from><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ Math.min((currentPage - 1) * props.pageSize + 1, dataResult.total) }}</span></template>
62
+ <template #to><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ Math.min(currentPage * props.pageSize, dataResult.total) }}</span></template>
63
+ <template #total><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ dataResult.total }}</span></template>
64
+ </i18n-t>
65
+ <div class="af-pagination-container flex flex-row items-center xs:flex-row xs:justify-between xs:items-center gap-3">
66
+ <div class="inline-flex">
67
+ <!-- Buttons -->
68
+ <button
69
+ class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightActivePaginationButtonText bg-lightActivePaginationButtonBackground border-r-0 rounded-s hover:opacity-90 dark:bg-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText disabled:opacity-50"
70
+ @click="currentPage--; pageInput = currentPage.toString();" :disabled="currentPage <= 1">
71
+ <svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
72
+ viewBox="0 0 14 10">
73
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
74
+ d="M13 5H1m0 0 4 4M1 5l4-4"/>
75
+ </svg>
76
+ </button>
77
+ <button
78
+ class="flex items-center py-1 px-3 text-sm font-medium text-lightUnactivePaginationButtonText focus:outline-none bg-lightUnactivePaginationButtonBackground border-r-0 border border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:text-darkUnactivePaginationButtonText dark:border-darkUnactivePaginationButtonBorder dark:hover:text-darkUnactivePaginationButtonHoverText dark:hover:bg-darkUnactivePaginationButtonHoverBackground disabled:opacity-50"
79
+ @click="switchPage(1); pageInput = currentPage.toString();" :disabled="currentPage <= 1">
80
+ <!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> -->
81
+ 1
82
+ </button>
83
+ <div
84
+ contenteditable="true"
85
+ class="min-w-10 outline-none inline-block w-auto py-1.5 px-3 text-sm text-center text-lightTablePaginationInputText border border-lightTablePaginationInputBorder bg-lightTablePaginationInputBackground dark:border-darkTablePaginationInputBorder dark:text-darkTablePaginationInputText dark:bg-darkTablePaginationInputBackground z-10"
86
+ @keydown="onPageKeydown($event)"
87
+ @input="onPageInput($event)"
88
+ @blur="validatePageInput()"
89
+ >
90
+ {{ pageInput }}
91
+ </div>
92
+
93
+ <button
94
+ class="flex items-center py-1 px-3 text-sm font-medium text-lightUnactivePaginationButtonText focus:outline-none bg-lightUnactivePaginationButtonBackground border-l-0 border border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:text-darkUnactivePaginationButtonText dark:border-darkUnactivePaginationButtonBorder dark:hover:text-darkUnactivePaginationButtonHoverText dark:hover:bg-darkUnactivePaginationButtonHoverBackground disabled:opacity-50"
95
+ @click="currentPage = totalPages; pageInput = currentPage.toString();" :disabled="currentPage >= totalPages">
96
+ {{ totalPages }}
97
+
98
+ <!-- <IconChevronDoubleRightOutline class="w-4 h-4" /> -->
99
+ </button>
100
+ <button
101
+ class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightActivePaginationButtonText focus:outline-none bg-lightActivePaginationButtonBackground border-l-0 rounded-e hover:opacity-90 dark:bg-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText disabled:opacity-50"
102
+ @click="currentPage++; pageInput = currentPage.toString();" :disabled="currentPage >= totalPages">
103
+ <svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
104
+ viewBox="0 0 14 10">
105
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
106
+ d="M1 5h12m0 0L9 1m4 4L9 9"/>
107
+ </svg>
108
+ </button>
109
+ </div>
110
+ </div>
68
111
  </nav>
69
112
  </div>
70
113
 
@@ -73,7 +116,9 @@
73
116
  </template>
74
117
 
75
118
  <script setup lang="ts">
76
- import { ref, type Ref, computed } from 'vue';
119
+ import { ref, type Ref, computed, useTemplateRef, watch, nextTick } from 'vue';
120
+ import { asyncComputed } from '@vueuse/core';
121
+ import SkeleteLoader from '@/components/SkeleteLoader.vue';
77
122
 
78
123
  const props = withDefaults(
79
124
  defineProps<{
@@ -83,7 +128,7 @@
83
128
  }[],
84
129
  data: {
85
130
  [key: string]: any,
86
- }[],
131
+ }[] | ((offset: number, limit: number) => Promise<{data: {[key: string]: any}[], total: number}>),
87
132
  evenHighlights?: boolean,
88
133
  pageSize?: number,
89
134
  }>(), {
@@ -93,15 +138,38 @@
93
138
  );
94
139
 
95
140
  const currentPage = ref(1);
141
+ const isLoading = ref(false);
142
+ const pageInput = ref('1');
143
+ const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
144
+ const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
145
+ const rowHeights = ref<number[]>([]);
146
+ const columnWidths = ref<number[]>([]);
147
+
148
+ const dataResult = asyncComputed( async() => {
149
+ if (typeof props.data === 'function') {
150
+ isLoading.value = true;
151
+ const result = await props.data(currentPage.value, props.pageSize);
152
+ isLoading.value = false;
153
+ return result;
154
+ }
155
+ const start = (currentPage.value - 1) * props.pageSize;
156
+ const end = start + props.pageSize;
157
+ return { data: props.data.slice(start, end), total: props.data.length };
158
+ });
159
+
160
+ watch(() => currentPage.value, () => {
161
+ // rows are set to null when new records are loading
162
+ rowHeights.value = !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
163
+ columnWidths.value = !headerRefs.value ? [] : headerRefs.value.map((el: HTMLElement) => el.offsetWidth);
164
+ });
165
+
96
166
 
97
167
  const totalPages = computed(() => {
98
- return Math.ceil(props.data.length / props.pageSize);
168
+ return dataResult.value?.total ? Math.ceil(dataResult.value.total / props.pageSize) : 1;
99
169
  });
100
170
 
101
- const dataPage = computed(() => {
102
- const start = (currentPage.value - 1) * props.pageSize;
103
- const end = start + props.pageSize;
104
- return props.data.slice(start, end);
171
+ const dataPage = asyncComputed( async() => {
172
+ return dataResult.value.data;
105
173
  });
106
174
 
107
175
  function switchPage(p: number) {
@@ -112,5 +180,28 @@
112
180
  'update:activeTab',
113
181
  ]);
114
182
 
183
+ function onPageInput(event: any) {
184
+ pageInput.value = event.target.innerText;
185
+ }
186
+
187
+ function validatePageInput() {
188
+ const newPage = parseInt(pageInput.value) || 1;
189
+ const validPage = Math.max(1, Math.min(newPage, totalPages.value));
190
+ currentPage.value = validPage;
191
+ pageInput.value = validPage.toString();
192
+ }
193
+
194
+ async function onPageKeydown(event: any) {
195
+ // page input should accept only numbers, arrow keys and backspace
196
+ if (['Enter', 'Space'].includes(event.code) ||
197
+ (!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
198
+ && isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
199
+ event.preventDefault();
200
+ if (event.code === 'Enter') {
201
+ validatePageInput();
202
+ event.target.blur();
203
+ }
204
+ }
205
+ }
115
206
 
116
207
  </script>
@@ -0,0 +1,31 @@
1
+ <template>
2
+
3
+ <textarea
4
+ ref="input"
5
+ class="bg-lightInputBackground border border-lightInputBorder text-lightInputText placeholder-lightInputPlaceholderText text-sm rounded-lg block w-full p-2.5 dark:bg-darkInputBackground dark:border-darkInputBorder dark:placeholder-darkInputPlaceholderText dark:text-darkInputText dark:border-darkInputBorder focus:ring-lightInputFocusRing focus:border-lightInputFocusBorder dark:focus:ring-darkInputFocusRing dark:focus:border-darkInputFocusBorder"
6
+ :placeholder="placeholder"
7
+ :value="modelValue"
8
+ @input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
9
+ :readonly="readonly"
10
+ />
11
+
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+
16
+ import { ref } from 'vue';
17
+
18
+ const props = defineProps<{
19
+ modelValue: string,
20
+ readonly?: boolean,
21
+ placeholder?: string,
22
+ }>()
23
+
24
+ const input = ref<HTMLInputElement | null>(null)
25
+
26
+ defineExpose({
27
+ focus: () => input.value?.focus(),
28
+ });
29
+
30
+ </script>
31
+
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <label class="inline-flex items-center cursor-pointer bor" :class="{'opacity-50' : props.disabled}">
3
+ <input :id="id"
4
+ type="checkbox"
5
+ value="" class="sr-only peer"
6
+ :disabled="props.disabled"
7
+ :checked="props.modelValue"
8
+ @change="$emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
9
+ >
10
+ <div class="afcl-toggle border border-lightToggleBorderUnactive relative min-w-11 min-h-6 bg-lightToggleBgUnactive peer-focus:outline-none peer-focus:ring-4
11
+ peer-focus:ring-lightToggleRing dark:peer-focus:ring-darkToggleRing rounded-full peer dark:bg-darkToggleBgUnactive
12
+ peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:top-[2px] peer-checked:border-none
13
+ peer-checked:after:border-lightToggleBorderActive after:content-[''] after:absolute after:top-[1px]
14
+ after:start-[2px] after:bg-lightToggleCircleUnactive peer-checked:after:bg-lightToggleCircleActive dark:after:bg-darkToggleCircleUnactive after:border-lightToggleBgUnactive dark:after:border-darkToggleBgUnactive after:border after:rounded-full
15
+ after:h-5 after:w-5 after:transition-all dark:border-darkToggleBorderUnactive peer-checked:bg-lightToggleBgActive
16
+ dark:peer-checked:bg-darkToggleBgActive dark:peer-checked:after:border-darkToggleBorderActive dark:peer-checked:after:bg-darkToggleCircleActive">
17
+ </div>
18
+ <label :for="id" class="cursor-pointer ms-3 text-sm font-medium text-lightToggleText dark:text-darkToggleText">
19
+ <slot></slot>
20
+ </label>
21
+ </label>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ const props = defineProps({
26
+ modelValue: Boolean,
27
+ disabled: Boolean,
28
+ });
29
+
30
+ defineEmits(['update:modelValue']);
31
+ const id = `afcb-${Math.random().toString(36).substring(7)}`
32
+ </script>
@@ -1,16 +1,15 @@
1
1
  <template>
2
- <div ref="triggerEl" class="inline-flex items-center">
2
+ <div ref="triggerEl" class="afcl-tooltip inline-flex items-center">
3
3
  <slot></slot>
4
4
  </div>
5
5
  <div
6
6
  role="tooltip"
7
- class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700"
7
+ class="absolute z-20 invisible inline-block px-3 py-2 text-sm font-medium text-lightTooltipText dark:darkTooltipText transition-opacity duration-300 bg-lightTooltipBackground rounded-lg shadow-sm opacity-0 tooltip dark:bg-darkTooltipBackground"
8
8
  ref="tooltip"
9
9
  >
10
10
  <slot name="tooltip"></slot>
11
11
  <div class="tooltip-arrow" data-popper-arrow></div>
12
12
  </div>
13
-
14
13
  </template>
15
14
 
16
15
  <script setup lang="ts">
@@ -1,19 +1,19 @@
1
1
  <template>
2
2
  <div class="md:flex">
3
- <ul class="flex-column space-y space-y-4 text-sm font-medium text-gray-500 dark:text-gray-400 md:me-4 mb-4 md:mb-0">
3
+ <ul class="flex-column space-y space-y-4 text-sm font-medium text-lightVerticalTabsText dark:text-darkVerticalTabsText md:me-4 mb-4 md:mb-0">
4
4
  <li v-for="tab in tabs" :key="`${tab}-tab-controll`">
5
5
  <a
6
6
  href="#"
7
7
  @click="activeTab = tab"
8
8
  class="inline-flex items-center px-4 py-3 rounded-lg w-full"
9
- :class="tab === activeTab ? 'text-lightPrimaryContrast bg-lightPrimary active dark:bg-darkPrimary' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:hover:text-white'"
9
+ :class="tab === activeTab ? 'text-lightVerticalTabsTextActive bg-lightVerticalTabsBackgroundActive active dark:bg-darkVerticalTabsBackgroundActive dark:text-darkVerticalTabsTextActive' : 'text-lightVerticalTabsText dark:text-darkVerticalTabsText hover:text-lightVerticalTabsTextHover bg-lightVerticalTabsBackground hover:bg-lightVerticalTabsBackgroundHover dark:bg-darkVerticalTabsBackground dark:hover:bg-darkVerticalTabsBackgroundHover dark:hover:darkVerticalTabsTextHover'"
10
10
  aria-current="page"
11
11
  >
12
12
  <slot :name="`tab:${tab}`"></slot>
13
13
  </a>
14
14
  </li>
15
15
  </ul>
16
- <div class="ps-6 text-medium text-gray-500 dark:text-gray-400 w-full ">
16
+ <div class="ps-6 text-medium text-lightVerticalTabsSlotText dark:text-darkVerticalTabsSlotText w-full ">
17
17
  <slot :name="activeTab"></slot>
18
18
  </div>
19
19
  </div>
@@ -19,6 +19,7 @@ export { default as Skeleton } from './Skeleton.vue';
19
19
  export { default as Dialog } from './Dialog.vue';
20
20
  export { default as MixedChart } from './MixedChart.vue';
21
21
  export { default as CountryFlag } from './CountryFlag.vue';
22
-
23
-
24
-
22
+ export { default as JsonViewer } from './JsonViewer.vue';
23
+ export { default as Toggle } from './Toggle.vue';
24
+ export { default as DatePicker } from './DatePicker.vue';
25
+ export { default as Textarea } from './Textarea.vue';
@@ -6,24 +6,24 @@ const modalStore = useModalStore();
6
6
 
7
7
  <template>
8
8
  <Teleport to="body">
9
- <div v-if="modalStore.isOpened" class="bg-gray-900/50 dark:bg-gray-900/80 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-full max-h-full">
9
+ <div v-if="modalStore.isOpened" class="bg-gray-900/50 dark:bg-gray-900/80 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-[100] justify-center items-center w-full md:inset-0 h-full max-h-full">
10
10
  <div class="relative p-4 w-full max-w-md max-h-full top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 " >
11
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black">
12
- <button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
11
+ <div class="afcl-confirmation-container relative bg-lightAcceptModalBackground rounded-lg shadow dark:bg-darkAcceptModalBackground dark:shadow-black">
12
+ <button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-lightAcceptModalCloseIcon bg-transparent hover:bg-lightAcceptModalCloseIconHoverBackground hover:text-lightAcceptModalCloseIconHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkAcceptModalCloseIcon dark:hover:bg-darkAcceptModalCloseIconHoverBackground dark:hover:text-darkAcceptModalCloseIconHover" >
13
13
  <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
14
14
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
15
15
  </svg>
16
16
  <span class="sr-only">{{ $t('Close modal') }}</span>
17
17
  </button>
18
18
  <div class="p-4 md:p-5 text-center">
19
- <svg class="mx-auto mb-4 text-gray-400 w-12 h-12 dark:text-gray-200" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
19
+ <svg class="mx-auto mb-4 text-lightAcceptModalWarningIcon w-12 h-12 dark:text-darkAcceptModalWarningIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
20
20
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
21
21
  </svg>
22
- <h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">{{ modalStore?.modalContent?.content }}</h3>
23
- <button @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" type="button" class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center">
22
+ <h3 class="afcl-confirmation-title mb-5 text-lg font-normal text-lightAcceptModalText dark:text-darkAcceptModalText">{{ modalStore?.modalContent?.content }}</h3>
23
+ <button @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" type="button" class="afcl-confirmation-accept-button text-lightAcceptModalConfirmButtonText bg-lightAcceptModalConfirmButtonBackground hover:bg-lightAcceptModalConfirmButtonBackgroundHover focus:ring-4 focus:outline-none focus:ring-lightAcceptModalConfirmButtonFocus font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center dark:text-darkAcceptModalConfirmButtonText dark:bg-darkAcceptModalConfirmButtonBackground dark:hover:bg-darkAcceptModalConfirmButtonBackgroundHover dark:focus:ring-darkAcceptModalConfirmButtonFocus">
24
24
  {{ modalStore?.modalContent?.acceptText }}
25
25
  </button>
26
- <button @click="()=>{modalStore.onAcceptFunction(false);modalStore.togleModal()}" type="button" class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700">{{ modalStore?.modalContent?.cancelText }}</button>
26
+ <button @click="()=>{modalStore.onAcceptFunction(false);modalStore.togleModal()}" type="button" class="afcl-confirmation-cancel-button py-2.5 px-5 ms-3 text-sm font-medium text-lightAcceptModalCancelButtonText focus:outline-none bg-lightAcceptModalCancelButtonBackground rounded-lg border border-lightAcceptModalCancelButtonBorder hover:bg-lightAcceptModalCancelButtonBackgroundHover hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-lightAcceptModalCancelButtonFocus dark:focus:ring-darkAcceptModalCancelButtonFocus dark:bg-darkAcceptModalCancelButtonBackground dark:text-darkAcceptModalCancelButtonText dark:border-darkAcceptModalCancelButtonBorder dark:hover:text-darkAcceptModalCancelButtonTextHover dark:hover:bg-darkAcceptModalCancelButtonBackgroundHover">{{ modalStore?.modalContent?.cancelText }}</button>
27
27
  </div>
28
28
  </div>
29
29
  </div>
@@ -2,7 +2,7 @@
2
2
  <nav class="flex" aria-label="Breadcrumb">
3
3
  <ol class="inline-flex items-center space-x-1 md:space-x-2 rtl:space-x-reverse flex-wrap">
4
4
  <li class="inline-flex items-center">
5
- <RouterLink :to="{name: 'home'}" class="inline-flex items-center text-sm font-medium text-gray-700 hover:text-lightPrimary dark:text-gray-400 dark:hover:text-white">
5
+ <RouterLink :to="{name: 'home'}" class="inline-flex items-center text-sm font-medium text-lightBreadcrumbsHomepageText hover:text-lightBreadcrumbsHomepageTextHover dark:text-darkBreadcrumbsHomepageText dark:hover:text-darkBreadcrumbsHomepageTextHover">
6
6
  <svg class="w-3 h-3 me-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
7
7
  <path d="m19.707 9.293-2-2-7-7a1 1 0 0 0-1.414 0l-7 7-2 2a1 1 0 0 0 1.414 1.414L2 10.414V18a2 2 0 0 0 2 2h3a1 1 0 0 0 1-1v-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v4a1 1 0 0 0 1 1h3a2 2 0 0 0 2-2v-7.586l.293.293a1 1 0 0 0 1.414-1.414Z"/>
8
8
  </svg>
@@ -11,19 +11,19 @@
11
11
  </li>
12
12
  <li>
13
13
  <div class="flex items-center">
14
- <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
14
+ <svg class="rtl:rotate-180 w-3 h-3 text-lightBreadcrumbsArrowIcon dark:text-darkBreadcrumbsArrowIcon mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
15
15
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
16
16
  </svg>
17
- <RouterLink :to="{name: 'resource-list', params: { resourceId: $route.params.resourceId }}" class="text-sm font-medium text-gray-500 md:ms-2 dark:text-gray-400">{{ coreStore.resourceById[$route.params.resourceId]?.label }}</RouterLink>
17
+ <RouterLink :to="{name: 'resource-list', params: { resourceId: $route.params.resourceId }}" class="text-sm font-medium text-lightBreadcrumbsText md:ms-2 dark:text-darkBreadcrumbsText">{{ coreStore.resourceById[$route.params.resourceId]?.label }}</RouterLink>
18
18
  </div>
19
19
  </li>
20
20
 
21
21
  <li v-if="$route.params.primaryKey">
22
22
  <div class="flex items-center">
23
- <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
23
+ <svg class="rtl:rotate-180 w-3 h-3 text-lightBreadcrumbsArrowIcon dark:text-darkBreadcrumbsArrowIcon mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
24
24
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
25
25
  </svg>
26
- <span class="ms-1 text-sm font-medium text-gray-500 md:ms-2 dark:text-gray-400
26
+ <span class="ms-1 text-sm font-medium text-lightBreadcrumbsText md:ms-2 dark:text-darkBreadcrumbsText
27
27
  max-w-80 truncate">
28
28
  {{ $route.name === 'resource-edit' ? $t('Edit') : $t('Show') }} {{ coreStore.record?._label }}</span>
29
29
  </div>
@@ -19,12 +19,26 @@
19
19
  ref="input"
20
20
  class="w-full min-w-24"
21
21
  :options="columnOptions[column.name] || []"
22
+ :searchDisabled="!column.foreignResource.searchableFields"
23
+ @scroll-near-end="loadMoreOptions && loadMoreOptions(column.name)"
24
+ @search="(searchTerm) => {
25
+ if (column.foreignResource.searchableFields && onSearchInput && onSearchInput[column.name]) {
26
+ onSearchInput[column.name](searchTerm);
27
+ }
28
+ }"
22
29
  teleportToBody
23
30
  :placeholder = "columnOptions[column.name]?.length ?$t('Select...'): $t('There are no options available')"
24
31
  :modelValue="value"
25
32
  :readonly="(column.editReadonly && source === 'edit') || readonly"
26
33
  @update:modelValue="$emit('update:modelValue', $event)"
27
- />
34
+ >
35
+ <template #extra-item v-if="columnLoadingState && columnLoadingState[column.name]?.loading">
36
+ <div class="text-center text-gray-400 dark:text-gray-300 py-2 flex items-center justify-center gap-2">
37
+ <Spinner class="w-4 h-4" />
38
+ {{ $t('Loading...') }}
39
+ </div>
40
+ </template>
41
+ </Select>
28
42
  <Select
29
43
  v-else-if="column.enum"
30
44
  ref="input"
@@ -52,6 +66,7 @@
52
66
  step="1"
53
67
  class="w-40"
54
68
  placeholder="0"
69
+ :fullWidth="true"
55
70
  :min="![undefined, null].includes(column.minValue) ? column.minValue : ''"
56
71
  :max="![undefined, null].includes(column.maxValue) ? column.maxValue : ''"
57
72
  :prefix="column.inputPrefix"
@@ -60,7 +75,7 @@
60
75
  :modelValue="value"
61
76
  @update:modelValue="$emit('update:modelValue', $event)"
62
77
  />
63
- <CustomDatePicker
78
+ <DatePicker
64
79
  v-else-if="['datetime', 'date', 'time'].includes(type || column.type)"
65
80
  ref="input"
66
81
  :column="column"
@@ -76,6 +91,7 @@
76
91
  step="0.1"
77
92
  class="w-40"
78
93
  placeholder="0.0"
94
+ :fullWidth="true"
79
95
  :min="![undefined, null].includes(column.minValue) ? column.minValue : ''"
80
96
  :max="![undefined, null].includes(column.maxValue) ? column.maxValue : ''"
81
97
  :prefix="column.inputPrefix"
@@ -84,28 +100,25 @@
84
100
  @update:modelValue="$emit('update:modelValue', $event)"
85
101
  :readonly="(column.editReadonly && source === 'edit') || readonly"
86
102
  />
87
- <textarea
103
+ <Textarea
88
104
  v-else-if="['text', 'richtext'].includes(type || column.type)"
89
- ref="input"
90
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
91
105
  :placeholder="$t('Text')"
92
- :value="value"
93
- @input="$emit('update:modelValue', $event.target.value)"
106
+ :modelValue="value"
107
+ @update:modelValue="$emit('update:modelValue', $event)"
94
108
  :readonly="(column.editReadonly && source === 'edit') || readonly"
95
109
  />
96
- <textarea
110
+ <Textarea
97
111
  v-else-if="['json'].includes(type || column.type)"
98
- ref="input"
99
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
100
112
  :placeholder="$t('Text')"
101
- :value="value"
102
- @input="$emit('update:modelValue', $event.target.value)"
113
+ :modelValue="value"
114
+ @update:modelValue="$emit('update:modelValue', $event)"
103
115
  />
104
116
  <Input
105
117
  v-else
106
118
  ref="input"
107
119
  :type="!column.masked || unmasked[column.name] ? 'text' : 'password'"
108
120
  class="w-full"
121
+ :fullWidth="true"
109
122
  :placeholder="$t('Text')"
110
123
  :prefix="column.inputPrefix"
111
124
  :suffix="column.inputSuffix"
@@ -123,7 +136,7 @@
123
136
  class="h-6 inset-y-2 right-0 flex items-center px-2 pt-4 z-index-100 focus:outline-none"
124
137
  @click="$emit('delete')"
125
138
  >
126
- <IconTrashBinSolid class="w-6 h-6 text-gray-400"/>
139
+ <IconTrashBinSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons"/>
127
140
  </button>
128
141
  <button
129
142
  v-else-if="column.masked"
@@ -131,18 +144,20 @@
131
144
  @click="$emit('update:unmasked')"
132
145
  class="h-6 inset-y-2 right-0 flex items-center px-2 pt-4 z-index-100 focus:outline-none"
133
146
  >
134
- <IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]"/>
135
- <IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
147
+ <IconEyeSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons" v-if="!unmasked[column.name]"/>
148
+ <IconEyeSlashSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons" v-else />
136
149
  </button>
137
150
  </div>
138
151
  </template>
139
152
 
140
153
  <script setup lang="ts">
141
154
  import { IconEyeSlashSolid, IconEyeSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
142
- import CustomDatePicker from "@/components/CustomDatePicker.vue";
155
+ import DatePicker from "@/afcl/DatePicker.vue";
143
156
  import Select from '@/afcl/Select.vue';
144
157
  import Input from '@/afcl/Input.vue';
145
- import { ref } from 'vue';
158
+ import Spinner from '@/afcl/Spinner.vue';
159
+ import Textarea from '@/afcl/Textarea.vue';
160
+ import { ref, inject } from 'vue';
146
161
  import { getCustomComponent } from '@/utils';
147
162
  import { useI18n } from 'vue-i18n';
148
163
  import { useCoreStore } from '@/stores/core';
@@ -171,7 +186,11 @@
171
186
  }
172
187
  );
173
188
 
174
- const input = ref(null);
189
+ const columnLoadingState = inject('columnLoadingState', {} as any);
190
+ const onSearchInput = inject('onSearchInput', {} as any);
191
+ const loadMoreOptions = inject('loadMoreOptions', (() => {}) as any);
192
+
193
+ const input = ref<HTMLInputElement | null>(null);
175
194
 
176
195
  const getBooleanOptions = (column: any) => {
177
196
  const options: Array<{ label: string; value: boolean | null }> = [
@@ -13,12 +13,13 @@
13
13
  :currentValues="currentValues"
14
14
  :mode="mode"
15
15
  :columnOptions="columnOptions"
16
+ :unmasked="unmasked"
16
17
  :deletable="!column.editReadonly"
17
18
  @update:modelValue="setCurrentValue(column.name, $event, arrayItemIndex)"
18
19
  @update:unmasked="$emit('update:unmasked', column.name)"
19
20
  @update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
20
21
  @update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"
21
- @delete="setCurrentValue(column.name, currentValues[column.name].filter((_, index) => index !== arrayItemIndex))"
22
+ @delete="setCurrentValue(column.name, currentValues[column.name].filter((_: any, index: any) => index !== arrayItemIndex))"
22
23
  />
23
24
  </div>
24
25
  <div class="flex items-center">
@@ -26,7 +27,7 @@
26
27
  v-if="!column.editReadonly"
27
28
  type="button"
28
29
  @click="addArrayItem"
29
- class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
30
+ class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-lightInputText focus:outline-none bg-lightInputBackground rounded border border-lightInputBorder hover:bg-lightInputBackgroundHover hover:text-lightInputTextHover hover:border-lightInputBorderHover focus:z-10 focus:ring-4 focus:ring-lightInputFocusRing dark:focus:ring-darkInputFocusRing dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:darkInputTextHover dark:hover:bg-darkInputHover"
30
31
  :class="{'mt-2': currentValues[column.name].length}"
31
32
  >
32
33
  <IconPlusOutline class="w-4 h-4 me-2"/>
@@ -70,7 +71,7 @@
70
71
 
71
72
  const emit = defineEmits(['update:unmasked', 'update:inValidity', 'update:emptiness', 'focus-last-input']);
72
73
 
73
- const arrayItemRefs = ref([]);
74
+ const arrayItemRefs = ref<HTMLInputElement[]>([]);
74
75
 
75
76
  async function addArrayItem() {
76
77
  props.setCurrentValue(props.column.name, props.currentValues[props.column.name], props.currentValues[props.column.name].length);