feat(10.1-02): mount plugin widget elements and run their actions from the form
- pluginAssets loads controller scripts and stylesheets from {base}/assets/ only, once per URL
- WidgetField mounts the custom element with attributes only and posts summer-action through the typed client
- Only declared fill keys returned by the server are patched; the form turns dirty and nothing saves
- widget is a registered valueless type rendered on create and update, labelled as a group
- backend::lang.extension strings in en and pl; embedded dist rebuilt
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue'
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, provide, ref, watchEffect } from 'vue'
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
|
||||
import { ArrowLeft, Trash2 } from '@lucide/vue'
|
||||
import { api } from '../api/client'
|
||||
import type { AdminRecord, ErrorEnvelope, FormView, RecordEnvelope, RecordMeta } from '../api/types'
|
||||
import { controllerIdFromParams, controllerPath } from '../app/controllerRoutes'
|
||||
import { message, t } from '../app/i18n'
|
||||
import { currentLocale, message, t } from '../app/i18n'
|
||||
import { loadControllerAssets } from '../app/pluginAssets'
|
||||
import { mapWinterUrl } from '../app/winterUrl'
|
||||
import FormErrorBanner from '../components/form/FormErrorBanner.vue'
|
||||
import FormGrid from '../components/form/FormGrid.vue'
|
||||
import FormTabs from '../components/form/FormTabs.vue'
|
||||
import { FORM_ASSETS, FORM_LOCALE, FORM_PATCH, FORM_VALUES } from '../components/form/formContext'
|
||||
import { needsRecord } from '../components/form/registry'
|
||||
import {
|
||||
DEFAULT_TAB,
|
||||
@@ -63,6 +65,8 @@ const confirm = useConfirm()
|
||||
// Set right before a navigation the form itself starts after a save or a
|
||||
// delete, so the dirty guard does not ask.
|
||||
let leaving = false
|
||||
// The controller's plugin scripts: settled when every one loaded or failed.
|
||||
let assetsReady: Promise<string[]> = Promise.resolve([])
|
||||
|
||||
// A relation manager needs a saved record: on create it is dropped with its
|
||||
// tab even when the YAML forgets `context: update` (D-05, design screen 5).
|
||||
@@ -150,6 +154,10 @@ async function load(): Promise<void> {
|
||||
])
|
||||
schema.value = schemaResult.data?.data ?? null
|
||||
failed.value = !schemaResult.data || (recordResult !== null && !recordResult.data)
|
||||
if (schema.value) {
|
||||
// Plugin files load in the background; only widgets wait for them (D-14).
|
||||
assetsReady = loadControllerAssets(controllerId, schema.value.assets)
|
||||
}
|
||||
if (schema.value && mode === 'create') {
|
||||
values.value = initialValues(fields.value)
|
||||
}
|
||||
@@ -167,6 +175,14 @@ function update(name: string, value: unknown): void {
|
||||
}
|
||||
}
|
||||
|
||||
// Extension controls (widgets) read the values and locale and write action
|
||||
// results back through update, so a fill marks the form dirty and clears
|
||||
// that field's errors like an edit (D-07, D-08).
|
||||
provide(FORM_VALUES, computed(() => values.value))
|
||||
provide(FORM_PATCH, update)
|
||||
provide(FORM_LOCALE, computed(() => schema.value?.meta.locale || currentLocale.value))
|
||||
provide(FORM_ASSETS, () => assetsReady)
|
||||
|
||||
/** 422: messages under fields, the first invalid field (schema order) focused. */
|
||||
async function showErrors(error: ErrorEnvelope['error'] | undefined): Promise<void> {
|
||||
errors.value = fieldErrors(error?.details)
|
||||
|
||||
Reference in New Issue
Block a user