fix(12.2): close code-review blockers on uploads, JSON caps, and pivot fill
Keep form save behind in-flight uploads, make retries idempotent via X-Upload-Id, cap remaining JSON bodies, and surface pending pivot type errors instead of zeroing them. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,7 +13,7 @@ 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_SESSION, FORM_VALUES } from '../components/form/formContext'
|
||||
import { FORM_ASSETS, FORM_LOCALE, FORM_PATCH, FORM_SESSION, FORM_VALUES, createUploadGate } from '../components/form/formContext'
|
||||
import { RELATION_MANAGER, needsRecord } from '../components/form/registry'
|
||||
import {
|
||||
DEFAULT_TAB,
|
||||
@@ -79,6 +79,7 @@ const sessionHeader = { [SESSION_HEADER]: sessionKey } as { 'X-Session-Key': str
|
||||
const pendingChanges = ref(0)
|
||||
// Bumped after each successful save, so file fields reload their lists.
|
||||
const revision = ref(0)
|
||||
const { activeUploads, beginUpload } = createUploadGate()
|
||||
|
||||
// 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).
|
||||
@@ -151,7 +152,9 @@ const subtitle = computed(() =>
|
||||
const dirty = computed(
|
||||
() =>
|
||||
!loading.value &&
|
||||
(pendingChanges.value > 0 || snapshot(editablePayload(fields.value, values.value)) !== saved.value),
|
||||
(pendingChanges.value > 0 ||
|
||||
activeUploads.value > 0 ||
|
||||
snapshot(editablePayload(fields.value, values.value)) !== saved.value),
|
||||
)
|
||||
|
||||
function adopt(record: RecordEnvelope | undefined): void {
|
||||
@@ -211,6 +214,8 @@ provide(FORM_SESSION, {
|
||||
},
|
||||
pendingChanges: readonly(pendingChanges),
|
||||
revision: readonly(revision),
|
||||
beginUpload,
|
||||
activeUploads: readonly(activeUploads),
|
||||
})
|
||||
|
||||
/** 422: messages under fields, the first invalid field (schema order) focused. */
|
||||
@@ -236,7 +241,7 @@ function redirectTarget(kind: 'redirect' | 'redirectClose', id: unknown): string
|
||||
|
||||
/** Saves the record; returns the saved envelope, or null after an error. */
|
||||
async function save(): Promise<RecordEnvelope | null> {
|
||||
if (busy.value || !schema.value) {
|
||||
if (busy.value || !schema.value || activeUploads.value > 0) {
|
||||
return null
|
||||
}
|
||||
busy.value = true
|
||||
@@ -420,10 +425,10 @@ void load()
|
||||
</Button>
|
||||
<div class="ml-auto flex items-center gap-2.5">
|
||||
<Button variant="ghost" data-action="cancel" :to="listPath">{{ t('backend::lang.form.cancel') }}</Button>
|
||||
<Button variant="outline" data-action="save-close" :disabled="busy || loading || !schema" @click="onSaveAndClose">
|
||||
<Button variant="outline" data-action="save-close" :disabled="busy || loading || !schema || activeUploads > 0" @click="onSaveAndClose">
|
||||
{{ t('backend::lang.form.save_and_close') }}
|
||||
</Button>
|
||||
<Button variant="primary" data-action="save" :disabled="busy || loading || !schema" @click="onSave">
|
||||
<Button variant="primary" data-action="save" :disabled="busy || loading || !schema || activeUploads > 0" @click="onSave">
|
||||
{{ busy ? t('backend::lang.form.saving') : t('backend::lang.form.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user