@things-factory/figure-ui 10.1.5 → 10.1.7
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/index.ts +36 -3
- package/client/modeller/figure-animations.ts +712 -0
- package/client/modeller/figure-ask.ts +5 -5
- package/client/modeller/figure-canvas.ts +1 -1
- package/client/modeller/figure-capabilities.ts +372 -0
- package/client/modeller/figure-history-panel.ts +171 -18
- package/client/modeller/figure-inspector.ts +439 -76
- package/client/modeller/figure-parts.ts +15 -15
- package/client/modeller/figure-preview.ts +2 -2
- package/client/modeller/figure-report.ts +102 -37
- package/client/modeller/figure-settings.ts +20 -20
- package/client/modeller/figure-side.ts +91 -15
- package/client/modeller/figure-source.test.ts +15 -1
- package/client/modeller/figure-source.ts +31 -15
- package/client/modeller/figure-thumbnail.ts +49 -4
- package/client/modeller/maturity.ts +10 -10
- package/client/pages/figure-list-page.ts +204 -66
- package/client/pages/figure-modeller-page.ts +158 -42
- package/client/types.ts +31 -0
- package/client/viewparts/figure-thumb.ts +250 -0
- package/dist-client/graphql/index.d.ts +8 -1
- package/dist-client/graphql/index.js +33 -3
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/figure-animations.d.ts +93 -0
- package/dist-client/modeller/figure-animations.js +655 -0
- package/dist-client/modeller/figure-animations.js.map +1 -0
- package/dist-client/modeller/figure-ask.js +5 -5
- package/dist-client/modeller/figure-ask.js.map +1 -1
- package/dist-client/modeller/figure-canvas.js +1 -1
- package/dist-client/modeller/figure-canvas.js.map +1 -1
- package/dist-client/modeller/figure-capabilities.d.ts +42 -0
- package/dist-client/modeller/figure-capabilities.js +344 -0
- package/dist-client/modeller/figure-capabilities.js.map +1 -0
- package/dist-client/modeller/figure-history-panel.d.ts +15 -1
- package/dist-client/modeller/figure-history-panel.js +165 -18
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-inspector.d.ts +98 -0
- package/dist-client/modeller/figure-inspector.js +425 -75
- package/dist-client/modeller/figure-inspector.js.map +1 -1
- package/dist-client/modeller/figure-parts.js +15 -15
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +2 -2
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-report.d.ts +18 -1
- package/dist-client/modeller/figure-report.js +105 -37
- package/dist-client/modeller/figure-report.js.map +1 -1
- package/dist-client/modeller/figure-settings.js +19 -19
- package/dist-client/modeller/figure-settings.js.map +1 -1
- package/dist-client/modeller/figure-side.d.ts +24 -0
- package/dist-client/modeller/figure-side.js +94 -14
- package/dist-client/modeller/figure-side.js.map +1 -1
- package/dist-client/modeller/figure-source.d.ts +15 -8
- package/dist-client/modeller/figure-source.js +16 -7
- package/dist-client/modeller/figure-source.js.map +1 -1
- package/dist-client/modeller/figure-thumbnail.js +40 -4
- package/dist-client/modeller/figure-thumbnail.js.map +1 -1
- package/dist-client/modeller/maturity.js +10 -10
- package/dist-client/modeller/maturity.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +11 -4
- package/dist-client/pages/figure-list-page.js +201 -63
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +33 -0
- package/dist-client/pages/figure-modeller-page.js +156 -42
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +29 -0
- package/dist-client/types.js.map +1 -1
- package/dist-client/viewparts/figure-thumb.d.ts +29 -0
- package/dist-client/viewparts/figure-thumb.js +242 -0
- package/dist-client/viewparts/figure-thumb.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/test/i18n-prefix-guard.test.ts +171 -0
- package/test/korean-register-guard.test.ts +83 -0
- package/translations/en.json +351 -264
- package/translations/ja.json +276 -264
- package/translations/ko.json +351 -264
- package/translations/ms.json +276 -264
- package/translations/zh.json +276 -264
|
@@ -4,9 +4,10 @@ import { css, html, LitElement, nothing } from 'lit'
|
|
|
4
4
|
import { customElement, property, state } from 'lit/decorators.js'
|
|
5
5
|
|
|
6
6
|
import { i18next, localize } from '@operato/i18n'
|
|
7
|
+
import { ScrollbarStyles } from '@operato/styles'
|
|
7
8
|
|
|
8
|
-
import { fetchFigureVersions, releaseFigure, revertFigureVersion } from '../graphql/index.js'
|
|
9
|
-
import type { FigureVersion } from '../types.js'
|
|
9
|
+
import { fetchFigureVersions, inspectFigure, releaseFigure, revertFigureVersion } from '../graphql/index.js'
|
|
10
|
+
import type { FigureGateFinding, FigureInspection, FigureVersion } from '../types.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* 이력 — **발행하는 자리이자, 발행된 판들을 보는 자리.**
|
|
@@ -29,7 +30,9 @@ import type { FigureVersion } from '../types.js'
|
|
|
29
30
|
*/
|
|
30
31
|
@customElement('figure-history-panel')
|
|
31
32
|
export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
32
|
-
static styles =
|
|
33
|
+
static styles = [
|
|
34
|
+
ScrollbarStyles,
|
|
35
|
+
css`
|
|
33
36
|
:host {
|
|
34
37
|
display: flex;
|
|
35
38
|
flex-direction: column;
|
|
@@ -184,12 +187,79 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
184
187
|
border-color: transparent;
|
|
185
188
|
}
|
|
186
189
|
|
|
190
|
+
/*
|
|
191
|
+
게이트 사유. 막는 것은 색으로도 말하고, 알리는 것은 조용히 둔다 — 둘을 같은 톤으로 두면
|
|
192
|
+
「이 중 어느 것이 발행을 막았나」를 사람이 다시 세어야 한다.
|
|
193
|
+
*/
|
|
194
|
+
ul[gate] {
|
|
195
|
+
margin: var(--spacing-small, 6px) 0 0;
|
|
196
|
+
padding: 0;
|
|
197
|
+
list-style: none;
|
|
198
|
+
display: flex;
|
|
199
|
+
flex-direction: column;
|
|
200
|
+
gap: 3px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
li[head] {
|
|
204
|
+
font: var(--label-font, inherit);
|
|
205
|
+
font-size: 0.72rem;
|
|
206
|
+
color: var(--md-sys-color-error);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
li[head][quiet] {
|
|
210
|
+
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
li[finding] {
|
|
214
|
+
display: flex;
|
|
215
|
+
flex-direction: column;
|
|
216
|
+
align-items: flex-start;
|
|
217
|
+
gap: 3px;
|
|
218
|
+
padding: 3px 6px;
|
|
219
|
+
font-size: 0.72rem;
|
|
220
|
+
line-height: 1.5;
|
|
221
|
+
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
222
|
+
background-color: var(--md-sys-color-surface-container);
|
|
223
|
+
border-radius: 4px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
li[finding][blocking] {
|
|
227
|
+
color: var(--md-sys-color-on-error-container, var(--md-sys-color-on-surface));
|
|
228
|
+
background-color: var(--md-sys-color-error-container);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
li[finding] code[where] {
|
|
232
|
+
font-family: var(--mono-font, monospace);
|
|
233
|
+
font-size: 0.68rem;
|
|
234
|
+
opacity: 0.85;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* 왜 나쁜지는 곁글로 — 읽어야 하지만 잰 것보다 먼저 눈에 들 필요는 없다 */
|
|
238
|
+
li[finding] span[why-line] {
|
|
239
|
+
opacity: 0.8;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* 무엇을 바꾸면 되나 — 이 줄이 실제로 사람이 할 일이다. 연장 표를 달아 눈에 걸리게 한다 */
|
|
243
|
+
li[finding] span[how-line] {
|
|
244
|
+
display: flex;
|
|
245
|
+
align-items: flex-start;
|
|
246
|
+
gap: 4px;
|
|
247
|
+
padding-top: 2px;
|
|
248
|
+
font-weight: 600;
|
|
249
|
+
}
|
|
250
|
+
li[finding] span[how-line] md-icon {
|
|
251
|
+
--md-icon-size: 13px;
|
|
252
|
+
flex: none;
|
|
253
|
+
margin-top: 1px;
|
|
254
|
+
}
|
|
255
|
+
|
|
187
256
|
p[quiet] {
|
|
188
257
|
margin: 0;
|
|
189
258
|
line-height: 1.6;
|
|
190
259
|
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
191
260
|
}
|
|
192
261
|
`
|
|
262
|
+
]
|
|
193
263
|
|
|
194
264
|
/** 지금 열려 있는 도형. 없으면(새로 만드는 중) 발행할 것이 없다. */
|
|
195
265
|
@property({ type: String }) figureId?: string
|
|
@@ -201,11 +271,39 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
201
271
|
@state() private versions: FigureVersion[] = []
|
|
202
272
|
@state() private busy = false
|
|
203
273
|
@state() private failure = ''
|
|
274
|
+
/**
|
|
275
|
+
* 발행 판정. **저장된 정본에 대한 것**이라 저장할 때마다 다시 묻는다(`figureVersion` 이 아니라
|
|
276
|
+
* `dirty` 가 풀리는 순간이 그때다).
|
|
277
|
+
*/
|
|
278
|
+
@state() private inspection?: FigureInspection
|
|
204
279
|
|
|
205
280
|
updated(changes: Map<string, unknown>) {
|
|
206
281
|
if (changes.has('figureId') || changes.has('figureVersion')) {
|
|
207
282
|
void this.reload()
|
|
208
283
|
}
|
|
284
|
+
|
|
285
|
+
/*
|
|
286
|
+
저장이 끝난 순간(dirty 가 풀림) 정본이 바뀌었으니 판정을 다시 묻는다. 저작 중(dirty)에는
|
|
287
|
+
묻지 않는다 — 서버에 있는 것은 저장 전 정본이라, 그 답은 화면에 있는 것과 다른 것을 말한다.
|
|
288
|
+
*/
|
|
289
|
+
if (changes.has('figureId') || changes.has('dirty')) {
|
|
290
|
+
void this.inspect()
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private async inspect() {
|
|
295
|
+
if (!this.figureId || this.dirty) {
|
|
296
|
+
this.inspection = undefined
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
this.inspection = await inspectFigure(this.figureId)
|
|
302
|
+
} catch (e) {
|
|
303
|
+
/* 판정을 못 받은 것을 「통과」로 두지 않는다 — 모르는 것이다. 단추는 서버가 막는다. */
|
|
304
|
+
this.inspection = undefined
|
|
305
|
+
this.failure = (e as Error).message
|
|
306
|
+
}
|
|
209
307
|
}
|
|
210
308
|
|
|
211
309
|
private async reload() {
|
|
@@ -225,57 +323,105 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
225
323
|
render() {
|
|
226
324
|
return html`
|
|
227
325
|
<section>
|
|
228
|
-
<h3>${i18next.t('label.release')}</h3>
|
|
229
|
-
${this.figureId ? this.renderRelease() : html`<p quiet>${i18next.t('text.save-the-figure-before-releasing')}</p>`}
|
|
326
|
+
<h3>${i18next.t('figure.label.release')}</h3>
|
|
327
|
+
${this.figureId ? this.renderRelease() : html`<p quiet>${i18next.t('figure.text.save-the-figure-before-releasing')}</p>`}
|
|
230
328
|
</section>
|
|
231
329
|
|
|
232
330
|
<section>
|
|
233
|
-
<h3>${i18next.t('label.released-versions')}</h3>
|
|
331
|
+
<h3>${i18next.t('figure.label.released-versions')}</h3>
|
|
234
332
|
${this.versions.length
|
|
235
333
|
? html`<ul>
|
|
236
334
|
${this.versions.map(version => this.renderVersion(version))}
|
|
237
335
|
</ul>`
|
|
238
|
-
: html`<p quiet>${i18next.t('text.nothing-released-yet')}</p>`}
|
|
336
|
+
: html`<p quiet>${i18next.t('figure.text.nothing-released-yet')}</p>`}
|
|
239
337
|
</section>
|
|
240
338
|
`
|
|
241
339
|
}
|
|
242
340
|
|
|
243
341
|
private renderRelease() {
|
|
244
342
|
const released = this.figureState === 'released'
|
|
245
|
-
|
|
343
|
+
|
|
344
|
+
/*
|
|
345
|
+
게이트가 막는 것과 알리는 것을 함께 낸다. **막는 것은 단추를 잠근다** — 눌러 보고 서버에게
|
|
346
|
+
거절당하는 것으로 알게 하지 않는다. 알리는 것은 잠그지 않고 그대로 보여 준다.
|
|
347
|
+
*/
|
|
348
|
+
const blocking = (this.inspection?.findings ?? []).filter(finding => finding.blocking)
|
|
349
|
+
const advisory = (this.inspection?.findings ?? []).filter(finding => !finding.blocking)
|
|
350
|
+
|
|
351
|
+
/*
|
|
352
|
+
── 「발행되나」에 **한 번만** 답한다 ─────────────────────────────────────
|
|
353
|
+
전에는 막는 목록의 머리가 「이것들이 발행을 막습니다」, 알리는 목록의 머리가 「발행은 되지만
|
|
354
|
+
확인해 보십시오」였다. 두 줄이 나란히 서서 화면이 「막힌다」와 「된다」를 함께 말했고, 사람이
|
|
355
|
+
「그래서 되는 건가」를 되물었다.
|
|
356
|
+
|
|
357
|
+
답은 이 한 줄이 하고, 아래 목록들은 **이유**일 뿐이다 — 그래서 목록 머리는 문장이 아니라
|
|
358
|
+
이름씨다(「고쳐야 하는 것」·「막지는 않는 것」).
|
|
359
|
+
*/
|
|
246
360
|
const why = this.dirty
|
|
247
|
-
? i18next.t('text.release-needs-a-save-first')
|
|
361
|
+
? i18next.t('figure.text.release-needs-a-save-first')
|
|
248
362
|
: released
|
|
249
|
-
? i18next.t('text.already-released-edit-to-release-again')
|
|
250
|
-
:
|
|
363
|
+
? i18next.t('figure.text.already-released-edit-to-release-again')
|
|
364
|
+
: blocking.length
|
|
365
|
+
? i18next.t('figure.text.cannot-release-now')
|
|
366
|
+
: ''
|
|
251
367
|
|
|
252
368
|
return html`
|
|
253
369
|
<div now>
|
|
254
|
-
<span state ?released=${released}>${i18next.t(released ? 'label.released' : 'label.draft')}</span>
|
|
255
|
-
<span ver>${i18next.t('text.version-number', { version: this.figureVersion ?? 0 })}</span>
|
|
370
|
+
<span state ?released=${released}>${i18next.t(released ? 'figure.label.figure-released' : 'figure.label.draft')}</span>
|
|
371
|
+
<span ver>${i18next.t('figure.text.version-number', { version: this.figureVersion ?? 0 })}</span>
|
|
256
372
|
</div>
|
|
257
373
|
|
|
258
|
-
<input note placeholder=${i18next.t('text.what-changed-in-this-release')} ?disabled=${!!why || this.busy} />
|
|
374
|
+
<input note placeholder=${i18next.t('figure.text.what-changed-in-this-release')} ?disabled=${!!why || this.busy} />
|
|
259
375
|
|
|
260
376
|
<button release ?disabled=${!!why || this.busy} @click=${() => this.release()}>
|
|
261
|
-
${this.busy ? i18next.t('text.releasing') : i18next.t('button.release')}
|
|
377
|
+
${this.busy ? i18next.t('figure.text.releasing') : i18next.t('figure.button.release-figure')}
|
|
262
378
|
</button>
|
|
263
379
|
|
|
264
380
|
${why ? html`<p why>${why}</p>` : nothing}
|
|
381
|
+
${blocking.length
|
|
382
|
+
? html`<ul gate>
|
|
383
|
+
<li head>${i18next.t('figure.text.must-fix-to-release')}</li>
|
|
384
|
+
${blocking.map(finding => this.renderFinding(finding, true))}
|
|
385
|
+
</ul>`
|
|
386
|
+
: nothing}
|
|
387
|
+
${advisory.length
|
|
388
|
+
? html`<ul gate>
|
|
389
|
+
<li head quiet>${i18next.t('figure.text.does-not-block')}</li>
|
|
390
|
+
${advisory.map(finding => this.renderFinding(finding, false))}
|
|
391
|
+
</ul>`
|
|
392
|
+
: nothing}
|
|
265
393
|
${this.failure ? html`<p failed>${this.failure}</p>` : nothing}
|
|
266
394
|
`
|
|
267
395
|
}
|
|
268
396
|
|
|
397
|
+
/**
|
|
398
|
+
* 사유 한 줄 — **잰 것 · 왜 · 어떻게** 셋을 함께 말한다.
|
|
399
|
+
*
|
|
400
|
+
* 잰 것만 보여 줬더니 「1 조각이 2 조각으로 갈라진다」에서 사람이 멈췄다. 왜 나쁜지도, 무엇을
|
|
401
|
+
* 바꾸면 되는지도 알 수 없었다. 그 셋은 형식(`figure-model` 의 gate)이 만들고 여기서는 자리만
|
|
402
|
+
* 준다 — 화면이 문장을 지으면 서버가 거절할 때와 다른 말을 하게 된다.
|
|
403
|
+
*/
|
|
404
|
+
private renderFinding(finding: FigureGateFinding, blocking: boolean) {
|
|
405
|
+
return html`
|
|
406
|
+
<li finding ?blocking=${blocking}>
|
|
407
|
+
<span msg>${finding.message}</span>
|
|
408
|
+
${finding.at ? html`<code where>${finding.at}</code>` : nothing}
|
|
409
|
+
${finding.why ? html`<span why-line>${finding.why}</span>` : nothing}
|
|
410
|
+
${finding.how ? html`<span how-line><md-icon>build</md-icon>${finding.how}</span>` : nothing}
|
|
411
|
+
</li>
|
|
412
|
+
`
|
|
413
|
+
}
|
|
414
|
+
|
|
269
415
|
private renderVersion(version: FigureVersion) {
|
|
270
416
|
return html`
|
|
271
417
|
<li>
|
|
272
|
-
<span no>${i18next.t('text.version-number', { version: version.version })}</span>
|
|
418
|
+
<span no>${i18next.t('figure.text.version-number', { version: version.version })}</span>
|
|
273
419
|
<span when>
|
|
274
420
|
${version.updatedAt ? new Date(version.updatedAt).toLocaleString() : ''}
|
|
275
421
|
${version.updater?.name ? ` · ${version.updater.name}` : ''}
|
|
276
422
|
</span>
|
|
277
423
|
<button revert ?disabled=${this.busy} @click=${() => this.revert(version.version)}>
|
|
278
|
-
${i18next.t('button.revert')}
|
|
424
|
+
${i18next.t('figure.button.revert')}
|
|
279
425
|
</button>
|
|
280
426
|
${version.comment ? html`<span comment>${version.comment}</span>` : nothing}
|
|
281
427
|
</li>
|
|
@@ -295,6 +441,7 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
295
441
|
/* 정본을 든 자리가 갱신한다 — 여기서 페이지 상태를 고쳐 쓰지 않는다. */
|
|
296
442
|
this.dispatchEvent(new CustomEvent('figure-released', { detail: { figure }, bubbles: true, composed: true }))
|
|
297
443
|
await this.reload()
|
|
444
|
+
await this.inspect()
|
|
298
445
|
} catch (e) {
|
|
299
446
|
this.failure = (e as Error).message
|
|
300
447
|
} finally {
|
|
@@ -304,7 +451,7 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
304
451
|
|
|
305
452
|
private async revert(version: number) {
|
|
306
453
|
/* 되돌아갈 수 없는 조작은 아니지만(판본은 남는다), 지금 화면의 것이 덮인다 — 이름으로 확인한다. */
|
|
307
|
-
if (!confirm(i18next.t('text.revert-to-version-confirm', { version }))) {
|
|
454
|
+
if (!confirm(i18next.t('figure.text.revert-to-version-confirm', { version }))) {
|
|
308
455
|
return
|
|
309
456
|
}
|
|
310
457
|
|
|
@@ -315,6 +462,12 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
|
|
|
315
462
|
const result = await revertFigureVersion(this.figureId!, version)
|
|
316
463
|
this.dispatchEvent(new CustomEvent('figure-reverted', { detail: result, bubbles: true, composed: true }))
|
|
317
464
|
await this.reload()
|
|
465
|
+
/*
|
|
466
|
+
**되돌리면 정본이 바뀌므로 판정도 바뀐다.** 이것을 안 하면 옛 판의 사유가 새 정본 위에
|
|
467
|
+
남아 화면이 거짓말한다 — 되돌리기는 `dirty` 도 `figureVersion` 도 건드리지 않으므로
|
|
468
|
+
`updated` 의 감시로는 다시 묻지 않는다.
|
|
469
|
+
*/
|
|
470
|
+
await this.inspect()
|
|
318
471
|
} catch (e) {
|
|
319
472
|
this.failure = (e as Error).message
|
|
320
473
|
} finally {
|