adminforth 2.4.0-next.1 → 2.4.0-next.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/callTsProxy.js +14 -4
- package/commands/cli.js +12 -4
- package/commands/createApp/templates/.env.local.hbs +2 -2
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +9 -5
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/utils.js +40 -7
- package/commands/createCustomComponent/configLoader.js +3 -0
- package/commands/createCustomComponent/configUpdater.js +25 -21
- package/commands/createCustomComponent/fileGenerator.js +1 -1
- package/commands/createCustomComponent/main.js +2 -1
- package/commands/createCustomComponent/templates/login/beforeLogin.vue.hbs +18 -0
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +16 -3
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +14 -14
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -9
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +25 -9
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +50 -2
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +145 -25
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +451 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +507 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +1 -0
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +9 -0
- package/dist/modules/utils.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/src/App.vue +24 -14
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +6 -6
- package/dist/spa/src/afcl/Dropzone.vue +13 -11
- package/dist/spa/src/afcl/Input.vue +9 -7
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/Link.vue +1 -1
- package/dist/spa/src/afcl/LinkButton.vue +1 -1
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +52 -23
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +13 -13
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +2 -2
- package/dist/spa/src/afcl/VerticalTabs.vue +3 -3
- package/dist/spa/src/afcl/index.ts +4 -3
- package/dist/spa/src/components/AcceptModal.vue +6 -6
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/ColumnValueInput.vue +37 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -8
- package/dist/spa/src/components/Filters.vue +76 -31
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +38 -40
- package/dist/spa/src/components/ResourceListTableVirtual.vue +31 -33
- package/dist/spa/src/components/ShowTable.vue +17 -12
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +1 -1
- package/dist/spa/src/components/ThreeDotsMenu.vue +34 -7
- package/dist/spa/src/components/Toast.vue +2 -7
- package/dist/spa/src/components/ValueRenderer.vue +4 -4
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- 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 +7 -0
- package/dist/spa/src/stores/core.ts +1 -1
- package/dist/spa/src/types/Back.ts +84 -21
- package/dist/spa/src/types/Common.ts +26 -10
- package/dist/spa/src/types/adapters/CompletionAdapter.ts +25 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +27 -0
- package/dist/spa/src/types/adapters/ImageGenerationAdapter.ts +50 -0
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/OAuth2Adapter.ts +34 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +73 -0
- package/dist/spa/src/types/adapters/index.ts +6 -0
- package/dist/spa/src/utils.ts +217 -7
- package/dist/spa/src/views/CreateView.vue +21 -16
- package/dist/spa/src/views/EditView.vue +29 -19
- package/dist/spa/src/views/ListView.vue +51 -49
- package/dist/spa/src/views/LoginView.vue +57 -45
- package/dist/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/src/views/ShowView.vue +17 -13
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +44 -1
- package/dist/types/Back.d.ts +63 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +24 -8
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/adapters/CompletionAdapter.d.ts +20 -0
- package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CompletionAdapter.js +2 -0
- package/dist/types/adapters/CompletionAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +20 -0
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -0
- package/dist/types/adapters/EmailAdapter.js +2 -0
- package/dist/types/adapters/EmailAdapter.js.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts +37 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.js +2 -0
- package/dist/types/adapters/ImageGenerationAdapter.js.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts +32 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.js +2 -0
- package/dist/types/adapters/OAuth2Adapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +63 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -0
- package/dist/types/adapters/StorageAdapter.js +2 -0
- package/dist/types/adapters/StorageAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +7 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/index.js +2 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/package.json +2 -2
- package/dist/spa/src/types/Adapters.ts +0 -213
- package/dist/types/Adapters.d.ts +0 -168
- package/dist/types/Adapters.d.ts.map +0 -1
- package/dist/types/Adapters.js +0 -2
- package/dist/types/Adapters.js.map +0 -1
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="relative inline-block
|
|
2
|
+
<div class="afcl-select afcl-select-wrapper relative inline-block" ref="internalSelect"
|
|
3
3
|
:class="{'opacity-50': readonly}"
|
|
4
4
|
>
|
|
5
5
|
<div class="relative">
|
|
6
6
|
<input
|
|
7
7
|
ref="inputEl"
|
|
8
8
|
type="text"
|
|
9
|
-
:readonly="readonly"
|
|
9
|
+
:readonly="readonly || searchDisabled"
|
|
10
10
|
v-model="search"
|
|
11
11
|
@click="inputClick"
|
|
12
12
|
@input="inputInput"
|
|
13
|
-
class="block w-full pl-3 pr-10 py-2.5 border border-
|
|
13
|
+
class="block w-full pl-3 pr-10 py-2.5 border border-lightDropownButtonsBorder rounded-md leading-5 bg-lightDropdownButtonsBackground
|
|
14
|
+
placeholder-lightDropdownButtonsPlaceholderText text-lightDropdownButtonsText sm:text-sm transition duration-150 ease-in-out dark:bg-darkDropdownButtonsBackground dark:border-darkDropdownButtonsBorder dark:placeholder-darkDropdownButtonsPlaceholderText
|
|
15
|
+
dark:text-darkDropdownButtonsText focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
|
|
14
16
|
autocomplete="off" data-custom="no-autofill"
|
|
15
17
|
:placeholder="
|
|
16
18
|
selectedItems.length && !multiple ? '' : (showDropdown ? $t('Search') : placeholder || $t('Select...'))
|
|
17
19
|
"
|
|
18
20
|
/>
|
|
19
21
|
|
|
20
|
-
<div v-if="!multiple && selectedItems.length" class="absolute pointer-events-none inset-y-0 left-2 flex items-center pr-2 px-1">
|
|
22
|
+
<div v-if="!multiple && selectedItems.length" class="text-lightDropdownButtonsText dark:text-darkDropdownButtonsText absolute pointer-events-none inset-y-0 left-2 flex items-center pr-2 px-1">
|
|
21
23
|
<slot
|
|
22
24
|
name="selected-item"
|
|
23
25
|
:option="selectedItems[0]"
|
|
24
26
|
></slot>
|
|
25
|
-
<span v-if="!$slots['selected-item']" class="text-
|
|
27
|
+
<span v-if="!$slots['selected-item']" class="text-lightDropdownButtonsText dark:text-darkDropdownButtonsText font-medium ">
|
|
26
28
|
{{ selectedItems[0]?.label }}
|
|
27
29
|
</span>
|
|
28
30
|
</div>
|
|
29
31
|
|
|
30
32
|
<div class="absolute inset-y-0 right-2 flex items-center pointer-events-none">
|
|
31
33
|
<!-- triangle icon -->
|
|
32
|
-
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-
|
|
34
|
+
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-darkPrimary opacity-50 transition duration-150 ease-in"
|
|
33
35
|
:class="{ 'transform rotate-180': showDropdown }"
|
|
34
36
|
/>
|
|
35
37
|
</div>
|
|
@@ -37,18 +39,19 @@
|
|
|
37
39
|
<teleport to="body" v-if="teleportToBody && showDropdown">
|
|
38
40
|
<div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop}"
|
|
39
41
|
class="fixed z-[5] w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700
|
|
40
|
-
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
42
|
+
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
43
|
+
@scroll="handleDropdownScroll">
|
|
41
44
|
<div
|
|
42
45
|
v-for="item in filteredItems"
|
|
43
46
|
:key="item.value"
|
|
44
|
-
class="px-4 py-2 cursor-pointer hover:bg-
|
|
45
|
-
:class="{ 'bg-
|
|
47
|
+
class="px-4 py-2 cursor-pointer hover:bg-lightDropdownOptionsHoverBackground dark:hover:bg-darkDropdownOptionsHoverBackground text-lightDropdownOptionsText dark:text-darkDropdownOptionsText"
|
|
48
|
+
:class="{ 'bg-lightDropdownPicked dark:bg-darkDropdownPicked': selectedItems.includes(item) }"
|
|
46
49
|
@click="toogleItem(item)"
|
|
47
50
|
>
|
|
48
51
|
<slot name="item" :option="item"></slot>
|
|
49
52
|
<label v-if="!$slots.item" :for="item.value">{{ item.label }}</label>
|
|
50
53
|
</div>
|
|
51
|
-
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-
|
|
54
|
+
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText dark:text-darkDropdownOptionsText">
|
|
52
55
|
{{ options.length ? $t('No results found') : $t('No items here') }}
|
|
53
56
|
</div>
|
|
54
57
|
|
|
@@ -59,23 +62,23 @@
|
|
|
59
62
|
</teleport>
|
|
60
63
|
|
|
61
64
|
<div v-if="!teleportToBody && showDropdown" ref="dropdownEl" :style="dropdownStyle" :class="{'shadow-none': isTop}"
|
|
62
|
-
class="absolute z-10 mt-1 w-full bg-
|
|
63
|
-
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
65
|
+
class="absolute z-10 mt-1 w-full bg-lightDropdownOptionsBackground shadow-lg text-lightDropdownButtonsText dark:shadow-black dark:bg-darkDropdownOptionsBackground
|
|
66
|
+
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
67
|
+
@scroll="handleDropdownScroll">
|
|
64
68
|
<div
|
|
65
69
|
v-for="item in filteredItems"
|
|
66
70
|
:key="item.value"
|
|
67
|
-
class="px-4 py-2 cursor-pointer hover:bg-
|
|
68
|
-
:class="{ 'bg-
|
|
71
|
+
class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText hover:bg-lightDropdownOptionsHoverBackground dark:hover:bg-darkDropdownOptionsHoverBackground dark:text-darkDropdownOptionsText"
|
|
72
|
+
:class="{ 'bg-lightDropdownPicked dark:bg-darkDropdownPicked': selectedItems.includes(item) }"
|
|
69
73
|
@click="toogleItem(item)"
|
|
70
74
|
>
|
|
71
75
|
<slot name="item" :option="item"></slot>
|
|
72
76
|
<label v-if="!$slots.item" :for="item.value">{{ item.label }}</label>
|
|
73
77
|
</div>
|
|
74
|
-
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-
|
|
78
|
+
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText dark:text-darkDropdownOptionsText">
|
|
75
79
|
{{ options.length ? $t('No results found') : $t('No items here') }}
|
|
76
80
|
</div>
|
|
77
|
-
|
|
78
|
-
<div v-if="$slots['extra-item']" class="px-4 py-2 dark:text-gray-400">
|
|
81
|
+
<div v-if="$slots['extra-item']" class="px-4 py-2 dark:text-darkDropdownOptionsText">
|
|
79
82
|
<slot name="extra-item"></slot>
|
|
80
83
|
</div>
|
|
81
84
|
|
|
@@ -87,12 +90,12 @@
|
|
|
87
90
|
<template v-for="item in selectedItems" :key="`afcl-select-${item.value}`">
|
|
88
91
|
<slot name="selected-item" :item="item"></slot>
|
|
89
92
|
<div v-if="!$slots['selected-item']"
|
|
90
|
-
class="bg-
|
|
93
|
+
class="bg-lightDropdownMultipleSelectBackground text-lightDropdownMultipleSelectText text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-darkDropdownMultipleSelectBackground dark:text-darkDropdownMultipleSelectText">
|
|
91
94
|
<span>{{ item.label }}</span>
|
|
92
95
|
<button
|
|
93
96
|
type="button"
|
|
94
97
|
@click="toogleItem(item)"
|
|
95
|
-
class="z-index-100 flex-shrink-0 ml-1 h-4 w-4 -mr-1 rounded-full inline-flex items-center justify-center text-
|
|
98
|
+
class="z-index-100 flex-shrink-0 ml-1 h-4 w-4 -mr-1 rounded-full inline-flex items-center justify-center text-lightDropdownMultipleSelectIcon hover:text-lightDropdownMultipleSelectIconHover dark:text-darkDropdownMultipleSelectIcon dark:hover:text-darkDropdownMultipleSelectIconHover focus:outline-none focus:text-lightDropdownMultipleSelectIconFocus focus:bg-lightDropdownMultipleSelectIconFocusBackground dark:focus:text-darkDropdownMultipleSelectIconFocus dark:focus:bg-darkDropdownMultipleSelectIconFocusBackground"
|
|
96
99
|
>
|
|
97
100
|
<span class="sr-only">{{ $t('Remove item') }}</span>
|
|
98
101
|
<svg class="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8">
|
|
@@ -111,7 +114,7 @@
|
|
|
111
114
|
</template>
|
|
112
115
|
|
|
113
116
|
<script setup lang="ts">
|
|
114
|
-
import { ref, computed, onMounted, onUnmounted, watch, type Ref } from 'vue';
|
|
117
|
+
import { ref, computed, onMounted, onUnmounted, watch, nextTick, type Ref } from 'vue';
|
|
115
118
|
import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
|
|
116
119
|
import { useElementSize } from '@vueuse/core'
|
|
117
120
|
|
|
@@ -132,13 +135,17 @@ const props = defineProps({
|
|
|
132
135
|
type: Boolean,
|
|
133
136
|
default: false,
|
|
134
137
|
},
|
|
138
|
+
searchDisabled: {
|
|
139
|
+
type: Boolean,
|
|
140
|
+
default: false,
|
|
141
|
+
},
|
|
135
142
|
teleportToBody: {
|
|
136
143
|
type: Boolean,
|
|
137
144
|
default: false,
|
|
138
145
|
},
|
|
139
146
|
});
|
|
140
147
|
|
|
141
|
-
const emit = defineEmits(['update:modelValue']);
|
|
148
|
+
const emit = defineEmits(['update:modelValue', 'scroll-near-end', 'search']);
|
|
142
149
|
|
|
143
150
|
const search = ref('');
|
|
144
151
|
const showDropdown = ref(false);
|
|
@@ -159,6 +166,9 @@ function inputInput() {
|
|
|
159
166
|
selectedItems.value = [];
|
|
160
167
|
emit('update:modelValue', null);
|
|
161
168
|
}
|
|
169
|
+
if (!props.searchDisabled) {
|
|
170
|
+
emit('search', search.value);
|
|
171
|
+
}
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
function updateFromProps() {
|
|
@@ -176,7 +186,7 @@ function updateFromProps() {
|
|
|
176
186
|
}
|
|
177
187
|
}
|
|
178
188
|
|
|
179
|
-
function inputClick() {
|
|
189
|
+
async function inputClick() {
|
|
180
190
|
if (props.readonly) return;
|
|
181
191
|
// Toggle local dropdown
|
|
182
192
|
showDropdown.value = !showDropdown.value;
|
|
@@ -184,6 +194,11 @@ function inputClick() {
|
|
|
184
194
|
if (!showDropdown.value && !search.value) {
|
|
185
195
|
search.value = '';
|
|
186
196
|
}
|
|
197
|
+
|
|
198
|
+
if(props.teleportToBody){
|
|
199
|
+
await nextTick();
|
|
200
|
+
handleScroll();
|
|
201
|
+
}
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
watch(
|
|
@@ -221,6 +236,15 @@ const handleScroll = () => {
|
|
|
221
236
|
}
|
|
222
237
|
};
|
|
223
238
|
|
|
239
|
+
const handleDropdownScroll = (event: Event) => {
|
|
240
|
+
const target = event.target as HTMLElement;
|
|
241
|
+
const threshold = 10; // pixels from bottom
|
|
242
|
+
|
|
243
|
+
if (target.scrollTop + target.clientHeight >= target.scrollHeight - threshold) {
|
|
244
|
+
emit('scroll-near-end');
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
224
248
|
onMounted(() => {
|
|
225
249
|
updateFromProps();
|
|
226
250
|
|
|
@@ -241,7 +265,12 @@ onMounted(() => {
|
|
|
241
265
|
});
|
|
242
266
|
|
|
243
267
|
const filteredItems = computed(() => {
|
|
244
|
-
|
|
268
|
+
|
|
269
|
+
if (props.searchDisabled) {
|
|
270
|
+
return props.options || [];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return (props.options || []).filter((item: any) =>
|
|
245
274
|
item.label.toLowerCase().includes(search.value.toLowerCase())
|
|
246
275
|
);
|
|
247
276
|
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="type === 'image'" role="status" class="flex animate-pulse items-center justify-center bg-
|
|
3
|
-
<svg class="w-10 h-10 text-
|
|
2
|
+
<div v-if="type === 'image'" role="status" class="flex animate-pulse items-center justify-center bg-lightSkeletonBackgroundColor rounded dark:bg-darkSkeletonBackgroundColor">
|
|
3
|
+
<svg class="w-10 h-10 text-lightSkeletonIconColor dark:text-darkSkeletonIconColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
|
|
4
4
|
<path d="M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z"/>
|
|
5
5
|
</svg>
|
|
6
6
|
</div>
|
|
7
|
-
<div v-else-if="type === 'video'" role="status" class="flex items-center justify-center max-w-sm bg-
|
|
8
|
-
<svg class="w-10 h-10 text-
|
|
7
|
+
<div v-else-if="type === 'video'" role="status" class="flex items-center justify-center max-w-sm bg-lightSkeletonBackgroundColor rounded-lg animate-pulse dark:bg-darkSkeletonBackgroundColor">
|
|
8
|
+
<svg class="w-10 h-10 text-lightSkeletonIconColor dark:text-darkSkeletonIconColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 20">
|
|
9
9
|
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.98 2.98 0 0 0 .13 5H5Z"/>
|
|
10
10
|
<path d="M14.066 0H7v5a2 2 0 0 1-2 2H0v11a1.97 1.97 0 0 0 1.934 2h12.132A1.97 1.97 0 0 0 16 18V2a1.97 1.97 0 0 0-1.934-2ZM9 13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2Zm4 .382a1 1 0 0 1-1.447.894L10 13v-2l1.553-1.276a1 1 0 0 1 1.447.894v2.764Z"/>
|
|
11
11
|
</svg>
|
|
12
12
|
<span class="sr-only">Loading...</span>
|
|
13
13
|
</div>
|
|
14
|
-
<svg v-else-if="type === 'avatar'" class="me-3 animate-pulse text-
|
|
14
|
+
<svg v-else-if="type === 'avatar'" class="me-3 animate-pulse text-lightSkeletonIconColor dark:text-darkSkeletonBackgroundColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
|
15
15
|
<path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm0 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 13a8.949 8.949 0 0 1-4.951-1.488A3.987 3.987 0 0 1 9 13h2a3.987 3.987 0 0 1 3.951 3.512A8.949 8.949 0 0 1 10 18Z"/>
|
|
16
16
|
</svg>
|
|
17
|
-
<div v-else role="status" class="flex items-center justify-center animate-pulse bg-
|
|
17
|
+
<div v-else role="status" class="flex items-center justify-center animate-pulse bg-lightSkeletonIconColor rounded-full dark:bg-darkSkeletonBackgroundColor">
|
|
18
18
|
<span class="sr-only">Loading...</span>
|
|
19
19
|
</div>
|
|
20
20
|
</template>
|
|
@@ -1,8 +1,8 @@
|
|
|
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-
|
|
5
|
-
<thead class="text-xs text-
|
|
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
7
|
<th scope="col" class="px-6 py-3"
|
|
8
8
|
v-for="column in columns"
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
<tr
|
|
20
20
|
v-for="(item, index) in dataPage"
|
|
21
21
|
:class="{
|
|
22
|
-
'odd:bg-
|
|
23
|
-
'border-b dark:border-
|
|
22
|
+
'afcl-table-body odd:bg-lightTableOddBackground odd:dark:bg-darkTableOddBackground even:bg-lightTableEvenBackground even:dark:bg-darkTableEvenBackground': evenHighlights,
|
|
23
|
+
'border-b border-lightTableBorder dark:border-darkTableBorder': index !== dataPage.length - 1 || totalPages > 1,
|
|
24
24
|
}"
|
|
25
25
|
>
|
|
26
26
|
<td class="px-6 py-4"
|
|
@@ -38,25 +38,25 @@
|
|
|
38
38
|
</tr>
|
|
39
39
|
</tbody>
|
|
40
40
|
</table>
|
|
41
|
-
<nav class="flex items-center flex-column flex-wrap md:flex-row justify-between p-4"
|
|
41
|
+
<nav class="afcl-table-pagination-container bg-lightTableBackground dark:bg-darkTableBackground flex items-center flex-column flex-wrap md:flex-row justify-between p-4"
|
|
42
42
|
v-if="totalPages > 1"
|
|
43
43
|
:aria-label="$t('Table navigation')">
|
|
44
44
|
<i18n-t
|
|
45
|
-
keypath="Showing {from} to {to} of {total}" tag="span" class="text-sm font-normal text-
|
|
45
|
+
keypath="Showing {from} to {to} of {total}" tag="span" class="afcl-table-pagination-text text-sm font-normal text-lightTablePaginationText dark:text-darkTablePaginationText mb-4 md:mb-0 block w-full md:inline md:w-auto"
|
|
46
46
|
>
|
|
47
|
-
<template #from><span class="font-semibold text-
|
|
48
|
-
<template #to><span class="font-semibold text-
|
|
49
|
-
<template #total><span class="font-semibold text-
|
|
47
|
+
<template #from><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ Math.min((currentPage - 1) * props.pageSize + 1, props.data.length) }}</span></template>
|
|
48
|
+
<template #to><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ Math.min(currentPage * props.pageSize, props.data.length) }}</span></template>
|
|
49
|
+
<template #total><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ props.data.length }}</span></template>
|
|
50
50
|
</i18n-t>
|
|
51
51
|
|
|
52
|
-
<ul class="inline-flex -space-x-px rtl:space-x-reverse text-sm h-8">
|
|
52
|
+
<ul class="afcl-table-pagination-list inline-flex -space-x-px rtl:space-x-reverse text-sm h-8">
|
|
53
53
|
<li v-for="page in totalPages" :key="page">
|
|
54
54
|
<a href="#"
|
|
55
55
|
@click.prevent="switchPage(page)"
|
|
56
56
|
:aria-current="page === page ? 'page' : undefined"
|
|
57
57
|
:class='{
|
|
58
|
-
"text-blue-600 bg-
|
|
59
|
-
"text-
|
|
58
|
+
"afcl-table-pagination-button text-blue-600 bg-lightActivePaginationButtonBackground text-lightActivePaginationButtonText dark:bg-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText hover:opacity-90": page === currentPage,
|
|
59
|
+
"text-lightUnactivePaginationButtonText border bg-lightUnactivePaginationButtonBackground border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:border-darkUnactivePaginationButtonBorder dark:text-darkUnactivePaginationButtonText dark:hover:bg-darkUnactivePaginationButtonHoverBackground dark:hover:text-darkUnactivePaginationButtonHoverText": page !== currentPage,
|
|
60
60
|
"rounded-s-lg ms-0": page === 1,
|
|
61
61
|
"rounded-e-lg": page === totalPages,
|
|
62
62
|
}'
|
|
@@ -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.checked)"
|
|
9
|
+
>
|
|
10
|
+
<div class="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,10 +1,10 @@
|
|
|
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-
|
|
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>
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
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';
|
|
@@ -8,22 +8,22 @@ const modalStore = useModalStore();
|
|
|
8
8
|
<Teleport to="body">
|
|
9
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">
|
|
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-
|
|
12
|
-
<button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-
|
|
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-
|
|
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-
|
|
23
|
-
<button @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" type="button" class="text-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
-
:
|
|
93
|
-
@
|
|
106
|
+
:modelValue="value"
|
|
107
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
94
108
|
:readonly="(column.editReadonly && source === 'edit') || readonly"
|
|
95
109
|
/>
|
|
96
|
-
<
|
|
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
|
-
:
|
|
102
|
-
@
|
|
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-
|
|
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-
|
|
135
|
-
<IconEyeSlashSolid class="w-6 h-6 text-
|
|
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
|
|
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
|
|
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
|
|
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 }> = [
|