adminforth 2.4.0-next.321 → 2.4.0-next.323

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.
@@ -55,7 +55,7 @@
55
55
  @update:emptiness="customComponentsEmptiness[$event.name] = $event.value"
56
56
  :readonly="readonlyColumns?.includes(column.name)"
57
57
  />
58
- <div v-if="columnError(column) && validating" class="mt-1 text-xs text-lightInputErrorColor dark:text-darkInputErrorColor">{{ columnError(column) }}</div>
58
+ <div v-if="columnError(column) && validating" class="af-invalid-field-message mt-1 text-xs text-lightInputErrorColor dark:text-darkInputErrorColor">{{ columnError(column) }}</div>
59
59
  <div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-lightFormFieldTextColor dark:text-darkFormFieldTextColor">{{ column.editingNote[mode] }}</div>
60
60
  </td>
61
61
  </tr>
@@ -377,4 +377,9 @@ watch(() => isValid.value, (value) => {
377
377
  emit('update:isValid', value);
378
378
  });
379
379
 
380
+ defineExpose({
381
+ columnError,
382
+ editableColumns,
383
+ })
384
+
380
385
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="min-w-40">
2
+ <div v-if="options && options.length" class="min-w-40">
3
3
  <div class="cursor-pointer flex items-center justify-between gap-1 block px-4 py-2 text-sm
4
4
  bg-lightUserMenuItemBackground hover:bg-lightUserMenuItemBackgroundHover text-lightUserMenuItemText
5
5
  hover:text-lightUserMenuItemText dark:bg-darkUserMenuItemBackground dark:hover:bg-darkUserMenuItemBackgroundHover
@@ -67,6 +67,7 @@
67
67
 
68
68
  <ResourceForm
69
69
  v-else
70
+ ref="resourceFormRef"
70
71
  :record="record"
71
72
  :resource="coreStore.resource!"
72
73
  @update:record="onUpdateRecord"
@@ -98,7 +99,7 @@ import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
98
99
  import { useCoreStore } from '@/stores/core';
99
100
  import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions, initThreeDotsDropdown } from '@/utils';
100
101
  import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
101
- import { onMounted, ref, watch } from 'vue';
102
+ import { onMounted, ref, watch, nextTick } from 'vue';
102
103
  import { useRoute, useRouter } from 'vue-router';
103
104
  import { computed } from 'vue';
104
105
  import { showErrorTost } from '@/composables/useFrontendApi';
@@ -106,6 +107,7 @@ import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
106
107
  import adminforth from '@/adminforth';
107
108
  import { useI18n } from 'vue-i18n';
108
109
  import { type AdminForthComponentDeclarationFull } from '@/types/Common.js';
110
+ import type { AdminForthResourceColumn } from '@/types/Back';
109
111
 
110
112
  const isValid = ref(false);
111
113
  const validating = ref(false);
@@ -122,6 +124,8 @@ const coreStore = useCoreStore();
122
124
 
123
125
  const { t } = useI18n();
124
126
 
127
+ const resourceFormRef = ref<InstanceType<typeof ResourceForm> | null>(null);
128
+
125
129
  const createSaveButtonInjection = computed<AdminForthComponentDeclarationFull | null>(() => {
126
130
  const raw: any = coreStore.resourceOptions?.pageInjections?.create?.saveButton as any;
127
131
  if (!raw) return null;
@@ -180,6 +184,8 @@ onMounted(async () => {
180
184
  async function saveRecord(opts?: { confirmationResult?: any }) {
181
185
  if (!isValid.value) {
182
186
  validating.value = true;
187
+ await nextTick();
188
+ scrollToInvalidField();
183
189
  return;
184
190
  } else {
185
191
  validating.value = false;
@@ -217,5 +223,23 @@ async function saveRecord(opts?: { confirmationResult?: any }) {
217
223
  }
218
224
  }
219
225
 
226
+ function scrollToInvalidField() {
227
+ let columnsWithErrors: {column: AdminForthResourceColumn, error: string}[] = [];
228
+ for (const column of resourceFormRef.value?.editableColumns || []) {
229
+ const error = resourceFormRef.value?.columnError(column);
230
+ if (error) {
231
+ columnsWithErrors.push({column, error});
232
+ }
233
+ }
234
+ const errorMessage = t('Failed to save. Please fix errors for the following fields:') + '<ul class="mt-2 list-disc list-inside">' + columnsWithErrors.map(c => `<li><strong>${c.column.label || c.column.name}</strong>: ${c.error}</li>`).join('') + '</ul>';
235
+ adminforth.alert({
236
+ messageHtml: errorMessage,
237
+ variant: 'danger'
238
+ });
239
+ const firstInvalidElement = document.querySelector('.af-invalid-field-message');
240
+ if (firstInvalidElement) {
241
+ firstInvalidElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
242
+ }
243
+ }
220
244
 
221
245
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "2.4.0-next.321",
3
+ "version": "2.4.0-next.323",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",