@things-factory/figure-ui 10.1.241 → 10.1.244
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/client/graphql/store.ts +3 -2
- package/client/modeller/editor.ts +63 -5
- package/client/modeller/figure-parts.ts +18 -3
- package/client/modeller/figure-preview.ts +1 -1
- package/client/modeller/figure-properties.ts +14 -7
- package/client/modeller/figure-save-conflict.ts +73 -0
- package/client/modeller/figure-section-editor.ts +3 -0
- package/client/modeller/keys.ts +8 -2
- package/client/modeller/modeller-keys.ts +4 -1
- package/client/modeller/product-session.ts +107 -5
- package/client/modeller/save-conflict.ts +91 -0
- package/client/pages/figure-modeller-page.ts +58 -43
- package/dist-client/graphql/store.js +3 -2
- package/dist-client/graphql/store.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +14 -0
- package/dist-client/modeller/editor.js +75 -5
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-parts.js +18 -3
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +1 -1
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-properties.d.ts +4 -2
- package/dist-client/modeller/figure-properties.js +16 -7
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/figure-save-conflict.d.ts +19 -0
- package/dist-client/modeller/figure-save-conflict.js +76 -0
- package/dist-client/modeller/figure-save-conflict.js.map +1 -0
- package/dist-client/modeller/figure-section-editor.d.ts +2 -0
- package/dist-client/modeller/figure-section-editor.js +8 -0
- package/dist-client/modeller/figure-section-editor.js.map +1 -1
- package/dist-client/modeller/keys.d.ts +5 -0
- package/dist-client/modeller/keys.js +5 -3
- package/dist-client/modeller/keys.js.map +1 -1
- package/dist-client/modeller/modeller-keys.d.ts +2 -0
- package/dist-client/modeller/modeller-keys.js +2 -1
- package/dist-client/modeller/modeller-keys.js.map +1 -1
- package/dist-client/modeller/product-session.d.ts +368 -22
- package/dist-client/modeller/product-session.js +107 -7
- package/dist-client/modeller/product-session.js.map +1 -1
- package/dist-client/modeller/save-conflict.d.ts +12 -0
- package/dist-client/modeller/save-conflict.js +63 -0
- package/dist-client/modeller/save-conflict.js.map +1 -0
- package/dist-client/pages/figure-modeller-page.d.ts +11 -5
- package/dist-client/pages/figure-modeller-page.js +58 -49
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/test/browser/category-page.js +3 -1
- package/test/browser/category.check.mjs +6 -0
- package/test/browser/product-page.check.mjs +268 -6
- package/test/browser/product-page.js +4 -1
- package/test/browser/screen.check.mjs +3 -0
- package/test/browser/section.check.mjs +21 -0
- package/test/keys.test.ts +8 -0
- package/test/product-session.test.ts +137 -1
- package/test/save-conflict.test.ts +41 -0
- package/test/save-landed.test.ts +75 -0
- package/translations/en.json +12 -1
- package/translations/es.json +12 -1
- package/translations/ja.json +12 -1
- package/translations/ko.json +12 -1
- package/translations/ms.json +12 -1
- package/translations/zh.json +12 -1
package/test/save-landed.test.ts
CHANGED
|
@@ -214,3 +214,78 @@ test('the answer lost after the picture was written: read back by its hash, it w
|
|
|
214
214
|
assert.equal(session.read().dirty, false, 'source and picture both landed')
|
|
215
215
|
assert.equal(await thumbnailHashOf('not a picture'), undefined)
|
|
216
216
|
})
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
A real conflict -- another editor saved first -- leaves the edits here, with the server's latest kept to compare with
|
|
220
|
+
and, only when the person says so, to write over or to leave as it is by keeping the edits as a copy (2026-11-01 audit
|
|
221
|
+
item 6).
|
|
222
|
+
*/
|
|
223
|
+
test('a conflict keeps the latest; written over, the next save expects it; another change meanwhile is a conflict again', async () => {
|
|
224
|
+
const s = server()
|
|
225
|
+
const session = createFigureProductSession(s.store)
|
|
226
|
+
await session.open('a')
|
|
227
|
+
session.command({ kind: 'rename', name: 'Mine' } as never)
|
|
228
|
+
const theirs = serializeFigureAsset(addFigureBox(createFigureAsset('Theirs'), { id: 'body', size: { x: 50, y: 50, z: 50 }, position: { x: 0, y: 25, z: 0 } }))
|
|
229
|
+
s.setRow(theirs)
|
|
230
|
+
await assert.rejects(session.save(), { code: 'FIGURE_SOURCE_CONFLICT' })
|
|
231
|
+
assert.deepEqual(session.read().conflict, { latest: theirs })
|
|
232
|
+
assert.equal(session.read().dirty, true)
|
|
233
|
+
assert.equal(session.read().name, 'Mine', 'the edits stay')
|
|
234
|
+
/* Still the other's: saving again is the same conflict. */
|
|
235
|
+
await assert.rejects(session.save(), { code: 'FIGURE_SOURCE_CONFLICT' })
|
|
236
|
+
session.overwriteConflict()
|
|
237
|
+
assert.equal(session.read().conflict, undefined)
|
|
238
|
+
const third = serializeFigureAsset(createFigureAsset('Third'))
|
|
239
|
+
s.setRow(third)
|
|
240
|
+
await assert.rejects(session.save(), { code: 'FIGURE_SOURCE_CONFLICT' }, 'written over only while the latest is what was read')
|
|
241
|
+
assert.deepEqual(session.read().conflict, { latest: third })
|
|
242
|
+
session.overwriteConflict()
|
|
243
|
+
await session.save()
|
|
244
|
+
assert.equal(JSON.parse(s.row()).name, 'Mine')
|
|
245
|
+
assert.equal(session.read().conflict, undefined)
|
|
246
|
+
assert.equal(session.read().dirty, false)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('a conflict kept as a copy: a new figure under a new creation id, the edits with it, the other figure untouched', async () => {
|
|
250
|
+
const s = server()
|
|
251
|
+
const saved: { id?: string; creationId?: string; type?: string }[] = []
|
|
252
|
+
const rowWrites: [string, object][] = []
|
|
253
|
+
const store = {
|
|
254
|
+
...s.store,
|
|
255
|
+
save: async (q: { id?: string; source: string; expectedSource?: string; creationId?: string; type?: string }) => (saved.push(q), q.id ? s.store.save(q) : { id: q.creationId!, source: q.source }),
|
|
256
|
+
updateCatalog: async (id: string, patch: object) => (rowWrites.push([id, patch]), {})
|
|
257
|
+
}
|
|
258
|
+
const session = createFigureProductSession(store)
|
|
259
|
+
await session.open('a')
|
|
260
|
+
const opened = session.read().creationId
|
|
261
|
+
assert.throws(() => session.detachAsCopy(), { code: 'SESSION_NO_CONFLICT' }, 'only after a conflict')
|
|
262
|
+
session.command({ kind: 'rename', name: 'Mine' } as never)
|
|
263
|
+
session.editCatalog({ category: 'equipment', tags: ['new-tag'], type: 'gate-2' }, { type: 'gate' })
|
|
264
|
+
const theirs = serializeFigureAsset(createFigureAsset('Theirs'))
|
|
265
|
+
s.setRow(theirs)
|
|
266
|
+
await assert.rejects(session.save(), { code: 'FIGURE_SOURCE_CONFLICT' })
|
|
267
|
+
const copy = session.detachAsCopy()
|
|
268
|
+
assert.deepEqual(copy.catalog, { category: 'equipment', tags: ['new-tag'] }, 'the category and tags go with the copy; its type is asked anew')
|
|
269
|
+
assert.equal(copy.id, undefined)
|
|
270
|
+
assert.notEqual(copy.creationId, opened)
|
|
271
|
+
assert.equal(copy.conflict, undefined)
|
|
272
|
+
assert.equal(copy.name, 'Mine')
|
|
273
|
+
await session.save({ type: 'gate-copy' })
|
|
274
|
+
assert.deepEqual(saved.at(-1), { ...saved.at(-1), id: undefined, creationId: copy.creationId, type: 'gate-copy', expectedSource: undefined })
|
|
275
|
+
assert.equal(session.read().id, copy.creationId)
|
|
276
|
+
assert.deepEqual(rowWrites, [[copy.creationId, { category: 'equipment', tags: ['new-tag'] }]], 'written to the copy once it has a row')
|
|
277
|
+
assert.equal(session.read().dirty, false)
|
|
278
|
+
assert.equal(s.row(), theirs, 'the figure it came from is as the server had it')
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
test('the latest not readable: the conflict stands, and it cannot be written over blind', async () => {
|
|
282
|
+
const s = server()
|
|
283
|
+
const session = createFigureProductSession(s.store)
|
|
284
|
+
await session.open('a')
|
|
285
|
+
session.command({ kind: 'rename', name: 'Mine' } as never)
|
|
286
|
+
s.setRow(serializeFigureAsset(createFigureAsset('Theirs')))
|
|
287
|
+
s.state.loadFails = true
|
|
288
|
+
await assert.rejects(session.save(), { code: 'FIGURE_SOURCE_CONFLICT' })
|
|
289
|
+
assert.deepEqual(session.read().conflict, { latest: undefined })
|
|
290
|
+
assert.throws(() => session.overwriteConflict(), { code: 'SESSION_NO_CONFLICT' })
|
|
291
|
+
})
|
package/translations/en.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "Data {name} reads itself: {fields}.",
|
|
1295
1295
|
"figure.label.data-binding-resting": "resting",
|
|
1296
1296
|
"figure.text.data-binding-rests": "In {where} the {name} capability does this instead.",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "In {where} the {name} capability does this instead for: {targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "In {where} the {name} capability does this instead for: {targets}",
|
|
1298
|
+
"figure.title.save-conflict": "save conflict",
|
|
1299
|
+
"figure.text.save-conflict-desc": "This figure was saved elsewhere first. Your edits are still here on this screen.",
|
|
1300
|
+
"figure.label.conflict-changed": "parts that differ",
|
|
1301
|
+
"figure.label.conflict-mine-only": "parts only in your edits",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "parts only in the latest",
|
|
1303
|
+
"figure.text.conflict-other-changed": "Settings outside the parts (name, inputs, capabilities...) differ too.",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "The latest could not be read, so it was not compared. It cannot be overwritten.",
|
|
1305
|
+
"figure.button.save-as-copy": "save as a copy",
|
|
1306
|
+
"figure.button.open-latest": "open the latest in a new tab",
|
|
1307
|
+
"figure.button.overwrite-latest": "overwrite with my edits",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "What changed in the latest is replaced by your edits and not kept. Overwrite?"
|
|
1298
1309
|
}
|
package/translations/es.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "Datos que {name} lee por sí misma: {fields}.",
|
|
1295
1295
|
"figure.label.data-binding-resting": "en pausa",
|
|
1296
1296
|
"figure.text.data-binding-rests": "En {where} la capacidad {name} se encarga en su lugar.",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "En {where} la capacidad {name} se encarga en su lugar de: {targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "En {where} la capacidad {name} se encarga en su lugar de: {targets}",
|
|
1298
|
+
"figure.title.save-conflict": "conflicto al guardar",
|
|
1299
|
+
"figure.text.save-conflict-desc": "Esta figura se guardó antes en otro lugar. Tus ediciones siguen en esta pantalla.",
|
|
1300
|
+
"figure.label.conflict-changed": "partes distintas",
|
|
1301
|
+
"figure.label.conflict-mine-only": "partes solo en tus ediciones",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "partes solo en la última versión",
|
|
1303
|
+
"figure.text.conflict-other-changed": "También difieren ajustes fuera de las partes (nombre, entradas, capacidades...).",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "No se pudo leer la última versión, así que no se comparó. No se puede sobrescribir.",
|
|
1305
|
+
"figure.button.save-as-copy": "guardar como copia",
|
|
1306
|
+
"figure.button.open-latest": "abrir la última versión en una pestaña nueva",
|
|
1307
|
+
"figure.button.overwrite-latest": "sobrescribir con mis ediciones",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "Lo que cambió en la última versión se reemplaza por tus ediciones y no se conserva. ¿Sobrescribir?"
|
|
1298
1309
|
}
|
package/translations/ja.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "{name} 能力が読むデータ: {fields}。",
|
|
1295
1295
|
"figure.label.data-binding-resting": "休止",
|
|
1296
1296
|
"figure.text.data-binding-rests": "{where} では {name} 能力が代わりに受け持ちます。",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "{where} では {name} 能力が代わりに受け持ちます: {targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "{where} では {name} 能力が代わりに受け持ちます: {targets}",
|
|
1298
|
+
"figure.title.save-conflict": "保存の競合",
|
|
1299
|
+
"figure.text.save-conflict-desc": "別の場所でこの Figure が先に保存されました。編集内容はこの画面にそのまま残っています。",
|
|
1300
|
+
"figure.label.conflict-changed": "異なる部品",
|
|
1301
|
+
"figure.label.conflict-mine-only": "自分の編集にだけある部品",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "最新版にだけある部品",
|
|
1303
|
+
"figure.text.conflict-other-changed": "部品以外の設定(名前・入力・能力など)も異なります。",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "最新版を読み込めなかったため比較できませんでした。上書きはできません。",
|
|
1305
|
+
"figure.button.save-as-copy": "コピーとして保存",
|
|
1306
|
+
"figure.button.open-latest": "最新版を新しいタブで開く",
|
|
1307
|
+
"figure.button.overwrite-latest": "自分の編集で上書き",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "最新版で変更された内容は自分の編集に置き換えられ、残りません。上書きしますか?"
|
|
1298
1309
|
}
|
package/translations/ko.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "{name} 능력이 읽는 데이터: {fields}.",
|
|
1295
1295
|
"figure.label.data-binding-resting": "쉼",
|
|
1296
1296
|
"figure.text.data-binding-rests": "{where}에서는 {name} 능력이 대신합니다.",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "{where}에서는 {name} 능력이 대신합니다: {targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "{where}에서는 {name} 능력이 대신합니다: {targets}",
|
|
1298
|
+
"figure.title.save-conflict": "저장 충돌",
|
|
1299
|
+
"figure.text.save-conflict-desc": "다른 곳에서 이 피규어를 먼저 저장했습니다. 내 편집은 이 화면에 그대로 있습니다.",
|
|
1300
|
+
"figure.label.conflict-changed": "달라진 부품",
|
|
1301
|
+
"figure.label.conflict-mine-only": "내 편집에만 있는 부품",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "최신본에만 있는 부품",
|
|
1303
|
+
"figure.text.conflict-other-changed": "부품 밖의 설정(이름·입력·능력 등)도 다릅니다.",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "최신본을 읽지 못해 비교하지 못했습니다. 덮어쓰기는 할 수 없습니다.",
|
|
1305
|
+
"figure.button.save-as-copy": "사본으로 저장",
|
|
1306
|
+
"figure.button.open-latest": "최신본을 새 탭에서 열기",
|
|
1307
|
+
"figure.button.overwrite-latest": "내 편집으로 덮어쓰기",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "최신본에서 바뀐 내용은 내 편집으로 바뀌고 남지 않습니다. 덮어쓸까요?"
|
|
1298
1309
|
}
|
package/translations/ms.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "Data yang {name} baca sendiri: {fields}.",
|
|
1295
1295
|
"figure.label.data-binding-resting": "rehat",
|
|
1296
1296
|
"figure.text.data-binding-rests": "Dalam {where} keupayaan {name} mengambil alih.",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "Dalam {where} keupayaan {name} mengambil alih: {targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "Dalam {where} keupayaan {name} mengambil alih: {targets}",
|
|
1298
|
+
"figure.title.save-conflict": "konflik simpanan",
|
|
1299
|
+
"figure.text.save-conflict-desc": "Figura ini telah disimpan di tempat lain dahulu. Suntingan anda masih ada pada skrin ini.",
|
|
1300
|
+
"figure.label.conflict-changed": "bahagian yang berbeza",
|
|
1301
|
+
"figure.label.conflict-mine-only": "bahagian hanya dalam suntingan anda",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "bahagian hanya dalam versi terkini",
|
|
1303
|
+
"figure.text.conflict-other-changed": "Tetapan di luar bahagian (nama, input, keupayaan...) juga berbeza.",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "Versi terkini tidak dapat dibaca, jadi tidak dibandingkan. Ia tidak boleh ditulis ganti.",
|
|
1305
|
+
"figure.button.save-as-copy": "simpan sebagai salinan",
|
|
1306
|
+
"figure.button.open-latest": "buka versi terkini dalam tab baharu",
|
|
1307
|
+
"figure.button.overwrite-latest": "tulis ganti dengan suntingan saya",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "Perubahan dalam versi terkini akan diganti oleh suntingan anda dan tidak disimpan. Tulis ganti?"
|
|
1298
1309
|
}
|
package/translations/zh.json
CHANGED
|
@@ -1294,5 +1294,16 @@
|
|
|
1294
1294
|
"figure.text.data-capability-fields": "{name} 能力自己读取的数据:{fields}。",
|
|
1295
1295
|
"figure.label.data-binding-resting": "暂停",
|
|
1296
1296
|
"figure.text.data-binding-rests": "在 {where} 中由 {name} 能力代为处理。",
|
|
1297
|
-
"figure.text.data-binding-rests-targets": "在 {where} 中由 {name} 能力代为处理:{targets}"
|
|
1297
|
+
"figure.text.data-binding-rests-targets": "在 {where} 中由 {name} 能力代为处理:{targets}",
|
|
1298
|
+
"figure.title.save-conflict": "保存冲突",
|
|
1299
|
+
"figure.text.save-conflict-desc": "此 Figure 已在别处先行保存。你的编辑仍保留在此画面中。",
|
|
1300
|
+
"figure.label.conflict-changed": "不同的部件",
|
|
1301
|
+
"figure.label.conflict-mine-only": "仅在你的编辑中的部件",
|
|
1302
|
+
"figure.label.conflict-theirs-only": "仅在最新版本中的部件",
|
|
1303
|
+
"figure.text.conflict-other-changed": "部件以外的设置(名称、输入、能力等)也不同。",
|
|
1304
|
+
"figure.text.conflict-latest-unread": "无法读取最新版本,因此未能比较。无法覆盖。",
|
|
1305
|
+
"figure.button.save-as-copy": "另存为副本",
|
|
1306
|
+
"figure.button.open-latest": "在新标签页中打开最新版本",
|
|
1307
|
+
"figure.button.overwrite-latest": "用我的编辑覆盖",
|
|
1308
|
+
"figure.text.overwrite-latest-warning": "最新版本中的更改将被你的编辑替换且不会保留。要覆盖吗?"
|
|
1298
1309
|
}
|