@open-mercato/ui 0.6.5-develop.4674.1.bf258550ce → 0.6.5-develop.4691.1.bb409545b3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ui",
|
|
3
|
-
"version": "0.6.5-develop.
|
|
3
|
+
"version": "0.6.5-develop.4691.1.bb409545b3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -149,13 +149,13 @@
|
|
|
149
149
|
"remark-gfm": "^4.0.1"
|
|
150
150
|
},
|
|
151
151
|
"peerDependencies": {
|
|
152
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
152
|
+
"@open-mercato/shared": "0.6.5-develop.4691.1.bb409545b3",
|
|
153
153
|
"react": ">=18.0.0",
|
|
154
154
|
"react-dom": ">=18.0.0",
|
|
155
155
|
"react-is": ">=18.0.0"
|
|
156
156
|
},
|
|
157
157
|
"devDependencies": {
|
|
158
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
158
|
+
"@open-mercato/shared": "0.6.5-develop.4691.1.bb409545b3",
|
|
159
159
|
"@testing-library/dom": "^10.4.1",
|
|
160
160
|
"@testing-library/jest-dom": "^6.9.1",
|
|
161
161
|
"@testing-library/react": "^16.3.1",
|
package/src/backend/CrudForm.tsx
CHANGED
|
@@ -2321,7 +2321,18 @@ export function CrudForm<TValues extends Record<string, unknown>>({
|
|
|
2321
2321
|
appliedInitialValuesSnapshotRef.current = snapshot
|
|
2322
2322
|
const initialRecord = initialValues as Record<string, unknown>
|
|
2323
2323
|
let mergedValues: CrudFormValues<TValues> | null = null
|
|
2324
|
+
// Whether the user already has unsaved edits relative to the load-time baseline,
|
|
2325
|
+
// computed from `prev` (React's latest committed values) — NOT from isDirtyRef or
|
|
2326
|
+
// valuesRef, which are both updated in post-render effects and therefore still
|
|
2327
|
+
// hold stale values when this layout effect runs in the SAME render that async
|
|
2328
|
+
// custom-field / injected-field definitions arrive. That lag was the residual
|
|
2329
|
+
// race that let the baseline absorb an in-progress edit under load.
|
|
2330
|
+
let hadUnsavedEdits = false
|
|
2324
2331
|
setValues((prev) => {
|
|
2332
|
+
const priorBaseline = dirtyBaselineSnapshotRef.current
|
|
2333
|
+
hadUnsavedEdits =
|
|
2334
|
+
priorBaseline !== undefined &&
|
|
2335
|
+
createDirtySnapshot(prev as Record<string, unknown>) !== priorBaseline
|
|
2325
2336
|
const merged = { ...prev, ...initialValues } as CrudFormValues<TValues>
|
|
2326
2337
|
for (const definition of injectedFieldDefinitions) {
|
|
2327
2338
|
if (merged[definition.id] !== undefined) continue
|
|
@@ -2348,7 +2359,17 @@ export function CrudForm<TValues extends Record<string, unknown>>({
|
|
|
2348
2359
|
mergedValues = merged
|
|
2349
2360
|
return mergedValues
|
|
2350
2361
|
})
|
|
2351
|
-
if (mergedValues) {
|
|
2362
|
+
if (mergedValues && !hadUnsavedEdits) {
|
|
2363
|
+
// Do not absorb an in-progress edit into the pristine baseline. This effect
|
|
2364
|
+
// re-runs whenever the snapshot changes — which includes custom-field
|
|
2365
|
+
// definitions and injected fields loading ASYNCHRONOUSLY after mount. If the
|
|
2366
|
+
// user has already started editing by the time they arrive, recomputing the
|
|
2367
|
+
// baseline from the current (merged) values would set the baseline equal to
|
|
2368
|
+
// the edited values, silently clearing dirty (header Save disables, the edit
|
|
2369
|
+
// looks pristine) and discarding the unsaved change. Re-establish the baseline
|
|
2370
|
+
// only when there are no pending edits; while dirty, keep the load-time
|
|
2371
|
+
// baseline so the edit stays dirty until save/discard. Root cause of the flaky
|
|
2372
|
+
// optimistic-lock stale-edit conflicts (#2055 / TC-LOCK-OSS-015 / TC-LOCK-OSS-029).
|
|
2352
2373
|
dirtyBaselineSnapshotRef.current = createDirtySnapshot(mergedValues as Record<string, unknown>)
|
|
2353
2374
|
}
|
|
2354
2375
|
if (!extendedInjectionEventsEnabled || !mergedValues) return
|
|
@@ -2362,6 +2383,9 @@ export function CrudForm<TValues extends Record<string, unknown>>({
|
|
|
2362
2383
|
)
|
|
2363
2384
|
const transformed = result.data
|
|
2364
2385
|
if (cancelled || !transformed) return
|
|
2386
|
+
// As above: never re-apply transformed display data over an in-progress
|
|
2387
|
+
// edit — it would overwrite the user's unsaved changes and reset dirty.
|
|
2388
|
+
if (isDirtyRef.current) return
|
|
2365
2389
|
dirtyBaselineSnapshotRef.current = createDirtySnapshot(transformed as Record<string, unknown>)
|
|
2366
2390
|
setValues(transformed as CrudFormValues<TValues>)
|
|
2367
2391
|
} catch (err) {
|