@things-factory/figure-library 10.1.207 → 10.1.208

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.
Files changed (60) hide show
  1. package/dist-client/figure-palette-group.d.ts +52 -0
  2. package/dist-client/figure-palette-group.js +41 -0
  3. package/dist-client/figure-palette-group.js.map +1 -0
  4. package/dist-client/figure-palette.d.ts +7 -0
  5. package/dist-client/figure-palette.js +49 -0
  6. package/dist-client/figure-palette.js.map +1 -0
  7. package/dist-client/item-types/index.d.ts +10 -0
  8. package/dist-client/item-types/index.js +48 -0
  9. package/dist-client/item-types/index.js.map +1 -0
  10. package/dist-client/item-types/item-types-editor.d.ts +9 -0
  11. package/dist-client/item-types/item-types-editor.js +49 -0
  12. package/dist-client/item-types/item-types-editor.js.map +1 -0
  13. package/dist-client/item-types/item-types-renderer.d.ts +2 -0
  14. package/dist-client/item-types/item-types-renderer.js +8 -0
  15. package/dist-client/item-types/item-types-renderer.js.map +1 -0
  16. package/dist-client/item-types/item-types-rows.d.ts +16 -0
  17. package/dist-client/item-types/item-types-rows.js +58 -0
  18. package/dist-client/item-types/item-types-rows.js.map +1 -0
  19. package/dist-client/item-types/ox-item-types-input.d.ts +24 -0
  20. package/dist-client/item-types/ox-item-types-input.js +284 -0
  21. package/dist-client/item-types/ox-item-types-input.js.map +1 -0
  22. package/dist-client/pages/figure-library-page.d.ts +3 -3
  23. package/dist-client/pages/figure-library-page.js +34 -5
  24. package/dist-client/pages/figure-library-page.js.map +1 -1
  25. package/dist-client/tsconfig.tsbuildinfo +1 -1
  26. package/dist-client/viewparts/figure-releases-popup.d.ts +10 -0
  27. package/dist-client/viewparts/figure-releases-popup.js +68 -0
  28. package/dist-client/viewparts/figure-releases-popup.js.map +1 -1
  29. package/dist-server/service/figure-library-release/figure-library-release.js +2 -2
  30. package/dist-server/service/figure-library-release/figure-library-release.js.map +1 -1
  31. package/dist-server/service/figure-library-resolver.d.ts +3 -0
  32. package/dist-server/service/figure-library-resolver.js +48 -2
  33. package/dist-server/service/figure-library-resolver.js.map +1 -1
  34. package/dist-server/service/figure-library-types.d.ts +2 -0
  35. package/dist-server/service/figure-library-types.js +8 -0
  36. package/dist-server/service/figure-library-types.js.map +1 -1
  37. package/dist-server/service/figure-type-map/figure-type-map-entry.d.ts +3 -0
  38. package/dist-server/service/figure-type-map/figure-type-map-entry.js +21 -0
  39. package/dist-server/service/figure-type-map/figure-type-map-entry.js.map +1 -1
  40. package/dist-server/service/library/blueprints.js +4 -0
  41. package/dist-server/service/library/blueprints.js.map +1 -1
  42. package/dist-server/service/library/extensions.js +3 -0
  43. package/dist-server/service/library/extensions.js.map +1 -1
  44. package/dist-server/service/library/figures.d.ts +8 -0
  45. package/dist-server/service/library/figures.js +5 -1
  46. package/dist-server/service/library/figures.js.map +1 -1
  47. package/dist-server/service/library/inspection.d.ts +1 -1
  48. package/dist-server/service/library/inspection.js +2 -0
  49. package/dist-server/service/library/inspection.js.map +1 -1
  50. package/dist-server/service/library/type-map.d.ts +15 -0
  51. package/dist-server/service/library/type-map.js +59 -0
  52. package/dist-server/service/library/type-map.js.map +1 -1
  53. package/dist-server/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +9 -7
  55. package/translations/en.json +27 -2
  56. package/translations/es.json +27 -2
  57. package/translations/ja.json +27 -2
  58. package/translations/ko.json +32 -7
  59. package/translations/ms.json +27 -2
  60. package/translations/zh.json +27 -2
@@ -0,0 +1,284 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ /*
3
+ * The item type table of a domain (ADR-0155), edited in a popup from a theme of type item-types (fmsim: carrier-types):
4
+ * one row per type -- code, name, the figure it is drawn by. A type has no size; an item is drawn at the size of the
5
+ * place it sits in (amendment 1). The figure is chosen from the names the domain's library marks as items (amendment
6
+ * 1 E · F), shown with their thumbnails. What does not hold is said on its row by things-scene's rule and the table is
7
+ * not confirmed until it holds; a figure written before that is no longer marked is told on its row and does not stop it.
8
+ *
9
+ * The words are the module's translations; an app whose items are called otherwise (fmsim: carriers) says them its own way.
10
+ */
11
+ import '@material/web/icon/icon.js';
12
+ import gql from 'graphql-tag';
13
+ import { css, html, LitElement, nothing } from 'lit';
14
+ import { customElement, property, state } from 'lit/decorators.js';
15
+ import { client } from '@operato/graphql';
16
+ import { i18next } from '@operato/i18n';
17
+ import { closePopup } from '@operato/popup';
18
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
19
+ import { getPathInfo } from '@operato/utils';
20
+ import { emptyRow, rowIssues } from './item-types-rows.js';
21
+ /* The names the domain draws as items, with the name and thumbnail of the release each draws with. */
22
+ const ITEM_FIGURES = gql `
23
+ query ($filters: [Filter!], $pagination: Pagination) {
24
+ figureLibraryFigures(filters: $filters, pagination: $pagination) {
25
+ items {
26
+ name
27
+ release {
28
+ name
29
+ dependencies
30
+ }
31
+ }
32
+ }
33
+ }
34
+ `;
35
+ /** As many item figures as one domain is expected to have; the picker lists them all. */
36
+ const ITEM_FIGURE_LIMIT = 500;
37
+ const t = (key, options) => i18next.t(`figure-library.item-types.${key}`, options);
38
+ let OxItemTypesInput = class OxItemTypesInput extends LitElement {
39
+ constructor() {
40
+ super(...arguments);
41
+ /** The rows as typed; the popup's own copy (see the note in ox-popup-value-map-input on re-rendered popups). */
42
+ this.rows = [];
43
+ /** The domain's item figures; null until they are read, empty when the library cannot be read or marks none. */
44
+ this.figures = null;
45
+ /** Thumbnails that could not be drawn: an empty box in their place, not a broken image. */
46
+ this.unreadThumbnails = new Set();
47
+ }
48
+ static { this.styles = [
49
+ CommonHeaderStyles,
50
+ ScrollbarStyles,
51
+ css `
52
+ :host {
53
+ display: flex;
54
+ flex-direction: column;
55
+ background-color: var(--md-sys-color-surface);
56
+ width: var(--overlay-center-large-width, 80%);
57
+ height: var(--overlay-center-large-height, 70%);
58
+ }
59
+ [body] {
60
+ flex: 1;
61
+ overflow: auto;
62
+ padding: var(--spacing-medium, 8px);
63
+ }
64
+ table {
65
+ width: 100%;
66
+ border-collapse: collapse;
67
+ font-size: var(--ui-t-body, 13px);
68
+ }
69
+ th {
70
+ text-align: left;
71
+ font-weight: 600;
72
+ color: var(--md-sys-color-on-surface-variant);
73
+ padding: 4px;
74
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
75
+ white-space: nowrap;
76
+ }
77
+ td {
78
+ padding: 2px 4px;
79
+ vertical-align: middle;
80
+ }
81
+ input,
82
+ select {
83
+ width: 100%;
84
+ box-sizing: border-box;
85
+ font: inherit;
86
+ padding: 3px 6px;
87
+ border: 1px solid var(--md-sys-color-outline-variant);
88
+ border-radius: 4px;
89
+ background: var(--md-sys-color-surface);
90
+ color: var(--md-sys-color-on-surface);
91
+ }
92
+ td[figure] {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 6px;
96
+ min-width: 220px;
97
+ }
98
+ td[figure] img,
99
+ td[figure] [no-thumb] {
100
+ flex: none;
101
+ width: 28px;
102
+ height: 28px;
103
+ object-fit: contain;
104
+ border-radius: 4px;
105
+ background: var(--md-sys-color-surface-container);
106
+ }
107
+ td[note] {
108
+ font-size: var(--ui-t-small, 11.5px);
109
+ min-width: 160px;
110
+ }
111
+ [issue] {
112
+ color: var(--md-sys-color-error);
113
+ }
114
+ [warning],
115
+ [empty] {
116
+ color: var(--md-sys-color-on-surface-variant);
117
+ }
118
+ [empty] {
119
+ margin: 0 0 var(--spacing-medium, 8px);
120
+ font-size: var(--ui-t-small, 11.5px);
121
+ }
122
+ /* The row buttons as the value map editor draws its own (ox-input-value-map). */
123
+ button[remove],
124
+ button[add] {
125
+ display: inline-flex;
126
+ align-items: center;
127
+ gap: 4px;
128
+ border: var(--button-border);
129
+ border-radius: var(--ox-input-radius, 4px);
130
+ background-color: var(--button-background-color);
131
+ padding: 2px 8px;
132
+ color: var(--button-color);
133
+ font: inherit;
134
+ cursor: pointer;
135
+ --md-icon-size: var(--fontsize-default, 14px);
136
+ }
137
+ button[remove]:hover,
138
+ button[add]:hover {
139
+ border: var(--button-activ-border);
140
+ background-color: var(--button-background-focus-color);
141
+ color: var(--md-sys-color-primary-container);
142
+ }
143
+ button[add] {
144
+ margin-top: 6px;
145
+ }
146
+ [summary] {
147
+ flex: 1;
148
+ display: flex;
149
+ align-items: center;
150
+ color: var(--md-sys-color-error);
151
+ }
152
+ `
153
+ ]; }
154
+ connectedCallback() {
155
+ super.connectedCallback();
156
+ this.fetchFigures();
157
+ }
158
+ render() {
159
+ const issues = rowIssues(this.rows);
160
+ return html `
161
+ <div body>
162
+ ${this.figures?.length === 0 ? html `<p empty>${t('no-item-figures')}</p>` : nothing}
163
+ <table>
164
+ <thead>
165
+ <tr>
166
+ <th>${t('code')}</th>
167
+ <th>${t('name')}</th>
168
+ <th>${t('figure')}</th>
169
+ <th></th>
170
+ <th></th>
171
+ </tr>
172
+ </thead>
173
+ <tbody>
174
+ ${this.rows.map((row, i) => this.renderRow(row, i, issues.get(i) ?? []))}
175
+ </tbody>
176
+ </table>
177
+ <button add @click=${this.onAdd}><md-icon>add</md-icon>${t('add')}</button>
178
+ </div>
179
+ <div class="footer">
180
+ <div summary>${issues.size ? t('fix-rows', { count: issues.size }) : nothing}</div>
181
+ <button @click=${this.onCancel} danger><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>
182
+ <button @click=${this.onConfirm} ?disabled=${issues.size > 0} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
183
+ </div>
184
+ `;
185
+ }
186
+ renderRow(row, i, issues) {
187
+ const figures = this.figures ?? [];
188
+ const chosen = figures.find(f => f.name === row.figure);
189
+ /* A figure written before that the library no longer marks as an item: kept as written, and told. */
190
+ const unmarked = !!row.figure && this.figures !== null && !chosen;
191
+ return html `<tr>
192
+ <td><input .value=${row.code} data-row=${i} data-key="code" @input=${this.onInput} /></td>
193
+ <td><input .value=${row.name} data-row=${i} data-key="name" @input=${this.onInput} /></td>
194
+ <td figure>
195
+ ${chosen?.thumbnail && !this.unreadThumbnails.has(chosen.thumbnail)
196
+ ? html `<img src=${chosen.thumbnail} alt="" @error=${() => (this.unreadThumbnails = new Set([...this.unreadThumbnails, chosen.thumbnail]))} />`
197
+ : html `<span no-thumb></span>`}
198
+ <select data-row=${i} data-key="figure" @change=${this.onInput}>
199
+ <option value="" ?selected=${!row.figure}>${t('figure-none')}</option>
200
+ ${unmarked ? html `<option value=${row.figure} selected>${row.figure}</option>` : nothing}
201
+ ${figures.map(f => html `<option value=${f.name} ?selected=${f.name === row.figure}>${f.label}</option>`)}
202
+ </select>
203
+ </td>
204
+ <td note>
205
+ ${issues.map(issue => html `<div issue>${this.issueText(issue)}</div>`)}
206
+ ${unmarked ? html `<div warning>${t('figure-not-item')}</div>` : nothing}
207
+ </td>
208
+ <td><button remove title=${t('remove')} data-row=${i} @click=${this.onRemove}><md-icon>delete</md-icon></button></td>
209
+ </tr>`;
210
+ }
211
+ issueText(issue) {
212
+ if (issue.code === 'item-type-duplicate')
213
+ return t('issue.duplicate', { rows: issue.at.map(n => n + 1).join(', ') });
214
+ return t(`issue.${issue.code.replace('item-type-', '')}`);
215
+ }
216
+ onInput(e) {
217
+ const input = e.target;
218
+ const i = Number(input.dataset.row);
219
+ const key = input.dataset.key;
220
+ this.rows = this.rows.map((r, n) => (n === i ? { ...r, [key]: input.value } : r));
221
+ }
222
+ onAdd() {
223
+ this.rows = [...this.rows, emptyRow()];
224
+ }
225
+ onRemove(e) {
226
+ const i = Number(e.currentTarget.dataset.row);
227
+ this.rows = this.rows.filter((_, n) => n !== i);
228
+ }
229
+ onCancel() {
230
+ closePopup(this);
231
+ }
232
+ onConfirm() {
233
+ if (rowIssues(this.rows).size)
234
+ return;
235
+ this.confirmCallback?.(this.rows);
236
+ closePopup(this);
237
+ }
238
+ /** The names the domain's library marks as items, by display name. None when the library cannot be read. */
239
+ async fetchFigures() {
240
+ try {
241
+ const { data } = await client.query({
242
+ query: ITEM_FIGURES,
243
+ variables: { filters: [{ name: 'item', operator: 'eq', value: true }], pagination: { page: 1, limit: ITEM_FIGURE_LIMIT } },
244
+ fetchPolicy: 'network-only'
245
+ });
246
+ const { contextPath } = getPathInfo(location.pathname);
247
+ this.figures = (data?.figureLibraryFigures?.items ?? [])
248
+ .map((item) => {
249
+ const hash = item.release?.dependencies?.find((d) => d.role === 'thumbnail')?.hash;
250
+ const display = item.release?.name;
251
+ return {
252
+ name: item.name,
253
+ label: display && display !== item.name ? `${display} — ${item.name}` : item.name,
254
+ thumbnail: hash ? `${contextPath}/figure-library-file/${hash}` : ''
255
+ };
256
+ })
257
+ .sort((a, b) => a.label.localeCompare(b.label));
258
+ }
259
+ catch {
260
+ this.figures = [];
261
+ }
262
+ }
263
+ };
264
+ __decorate([
265
+ property({ type: Array }),
266
+ __metadata("design:type", Array)
267
+ ], OxItemTypesInput.prototype, "rows", void 0);
268
+ __decorate([
269
+ property({ type: Object }),
270
+ __metadata("design:type", Function)
271
+ ], OxItemTypesInput.prototype, "confirmCallback", void 0);
272
+ __decorate([
273
+ state(),
274
+ __metadata("design:type", Object)
275
+ ], OxItemTypesInput.prototype, "figures", void 0);
276
+ __decorate([
277
+ state(),
278
+ __metadata("design:type", Object)
279
+ ], OxItemTypesInput.prototype, "unreadThumbnails", void 0);
280
+ OxItemTypesInput = __decorate([
281
+ customElement('ox-item-types-input')
282
+ ], OxItemTypesInput);
283
+ export { OxItemTypesInput };
284
+ //# sourceMappingURL=ox-item-types-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-item-types-input.js","sourceRoot":"","sources":["../../client/item-types/ox-item-types-input.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The item type table of a domain (ADR-0155), edited in a popup from a theme of type item-types (fmsim: carrier-types):\n * one row per type -- code, name, the figure it is drawn by. A type has no size; an item is drawn at the size of the\n * place it sits in (amendment 1). The figure is chosen from the names the domain's library marks as items (amendment\n * 1 E · F), shown with their thumbnails. What does not hold is said on its row by things-scene's rule and the table is\n * not confirmed until it holds; a figure written before that is no longer marked is told on its row and does not stop it.\n *\n * The words are the module's translations; an app whose items are called otherwise (fmsim: carriers) says them its own way.\n */\nimport '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\nimport { getPathInfo } from '@operato/utils'\nimport type { ItemTypeIssue } from '@hatiolab/things-scene'\n\nimport { emptyRow, rowIssues, type ItemTypeRow } from './item-types-rows.js'\n\n/* The names the domain draws as items, with the name and thumbnail of the release each draws with. */\nconst ITEM_FIGURES = gql`\n query ($filters: [Filter!], $pagination: Pagination) {\n figureLibraryFigures(filters: $filters, pagination: $pagination) {\n items {\n name\n release {\n name\n dependencies\n }\n }\n }\n }\n`\n\n/** As many item figures as one domain is expected to have; the picker lists them all. */\nconst ITEM_FIGURE_LIMIT = 500\n\ninterface ItemFigure {\n name: string\n label: string\n thumbnail: string\n}\n\nconst t = (key: string, options?: Record<string, unknown>) => i18next.t(`figure-library.item-types.${key}`, options)\n\n@customElement('ox-item-types-input')\nexport class OxItemTypesInput extends LitElement {\n static styles = [\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface);\n width: var(--overlay-center-large-width, 80%);\n height: var(--overlay-center-large-height, 70%);\n }\n [body] {\n flex: 1;\n overflow: auto;\n padding: var(--spacing-medium, 8px);\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--ui-t-body, 13px);\n }\n th {\n text-align: left;\n font-weight: 600;\n color: var(--md-sys-color-on-surface-variant);\n padding: 4px;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n white-space: nowrap;\n }\n td {\n padding: 2px 4px;\n vertical-align: middle;\n }\n input,\n select {\n width: 100%;\n box-sizing: border-box;\n font: inherit;\n padding: 3px 6px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n td[figure] {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 220px;\n }\n td[figure] img,\n td[figure] [no-thumb] {\n flex: none;\n width: 28px;\n height: 28px;\n object-fit: contain;\n border-radius: 4px;\n background: var(--md-sys-color-surface-container);\n }\n td[note] {\n font-size: var(--ui-t-small, 11.5px);\n min-width: 160px;\n }\n [issue] {\n color: var(--md-sys-color-error);\n }\n [warning],\n [empty] {\n color: var(--md-sys-color-on-surface-variant);\n }\n [empty] {\n margin: 0 0 var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 11.5px);\n }\n /* The row buttons as the value map editor draws its own (ox-input-value-map). */\n button[remove],\n button[add] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n border: var(--button-border);\n border-radius: var(--ox-input-radius, 4px);\n background-color: var(--button-background-color);\n padding: 2px 8px;\n color: var(--button-color);\n font: inherit;\n cursor: pointer;\n --md-icon-size: var(--fontsize-default, 14px);\n }\n button[remove]:hover,\n button[add]:hover {\n border: var(--button-activ-border);\n background-color: var(--button-background-focus-color);\n color: var(--md-sys-color-primary-container);\n }\n button[add] {\n margin-top: 6px;\n }\n [summary] {\n flex: 1;\n display: flex;\n align-items: center;\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n /** The rows as typed; the popup's own copy (see the note in ox-popup-value-map-input on re-rendered popups). */\n @property({ type: Array }) rows: ItemTypeRow[] = []\n @property({ type: Object }) confirmCallback?: (rows: ItemTypeRow[]) => void\n\n /** The domain's item figures; null until they are read, empty when the library cannot be read or marks none. */\n @state() private figures: ItemFigure[] | null = null\n /** Thumbnails that could not be drawn: an empty box in their place, not a broken image. */\n @state() private unreadThumbnails = new Set<string>()\n\n connectedCallback() {\n super.connectedCallback()\n this.fetchFigures()\n }\n\n render() {\n const issues = rowIssues(this.rows)\n return html`\n <div body>\n ${this.figures?.length === 0 ? html`<p empty>${t('no-item-figures')}</p>` : nothing}\n <table>\n <thead>\n <tr>\n <th>${t('code')}</th>\n <th>${t('name')}</th>\n <th>${t('figure')}</th>\n <th></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n ${this.rows.map((row, i) => this.renderRow(row, i, issues.get(i) ?? []))}\n </tbody>\n </table>\n <button add @click=${this.onAdd}><md-icon>add</md-icon>${t('add')}</button>\n </div>\n <div class=\"footer\">\n <div summary>${issues.size ? t('fix-rows', { count: issues.size }) : nothing}</div>\n <button @click=${this.onCancel} danger><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>\n <button @click=${this.onConfirm} ?disabled=${issues.size > 0} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>\n </div>\n `\n }\n\n private renderRow(row: ItemTypeRow, i: number, issues: ItemTypeIssue[]) {\n const figures = this.figures ?? []\n const chosen = figures.find(f => f.name === row.figure)\n /* A figure written before that the library no longer marks as an item: kept as written, and told. */\n const unmarked = !!row.figure && this.figures !== null && !chosen\n return html`<tr>\n <td><input .value=${row.code} data-row=${i} data-key=\"code\" @input=${this.onInput} /></td>\n <td><input .value=${row.name} data-row=${i} data-key=\"name\" @input=${this.onInput} /></td>\n <td figure>\n ${chosen?.thumbnail && !this.unreadThumbnails.has(chosen.thumbnail)\n ? html`<img src=${chosen.thumbnail} alt=\"\" @error=${() => (this.unreadThumbnails = new Set([...this.unreadThumbnails, chosen.thumbnail]))} />`\n : html`<span no-thumb></span>`}\n <select data-row=${i} data-key=\"figure\" @change=${this.onInput}>\n <option value=\"\" ?selected=${!row.figure}>${t('figure-none')}</option>\n ${unmarked ? html`<option value=${row.figure} selected>${row.figure}</option>` : nothing}\n ${figures.map(f => html`<option value=${f.name} ?selected=${f.name === row.figure}>${f.label}</option>`)}\n </select>\n </td>\n <td note>\n ${issues.map(issue => html`<div issue>${this.issueText(issue)}</div>`)}\n ${unmarked ? html`<div warning>${t('figure-not-item')}</div>` : nothing}\n </td>\n <td><button remove title=${t('remove')} data-row=${i} @click=${this.onRemove}><md-icon>delete</md-icon></button></td>\n </tr>`\n }\n\n private issueText(issue: ItemTypeIssue): string {\n if (issue.code === 'item-type-duplicate') return t('issue.duplicate', { rows: issue.at.map(n => n + 1).join(', ') })\n return t(`issue.${issue.code.replace('item-type-', '')}`)\n }\n\n private onInput(e: Event) {\n const input = e.target as HTMLInputElement | HTMLSelectElement\n const i = Number(input.dataset.row)\n const key = input.dataset.key as keyof ItemTypeRow\n this.rows = this.rows.map((r, n) => (n === i ? { ...r, [key]: input.value } : r))\n }\n\n private onAdd() {\n this.rows = [...this.rows, emptyRow()]\n }\n\n private onRemove(e: Event) {\n const i = Number((e.currentTarget as HTMLElement).dataset.row)\n this.rows = this.rows.filter((_, n) => n !== i)\n }\n\n private onCancel() {\n closePopup(this)\n }\n\n private onConfirm() {\n if (rowIssues(this.rows).size) return\n this.confirmCallback?.(this.rows)\n closePopup(this)\n }\n\n /** The names the domain's library marks as items, by display name. None when the library cannot be read. */\n private async fetchFigures() {\n try {\n const { data } = await client.query({\n query: ITEM_FIGURES,\n variables: { filters: [{ name: 'item', operator: 'eq', value: true }], pagination: { page: 1, limit: ITEM_FIGURE_LIMIT } },\n fetchPolicy: 'network-only'\n })\n const { contextPath } = getPathInfo(location.pathname)\n this.figures = (data?.figureLibraryFigures?.items ?? [])\n .map((item: any) => {\n const hash = item.release?.dependencies?.find((d: any) => d.role === 'thumbnail')?.hash\n const display = item.release?.name\n return {\n name: item.name,\n label: display && display !== item.name ? `${display} — ${item.name}` : item.name,\n thumbnail: hash ? `${contextPath}/figure-library-file/${hash}` : ''\n }\n })\n .sort((a: ItemFigure, b: ItemFigure) => a.label.localeCompare(b.label))\n } catch {\n this.figures = []\n }\n }\n}\n"]}
@@ -27,11 +27,11 @@ export declare class FigureLibraryPage extends FigureLibraryPage_base {
27
27
  /** The picture cell every catalog card draws, with the one marker this figure needs. */
28
28
  private thumbnailOf;
29
29
  /**
30
- * The one thing a card says before it is opened, the gravest first: nothing here can draw it, it does not draw its
31
- * latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.
30
+ * The one thing a card says before it is opened, the gravest first: it is archived, nothing here can draw it, it does
31
+ * not draw its latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.
32
32
  */
33
33
  private markerOf;
34
- /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」. */
34
+ /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」, and whether it is an item. */
35
35
  private metaOf;
36
36
  private openReleases;
37
37
  private openImport;
@@ -30,6 +30,8 @@ const FIGURES = gql `
30
30
  responses: figureLibraryFigures(filters: $filters, pagination: $pagination, sortings: $sortings) {
31
31
  items {
32
32
  name
33
+ archivedAt
34
+ item
33
35
  latestVersion
34
36
  releaseCount
35
37
  release {
@@ -172,6 +174,24 @@ let FigureLibraryPage = class FigureLibraryPage extends localize(i18next)(PageVi
172
174
  hidden: true,
173
175
  record: { editable: false },
174
176
  filter: { operator: 'eq', options: capabilities }
177
+ },
178
+ /* Only the names this domain draws as items (ADR-0155 개정 1 E): what an item type table picks a look from. */
179
+ {
180
+ type: 'boolean',
181
+ name: 'item',
182
+ header: i18next.t('figure-library.label.item-only'),
183
+ hidden: true,
184
+ record: { editable: false },
185
+ filter: { operator: 'eq' }
186
+ },
187
+ /* Archived figures are left out unless this box is checked (ADR-0114 결정 18, 화면; user 2026-10-22). */
188
+ {
189
+ type: 'boolean',
190
+ name: 'archived',
191
+ header: i18next.t('figure-library.label.archived'),
192
+ hidden: true,
193
+ record: { editable: false },
194
+ filter: { operator: 'eq' }
175
195
  }
176
196
  ],
177
197
  rows: {
@@ -218,10 +238,12 @@ let FigureLibraryPage = class FigureLibraryPage extends localize(i18next)(PageVi
218
238
  </ox-card-thumb>`;
219
239
  }
220
240
  /**
221
- * The one thing a card says before it is opened, the gravest first: nothing here can draw it, it does not draw its
222
- * latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.
241
+ * The one thing a card says before it is opened, the gravest first: it is archived, nothing here can draw it, it does
242
+ * not draw its latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.
223
243
  */
224
244
  markerOf(record) {
245
+ if (record?.archivedAt)
246
+ return [i18next.t('figure-library.text.archived'), 'plain'];
225
247
  const release = record?.release;
226
248
  if (!release)
227
249
  return [i18next.t('figure-library.text.format-unsupported'), 'crit'];
@@ -231,12 +253,19 @@ let FigureLibraryPage = class FigureLibraryPage extends localize(i18next)(PageVi
231
253
  return [i18next.t('figure-library.text.deprecated'), 'plain'];
232
254
  return ['', 'plain'];
233
255
  }
234
- /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」. */
256
+ /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」, and whether it is an item. */
235
257
  metaOf(record) {
236
- return record?.release ? `${record.name} · ${versionText(record.release.version)}` : record?.name ?? '';
258
+ const line = record?.release ? `${record.name} · ${versionText(record.release.version)}` : record?.name ?? '';
259
+ return record?.item ? `${line} · ${i18next.t('figure-library.text.item')}` : line;
237
260
  }
238
261
  openReleases(record) {
239
- openPopup(html `<figure-releases-popup .name=${record.name} .drawing=${record.release?.id ?? ''} @saved=${() => this.grist.fetch()}></figure-releases-popup>`, {
262
+ openPopup(html `<figure-releases-popup
263
+ .name=${record.name}
264
+ .drawing=${record.release?.id ?? ''}
265
+ .archived=${!!record.archivedAt}
266
+ .item=${!!record.item}
267
+ @saved=${() => this.grist.fetch()}
268
+ ></figure-releases-popup>`, {
240
269
  backdrop: true,
241
270
  size: 'large',
242
271
  title: i18next.t('figure-library.title.releases-of', { name: (record.release ?? record.latest).name, count: record.releaseCount })
@@ -1 +1 @@
1
- {"version":3,"file":"figure-library-page.js","sourceRoot":"","sources":["../../client/pages/figure-library-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-grist/ox-card-thumb.js'\nimport '@things-factory/figure-viewer/dist-client/figure-thumb-mark.js'\nimport '../viewparts/figure-releases-popup.js'\nimport '../viewparts/figure-package-import.js'\nimport { versionText } from '../viewparts/figure-version.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/popup'\nimport { PageView } from '@operato/shell'\nimport { CardCatalogStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { getPathInfo } from '@operato/utils'\n\n/*\n * The board server's figures (ADR-0114, amended 2026-10-12), as a card catalogue with the board catalog's card: the\n * thumbnail, the name, and one line - the full name and the version it draws with. The one thing to know before opening\n * a card is its corner marker: cannot be read here, not drawing the latest, or deprecated. Clicking a card opens its\n * releases side by side to compare them and choose the one it draws with.\n *\n * The library is expected to grow to many figures, so the list pages from the server and the filters (category,\n * capability) are drop-down lists in the filter bar beside the name search. Upload, the screen's one primary action, is\n * the FAB; it opens a popup whose drop box takes the package and says what it came to.\n */\n\nconst FIGURES = gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: figureLibraryFigures(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n name\n latestVersion\n releaseCount\n release {\n id\n name\n version\n category\n capabilities\n formatSupported\n deprecated\n dependencies\n }\n latest {\n id\n name\n version\n formatSupported\n dependencies\n }\n }\n total\n }\n }\n`\n\nconst FACETS = gql`\n query {\n figureLibraryFacets {\n categories\n uncategorized\n capabilities\n incapable\n }\n }\n`\n\n/** The filter value for a figure with no category, or one that declares no capability. */\nconst NONE = '-'\n\n@customElement('figure-library-page')\nexport class FigureLibraryPage extends localize(i18next)(PageView) {\n static styles = [\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n /* The card, its picture cell and the upload FAB: every card catalog's (ADR-0117 amendment 2026-10-13). */\n CardCatalogStyles,\n css`\n ox-filters-form {\n flex: 1;\n }\n `\n ]\n\n @state() private gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('figure-library.title'),\n search: {\n placeholder: i18next.t('figure-library.text.search'),\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n }\n }\n }\n\n render() {\n return html`\n <ox-grist class=\"page-fill\" mode=\"CARD\" .config=${this.gristConfig} .fetchHandler=${this.fetchHandler}>\n <div slot=\"headroom\">\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </ox-grist>\n\n <button fab @click=${() => this.openImport()}>\n <md-icon>upload_file</md-icon>${i18next.t('figure-library.button.upload')}\n </button>\n `\n }\n\n async pageInitialized() {\n await this.configure()\n }\n\n /*\n * The filter options are read once here (and again after an import), never per render: an async options function\n * runs on every render of the filter bar and replaces the open list's options under the pointer.\n */\n private async configure() {\n const { categories, capabilities } = await this.facets()\n this.gristConfig = {\n list: {\n thumbnail: 'thumbnail',\n fields: ['title', 'meta'],\n details: []\n },\n columns: [\n {\n type: 'image',\n name: 'thumbnail',\n record: { editable: false, renderEmpty: true, renderer: (_value, _column, record) => this.thumbnailOf(record) }\n },\n {\n type: 'string',\n name: 'title',\n record: {\n editable: false,\n renderer: (_value, _column, record) => (record.release ?? record.latest).name\n }\n },\n {\n type: 'string',\n name: 'meta',\n record: { editable: false, renderer: (_value, _column, record) => this.metaOf(record) }\n },\n { type: 'string', name: 'name', hidden: true, record: { editable: false }, filter: 'search' },\n {\n type: 'select',\n name: 'category',\n header: i18next.t('figure-library.label.category'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq', options: categories }\n },\n {\n type: 'select',\n name: 'capability',\n header: i18next.t('figure-library.label.capability'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq', options: capabilities }\n }\n ],\n rows: {\n selectable: false,\n appendable: false,\n handlers: {\n click: (_columns, _data, _column, record) => record && this.openReleases(record)\n }\n },\n pagination: { pages: [24, 48, 96] }\n }\n }\n\n async pageUpdated() {\n if (this.active) this.grist?.fetch()\n }\n\n private fetchHandler = async ({ page = 1, limit = 24, filters = [] }: FetchOption) => {\n const response = await client.query({\n query: FIGURES,\n variables: {\n /* The name search arrives as %text%; the server matches parts itself. */\n filters: filters\n .filter(filter => filter.value !== undefined && filter.value !== '' && !(Array.isArray(filter.value) && !filter.value.length))\n .map(filter => ({ ...filter, value: typeof filter.value === 'string' ? filter.value.replace(/^%|%$/g, '') : filter.value })),\n pagination: { page, limit }\n },\n fetchPolicy: 'network-only'\n })\n return { total: response.data.responses.total || 0, records: response.data.responses.items || [] }\n }\n\n /** The filter options, from what the figures that draw carry. */\n private async facets() {\n const response = await client.query({ query: FACETS, fetchPolicy: 'network-only' })\n const facets = response.data?.figureLibraryFacets ?? { categories: [], capabilities: [] }\n return {\n categories: [\n ...facets.categories.map((value: string) => ({ display: value, value })),\n ...(facets.uncategorized ? [{ display: i18next.t('figure-library.text.no-category'), value: NONE }] : [])\n ],\n capabilities: [\n ...facets.capabilities.map((value: string) => ({ display: i18next.t(`figure.label.role-${value}`, { defaultValue: value }), value })),\n ...(facets.incapable ? [{ display: i18next.t('figure-library.text.no-capability'), value: NONE }] : [])\n ]\n }\n }\n\n /** The picture cell every catalog card draws, with the one marker this figure needs. */\n private thumbnailOf(record: any) {\n const hash = (record?.release ?? record?.latest)?.dependencies?.find((d: any) => d.role === 'thumbnail')?.hash\n const { contextPath } = getPathInfo(location.pathname)\n const [badge, tone] = this.markerOf(record)\n return html`<ox-card-thumb\n src=${hash ? `${contextPath}/figure-library-file/${hash}` : ''}\n alt=${(record?.release ?? record?.latest)?.name ?? ''}\n badge=${badge}\n tone=${tone}\n >\n <figure-thumb-mark slot=\"empty\" .label=${i18next.t('figure-library.text.no-thumbnail')}></figure-thumb-mark>\n </ox-card-thumb>`\n }\n\n /**\n * The one thing a card says before it is opened, the gravest first: nothing here can draw it, it does not draw its\n * latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.\n */\n private markerOf(record: any): [string, 'plain' | 'warn' | 'crit'] {\n const release = record?.release\n if (!release) return [i18next.t('figure-library.text.format-unsupported'), 'crit']\n if (release.version !== record.latestVersion) return [i18next.t('figure-library.text.not-latest'), 'warn']\n if (release.deprecated) return [i18next.t('figure-library.text.deprecated'), 'plain']\n return ['', 'plain']\n }\n\n /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」. */\n private metaOf(record: any): string {\n return record?.release ? `${record.name} · ${versionText(record.release.version)}` : record?.name ?? ''\n }\n\n private openReleases(record: any) {\n openPopup(\n html`<figure-releases-popup .name=${record.name} .drawing=${record.release?.id ?? ''} @saved=${() => this.grist.fetch()}></figure-releases-popup>`,\n {\n backdrop: true,\n size: 'large',\n title: i18next.t('figure-library.title.releases-of', { name: (record.release ?? record.latest).name, count: record.releaseCount })\n }\n )\n }\n\n private openImport() {\n openPopup(\n html`<figure-package-import\n @imported=${async () => {\n await this.configure()\n this.grist.fetch()\n }}\n ></figure-package-import>`,\n { backdrop: true, size: 'small', closable: true, title: i18next.t('figure-library.button.upload') }\n )\n }\n}\n"]}
1
+ {"version":3,"file":"figure-library-page.js","sourceRoot":"","sources":["../../client/pages/figure-library-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-grist/ox-card-thumb.js'\nimport '@things-factory/figure-viewer/dist-client/figure-thumb-mark.js'\nimport '../viewparts/figure-releases-popup.js'\nimport '../viewparts/figure-package-import.js'\nimport { versionText } from '../viewparts/figure-version.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/popup'\nimport { PageView } from '@operato/shell'\nimport { CardCatalogStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { getPathInfo } from '@operato/utils'\n\n/*\n * The board server's figures (ADR-0114, amended 2026-10-12), as a card catalogue with the board catalog's card: the\n * thumbnail, the name, and one line - the full name and the version it draws with. The one thing to know before opening\n * a card is its corner marker: cannot be read here, not drawing the latest, or deprecated. Clicking a card opens its\n * releases side by side to compare them and choose the one it draws with.\n *\n * The library is expected to grow to many figures, so the list pages from the server and the filters (category,\n * capability) are drop-down lists in the filter bar beside the name search. Upload, the screen's one primary action, is\n * the FAB; it opens a popup whose drop box takes the package and says what it came to.\n */\n\nconst FIGURES = gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: figureLibraryFigures(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n name\n archivedAt\n item\n latestVersion\n releaseCount\n release {\n id\n name\n version\n category\n capabilities\n formatSupported\n deprecated\n dependencies\n }\n latest {\n id\n name\n version\n formatSupported\n dependencies\n }\n }\n total\n }\n }\n`\n\nconst FACETS = gql`\n query {\n figureLibraryFacets {\n categories\n uncategorized\n capabilities\n incapable\n }\n }\n`\n\n/** The filter value for a figure with no category, or one that declares no capability. */\nconst NONE = '-'\n\n@customElement('figure-library-page')\nexport class FigureLibraryPage extends localize(i18next)(PageView) {\n static styles = [\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n /* The card, its picture cell and the upload FAB: every card catalog's (ADR-0117 amendment 2026-10-13). */\n CardCatalogStyles,\n css`\n ox-filters-form {\n flex: 1;\n }\n `\n ]\n\n @state() private gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('figure-library.title'),\n search: {\n placeholder: i18next.t('figure-library.text.search'),\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n }\n }\n }\n\n render() {\n return html`\n <ox-grist class=\"page-fill\" mode=\"CARD\" .config=${this.gristConfig} .fetchHandler=${this.fetchHandler}>\n <div slot=\"headroom\">\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </ox-grist>\n\n <button fab @click=${() => this.openImport()}>\n <md-icon>upload_file</md-icon>${i18next.t('figure-library.button.upload')}\n </button>\n `\n }\n\n async pageInitialized() {\n await this.configure()\n }\n\n /*\n * The filter options are read once here (and again after an import), never per render: an async options function\n * runs on every render of the filter bar and replaces the open list's options under the pointer.\n */\n private async configure() {\n const { categories, capabilities } = await this.facets()\n this.gristConfig = {\n list: {\n thumbnail: 'thumbnail',\n fields: ['title', 'meta'],\n details: []\n },\n columns: [\n {\n type: 'image',\n name: 'thumbnail',\n record: { editable: false, renderEmpty: true, renderer: (_value, _column, record) => this.thumbnailOf(record) }\n },\n {\n type: 'string',\n name: 'title',\n record: {\n editable: false,\n renderer: (_value, _column, record) => (record.release ?? record.latest).name\n }\n },\n {\n type: 'string',\n name: 'meta',\n record: { editable: false, renderer: (_value, _column, record) => this.metaOf(record) }\n },\n { type: 'string', name: 'name', hidden: true, record: { editable: false }, filter: 'search' },\n {\n type: 'select',\n name: 'category',\n header: i18next.t('figure-library.label.category'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq', options: categories }\n },\n {\n type: 'select',\n name: 'capability',\n header: i18next.t('figure-library.label.capability'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq', options: capabilities }\n },\n /* Only the names this domain draws as items (ADR-0155 개정 1 E): what an item type table picks a look from. */\n {\n type: 'boolean',\n name: 'item',\n header: i18next.t('figure-library.label.item-only'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq' }\n },\n /* Archived figures are left out unless this box is checked (ADR-0114 결정 18, 화면; user 2026-10-22). */\n {\n type: 'boolean',\n name: 'archived',\n header: i18next.t('figure-library.label.archived'),\n hidden: true,\n record: { editable: false },\n filter: { operator: 'eq' }\n }\n ],\n rows: {\n selectable: false,\n appendable: false,\n handlers: {\n click: (_columns, _data, _column, record) => record && this.openReleases(record)\n }\n },\n pagination: { pages: [24, 48, 96] }\n }\n }\n\n async pageUpdated() {\n if (this.active) this.grist?.fetch()\n }\n\n private fetchHandler = async ({ page = 1, limit = 24, filters = [] }: FetchOption) => {\n const response = await client.query({\n query: FIGURES,\n variables: {\n /* The name search arrives as %text%; the server matches parts itself. */\n filters: filters\n .filter(filter => filter.value !== undefined && filter.value !== '' && !(Array.isArray(filter.value) && !filter.value.length))\n .map(filter => ({ ...filter, value: typeof filter.value === 'string' ? filter.value.replace(/^%|%$/g, '') : filter.value })),\n pagination: { page, limit }\n },\n fetchPolicy: 'network-only'\n })\n return { total: response.data.responses.total || 0, records: response.data.responses.items || [] }\n }\n\n /** The filter options, from what the figures that draw carry. */\n private async facets() {\n const response = await client.query({ query: FACETS, fetchPolicy: 'network-only' })\n const facets = response.data?.figureLibraryFacets ?? { categories: [], capabilities: [] }\n return {\n categories: [\n ...facets.categories.map((value: string) => ({ display: value, value })),\n ...(facets.uncategorized ? [{ display: i18next.t('figure-library.text.no-category'), value: NONE }] : [])\n ],\n capabilities: [\n ...facets.capabilities.map((value: string) => ({ display: i18next.t(`figure.label.role-${value}`, { defaultValue: value }), value })),\n ...(facets.incapable ? [{ display: i18next.t('figure-library.text.no-capability'), value: NONE }] : [])\n ]\n }\n }\n\n /** The picture cell every catalog card draws, with the one marker this figure needs. */\n private thumbnailOf(record: any) {\n const hash = (record?.release ?? record?.latest)?.dependencies?.find((d: any) => d.role === 'thumbnail')?.hash\n const { contextPath } = getPathInfo(location.pathname)\n const [badge, tone] = this.markerOf(record)\n return html`<ox-card-thumb\n src=${hash ? `${contextPath}/figure-library-file/${hash}` : ''}\n alt=${(record?.release ?? record?.latest)?.name ?? ''}\n badge=${badge}\n tone=${tone}\n >\n <figure-thumb-mark slot=\"empty\" .label=${i18next.t('figure-library.text.no-thumbnail')}></figure-thumb-mark>\n </ox-card-thumb>`\n }\n\n /**\n * The one thing a card says before it is opened, the gravest first: it is archived, nothing here can draw it, it does\n * not draw its latest release, or the release it draws is deprecated. A figure drawing its latest says nothing.\n */\n private markerOf(record: any): [string, 'plain' | 'warn' | 'crit'] {\n if (record?.archivedAt) return [i18next.t('figure-library.text.archived'), 'plain']\n const release = record?.release\n if (!release) return [i18next.t('figure-library.text.format-unsupported'), 'crit']\n if (release.version !== record.latestVersion) return [i18next.t('figure-library.text.not-latest'), 'warn']\n if (release.deprecated) return [i18next.t('figure-library.text.deprecated'), 'plain']\n return ['', 'plain']\n }\n\n /** The line under the name: the full name and the version it draws with, as a board card's 「v1 · 3일 전」, and whether it is an item. */\n private metaOf(record: any): string {\n const line = record?.release ? `${record.name} · ${versionText(record.release.version)}` : record?.name ?? ''\n return record?.item ? `${line} · ${i18next.t('figure-library.text.item')}` : line\n }\n\n private openReleases(record: any) {\n openPopup(\n html`<figure-releases-popup\n .name=${record.name}\n .drawing=${record.release?.id ?? ''}\n .archived=${!!record.archivedAt}\n .item=${!!record.item}\n @saved=${() => this.grist.fetch()}\n ></figure-releases-popup>`,\n {\n backdrop: true,\n size: 'large',\n title: i18next.t('figure-library.title.releases-of', { name: (record.release ?? record.latest).name, count: record.releaseCount })\n }\n )\n }\n\n private openImport() {\n openPopup(\n html`<figure-package-import\n @imported=${async () => {\n await this.configure()\n this.grist.fetch()\n }}\n ></figure-package-import>`,\n { backdrop: true, size: 'small', closable: true, title: i18next.t('figure-library.button.upload') }\n )\n }\n}\n"]}