@things-factory/figure-ui 10.1.254 → 10.1.257
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 +4 -3
- package/client/pages/figure-list-page.ts +7 -10
- package/dist-client/graphql/index.d.ts +1 -1
- package/dist-client/graphql/index.js +4 -3
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +4 -1
- package/dist-client/pages/figure-list-page.js +6 -10
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
package/client/graphql/index.ts
CHANGED
|
@@ -76,7 +76,7 @@ const FIGURE_LIST_FIELDS = `
|
|
|
76
76
|
* 중간에 한 벌 더 두면 격자가 아는 조건과 서버에 가는 조건이 어긋난다.
|
|
77
77
|
*/
|
|
78
78
|
/** How many of the domain's figures each state chip would show (draft, released), under the list's other conditions. */
|
|
79
|
-
export async function fetchFigureStateCounts(filters: unknown[]): Promise<
|
|
79
|
+
export async function fetchFigureStateCounts(filters: unknown[], signal?: AbortSignal): Promise<Record<string, number>> {
|
|
80
80
|
const response = await client.query({
|
|
81
81
|
query: gql`
|
|
82
82
|
query ($filters: [Filter!]) {
|
|
@@ -84,10 +84,11 @@ export async function fetchFigureStateCounts(filters: unknown[]): Promise<Map<st
|
|
|
84
84
|
}
|
|
85
85
|
`,
|
|
86
86
|
variables: { filters },
|
|
87
|
-
fetchPolicy: 'no-cache'
|
|
87
|
+
fetchPolicy: 'no-cache',
|
|
88
|
+
context: { fetchOptions: { signal }, queryDeduplication: false }
|
|
88
89
|
})
|
|
89
90
|
if (response.errors?.length) throw new Error(response.errors.map(one => one.message).join(' · '))
|
|
90
|
-
return
|
|
91
|
+
return Object.fromEntries((response.data?.figureStateCounts ?? []).map((row: { value: string; count: number }) => [row.value, row.count]))
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
export async function fetchFigureList(params: {
|
|
@@ -116,8 +116,6 @@ export class FigureListPage extends FigureListPageBase {
|
|
|
116
116
|
* only looked at, so a switch inside one list mixed two jobs. `figure-public-list-page` sets it.
|
|
117
117
|
*/
|
|
118
118
|
protected readonly scope: 'own' | 'public' = 'own'
|
|
119
|
-
/* How many figures each state chip would show, under the list's other conditions - counted by the server. */
|
|
120
|
-
private stateCounts = new Map<string, number>()
|
|
121
119
|
|
|
122
120
|
private listen?: () => void
|
|
123
121
|
|
|
@@ -154,6 +152,7 @@ export class FigureListPage extends FigureListPageBase {
|
|
|
154
152
|
@search-tag=${(e: CustomEvent) => this.findByTag(e.detail.tag)}
|
|
155
153
|
.config=${this.gristConfig}
|
|
156
154
|
.fetchHandler=${this.fetchHandler.bind(this)}
|
|
155
|
+
.countHandler=${this.scope === 'own' ? this.countHandler.bind(this) : undefined}
|
|
157
156
|
.personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}
|
|
158
157
|
>
|
|
159
158
|
<div slot="headroom" class="header">
|
|
@@ -341,7 +340,7 @@ export class FigureListPage extends FigureListPageBase {
|
|
|
341
340
|
[
|
|
342
341
|
{ display: i18next.t('figure.label.draft'), value: 'draft' },
|
|
343
342
|
{ display: i18next.t('figure.label.figure-released'), value: 'released' }
|
|
344
|
-
]
|
|
343
|
+
]
|
|
345
344
|
}
|
|
346
345
|
: undefined,
|
|
347
346
|
width: 120
|
|
@@ -544,18 +543,16 @@ export class FigureListPage extends FigureListPageBase {
|
|
|
544
543
|
* 받아 화면에 낸다 — 목록이 비어 있는 것과 못 불러온 것은 다른 사실이다.
|
|
545
544
|
*/
|
|
546
545
|
async fetchHandler({ page = 1, limit = 24, sortings = [], filters = [] }: FetchOption) {
|
|
547
|
-
if (this.scope === 'own')
|
|
548
|
-
fetchFigureStateCounts(filters)
|
|
549
|
-
.then(counts => {
|
|
550
|
-
this.stateCounts = counts
|
|
551
|
-
;(this.renderRoot.querySelector('ox-filters-form') as any)?.requestUpdate()
|
|
552
|
-
})
|
|
553
|
-
.catch(e => console.error(e))
|
|
554
546
|
const { items, total } = await fetchFigureList({ page, limit, filters, sortings, scope: this.scope })
|
|
555
547
|
|
|
556
548
|
return { total: total || 0, records: items || [] }
|
|
557
549
|
}
|
|
558
550
|
|
|
551
|
+
/** How many figures each state chip would show, under the list's other conditions - the own catalogue's only. */
|
|
552
|
+
async countHandler({ filters = [], signal }: FetchOption) {
|
|
553
|
+
return { state: await fetchFigureStateCounts(filters, signal) }
|
|
554
|
+
}
|
|
555
|
+
|
|
559
556
|
/** The modeller that can edit this figure, by its format; a new figure starts in (`modeller-route.ts`). */
|
|
560
557
|
private openModeller(figure?: Figure) {
|
|
561
558
|
navigate(modellerPathOf(figure))
|
|
@@ -8,7 +8,7 @@ import type { Figure, FigureFinding, FigureInspection, FigureListResult, FigureP
|
|
|
8
8
|
* 중간에 한 벌 더 두면 격자가 아는 조건과 서버에 가는 조건이 어긋난다.
|
|
9
9
|
*/
|
|
10
10
|
/** How many of the domain's figures each state chip would show (draft, released), under the list's other conditions. */
|
|
11
|
-
export declare function fetchFigureStateCounts(filters: unknown[]): Promise<
|
|
11
|
+
export declare function fetchFigureStateCounts(filters: unknown[], signal?: AbortSignal): Promise<Record<string, number>>;
|
|
12
12
|
export declare function fetchFigureList(params: {
|
|
13
13
|
page?: number;
|
|
14
14
|
limit?: number;
|
|
@@ -60,7 +60,7 @@ const FIGURE_LIST_FIELDS = `
|
|
|
60
60
|
* 중간에 한 벌 더 두면 격자가 아는 조건과 서버에 가는 조건이 어긋난다.
|
|
61
61
|
*/
|
|
62
62
|
/** How many of the domain's figures each state chip would show (draft, released), under the list's other conditions. */
|
|
63
|
-
export async function fetchFigureStateCounts(filters) {
|
|
63
|
+
export async function fetchFigureStateCounts(filters, signal) {
|
|
64
64
|
const response = await client.query({
|
|
65
65
|
query: gql `
|
|
66
66
|
query ($filters: [Filter!]) {
|
|
@@ -68,11 +68,12 @@ export async function fetchFigureStateCounts(filters) {
|
|
|
68
68
|
}
|
|
69
69
|
`,
|
|
70
70
|
variables: { filters },
|
|
71
|
-
fetchPolicy: 'no-cache'
|
|
71
|
+
fetchPolicy: 'no-cache',
|
|
72
|
+
context: { fetchOptions: { signal }, queryDeduplication: false }
|
|
72
73
|
});
|
|
73
74
|
if (response.errors?.length)
|
|
74
75
|
throw new Error(response.errors.map(one => one.message).join(' · '));
|
|
75
|
-
return
|
|
76
|
+
return Object.fromEntries((response.data?.figureStateCounts ?? []).map((row) => [row.value, row.count]));
|
|
76
77
|
}
|
|
77
78
|
export async function fetchFigureList(params) {
|
|
78
79
|
const field = params.scope === 'public' ? 'publicFigures' : 'figures';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../client/graphql/index.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { i18next } from '@operato/i18n'\nimport { client, uploadContext, type UploadProgress } from '@operato/graphql'\n\nimport { reached, refusedIn } from './reached.js'\n\nimport type {\n Figure,\n FigureFinding,\n FigureInspection,\n FigureListResult,\n FigurePatch,\n FigureVersion,\n NewFigure\n} from '../types.js'\n\n/**\n * 응답에서 값을 꺼낸다. **서버가 말한 사유를 그대로 올린다.**\n *\n * 전에는 `response.data.figures` 처럼 바로 꺼냈다. 서버가 오류를 돌려주면 `data` 가\n * 없으므로 `Cannot read properties of undefined (reading 'figures')` 가 났고, 화면에는\n * 그 문장이 그대로 떴다. 사용자는 자기가 무엇을 잘못했는지 알 수 없다 — 실제로 AI\n * 요청에서 그렇게 났다.\n *\n * 값이 `null` 인 것은 오류가 아니다. 지운 것을 물었을 때처럼 없는 것이 답인 경우가 있다.\n * 여기서 막는 것은 **`data` 자체가 없는 것**이다.\n */\nfunction unwrap<T>(response: { data?: Record<string, unknown>; errors?: readonly { message: string }[] }, field: string): T {\n const said = response.errors?.[0]?.message\n if (said) throw new Error(said)\n\n if (!response.data) {\n /* The field name stays off the screen because the user cannot act on it; it goes to the console. */\n console.error(`[figure-ui] the server returned no data for ${field}`)\n throw new Error(i18next.t('figure.text.server-returned-no-data'))\n }\n\n return response.data[field] as T\n}\n\n\n/**\n * 목록에 필요한 필드만 가져온다 — `source` 는 무겁고 목록에서 쓰지 않는다.\n *\n * **`thumbnail` 도 여기 없다.** base64 문자열이라 목록 응답에 실으면 카탈로그를 열 때마다 그림\n * 전부가 다시 오고(표본 14개 227KB), data URL 은 브라우저가 캐시하지 못한다. 그림은 주소로\n * 부른다(`figure-thumbnail` 라우트). 대신 `thumbnailUpdatedAt` 을 받는다 — 그림이 있나 없나를\n * 그것으로 알고, 버전을 가리는 값으로도 쓴다.\n */\nconst FIGURE_LIST_FIELDS = `\n id\n namespace\n type\n name\n description\n category\n tags\n state\n version\n deprecated\n supersededBy\n public\n score\n triangles\n groups\n thumbnailUpdatedAt\n updatedAt\n updater { id name }\n`\n\n/**\n * 목록을 가져온다.\n *\n * 걸러 보기·정렬·쪽 나누기를 **그대로 넘긴다.** 화면이 `search`·`state` 같은 이름을 따로 만들어\n * filter 로 옮기던 것을 그만두었다 — 그 이름들은 격자(ox-grist)가 이미 컬럼 설정에서 만들어 주고,\n * 중간에 한 벌 더 두면 격자가 아는 조건과 서버에 가는 조건이 어긋난다.\n */\n/** How many of the domain's figures each state chip would show (draft, released), under the list's other conditions. */\nexport async function fetchFigureStateCounts(filters: unknown[]): Promise<Map<string, number>> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!]) {\n figureStateCounts(filters: $filters) { value count }\n }\n `,\n variables: { filters },\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length) throw new Error(response.errors.map(one => one.message).join(' · '))\n return new Map((response.data?.figureStateCounts ?? []).map((row: { value: string; count: number }) => [row.value, row.count]))\n}\n\nexport async function fetchFigureList(params: {\n page?: number\n limit?: number\n filters?: unknown[]\n sortings?: { name: string; desc?: boolean }[]\n /** 'public': other domains' public figures, with their domain (LV figure-server design G2). The domain's own by default. */\n scope?: 'own' | 'public'\n}): Promise<FigureListResult> {\n const field = params.scope === 'public' ? 'publicFigures' : 'figures'\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n ${field}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items { ${FIGURE_LIST_FIELDS} ${params.scope === 'public' ? 'domain { id name subdomain }' : ''} }\n total\n }\n }\n `,\n variables: {\n filters: params.filters ?? [],\n pagination: { page: params.page ?? 1, limit: params.limit ?? 30 },\n sortings: params.sortings?.length ? params.sortings : [{ name: 'updatedAt', desc: true }]\n },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureListResult>(response, field)\n}\n\n/** 저작면에 필요한 전부 — `source` 를 포함한다. */\nexport async function fetchFigure(id: string): Promise<Figure> {\n const response = await client.query({\n query: gql`\n query ($id: String!) {\n figure(id: $id) {\n ${FIGURE_LIST_FIELDS}\n source\n properties\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<Figure>(response, 'figure')\n}\n\n/**\n * 이미 쓰이고 있는 타입 이름.\n *\n * `type` 은 만든 뒤에 고칠 수 없으므로 **만들기 전에** 알려 줘야 한다. 저장을 눌러\n * 거절당하고 나서 아는 것은 늦다.\n */\nexport async function fetchFigureTypeNames(): Promise<string[]> {\n const response = await client.query({\n query: gql`\n query {\n figureTypeNames\n }\n `,\n fetchPolicy: 'network-only'\n })\n\n return unwrap<string[] | null>(response, 'figureTypeNames') ?? []\n}\n\nexport interface SaveResult {\n figure: Figure\n /** 막지 않는 발견. 저장은 됐지만 화면이 보여 줘야 한다. */\n violations: FigureFinding[]\n}\n\nexport async function createFigure(figure: NewFigure): Promise<SaveResult> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($figure: NewFigure!) {\n createFigure(figure: $figure) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n }\n }\n `,\n variables: { figure }\n })\n\n return unwrap<SaveResult>(response, 'createFigure')\n}\n\nexport async function updateFigure(id: string, patch: FigurePatch): Promise<SaveResult> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $patch: FigurePatch!) {\n updateFigure(id: $id, patch: $patch) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n }\n }\n `,\n variables: { id, patch }\n })\n\n return unwrap<SaveResult>(response, 'updateFigure')\n}\n\n/** Makes a released figure public to other domains, or private again (LV figure-server design G2). */\nexport async function setFigurePublic(id: string, isPublic: boolean): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $public: Boolean!) {\n setFigurePublic(id: $id, public: $public) {\n ${FIGURE_LIST_FIELDS}\n }\n }\n `,\n variables: { id, public: isPublic }\n })\n\n return unwrap<Figure>(response, 'setFigurePublic')\n}\n\n/** Retires a released figure, naming the type to use instead, or brings it back. Release rows are not touched. */\nexport async function setFigureDeprecation(id: string, deprecated: boolean, supersededBy?: string | null): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $deprecated: Boolean!, $supersededBy: String) {\n setFigureDeprecation(id: $id, deprecated: $deprecated, supersededBy: $supersededBy) {\n ${FIGURE_LIST_FIELDS}\n }\n }\n `,\n variables: { id, deprecated, supersededBy: supersededBy || null }\n })\n\n return unwrap<Figure>(response, 'setFigureDeprecation')\n}\n\nexport async function deleteFigure(id: string): Promise<boolean> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n deleteFigure(id: $id)\n }\n `,\n variables: { id }\n })\n\n return unwrap<boolean>(response, 'deleteFigure')\n}\n\n/**\n * 발행한다 — 버전 번호가 오르고, 그 순간이 버전으로 남는다.\n *\n * 이미 발행된 것을 다시 발행하면 서버가 거절한다. 고쳐서 다시 내려면 저장이 먼저이고, 저장은\n * 발행을 푼다(초안으로 돌아온다).\n */\nexport async function releaseFigure(id: string, comment?: string): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ReleaseFigure($id: String!, $comment: String) {\n releaseFigure(id: $id, comment: $comment) {\n id\n version\n state\n updatedAt\n }\n }\n `,\n variables: { id, comment }\n })\n\n return unwrap<Figure>(response, 'releaseFigure')\n}\n\n/** A namespace the domain owns (LV figure-server design G1): the `{namespace}` of the full name `{namespace}/{type}`. */\nexport interface FigureNamespace {\n id: string\n name: string\n description?: string | null\n state: 'active' | 'suspended'\n isDefault: boolean\n}\n\nconst FIGURE_NAMESPACE_FIELDS = 'id name description state isDefault'\n\n/** The categories the server allows, or null when a category is free text (LV figure-server design G5). */\nexport async function fetchFigureCategories(): Promise<string[] | null> {\n const response = await client.query({\n query: gql`\n query {\n figureCategories\n }\n `,\n fetchPolicy: 'network-only'\n })\n return unwrap<string[] | null>(response, 'figureCategories') ?? null\n}\n\n/** The domain's namespaces, its default first. */\nexport async function fetchFigureNamespaces(): Promise<FigureNamespace[]> {\n const response = await client.query({\n query: gql`\n query {\n figureNamespaces { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n fetchPolicy: 'network-only'\n })\n return unwrap<FigureNamespace[]>(response, 'figureNamespaces') ?? []\n}\n\n/** Adds a namespace to the domain; the server says why when it refuses (not a namespace, another domain's). */\nexport async function createFigureNamespace(name: string, isDefault = false): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!, $isDefault: Boolean) {\n createFigureNamespace(name: $name, isDefault: $isDefault) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name, isDefault }\n })\n return unwrap<FigureNamespace>(response, 'createFigureNamespace')\n}\n\n/** Makes one of the domain's active namespaces its default. */\nexport async function setDefaultFigureNamespace(name: string): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!) {\n setDefaultFigureNamespace(name: $name) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name }\n })\n return unwrap<FigureNamespace>(response, 'setDefaultFigureNamespace')\n}\n\n/** Suspends a namespace or makes it active again. */\nexport async function setFigureNamespaceState(name: string, state: 'active' | 'suspended'): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!, $state: String!) {\n setFigureNamespaceState(name: $name, state: $state) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name, state }\n })\n return unwrap<FigureNamespace>(response, 'setFigureNamespaceState')\n}\n\n/** A draft a revert kept when it wrote over it (ADR-0097 §5.6). Not a released version. */\nexport interface KeptDraft {\n id: string\n kind: 'revert' | 'undo'\n state?: string\n version?: number\n revertedToVersion?: number\n restoredAt?: string\n createdAt?: string\n creator?: { name?: string }\n}\n\nconst KEPT_FIELDS = `id kind state version revertedToVersion restoredAt createdAt creator { name }`\n\n/**\n * 옛 버전을 초안으로 되살린다. 정본·속성·그림이 돌아오고 이름·설명은 그대로다. 덮이는 초안은 같은 트랜잭션에서 서버가\n * 보관한다. `expectedSource` 는 서버가 들고 있다고 확인된 정본 -- 그 사이 바뀌었으면 거절된다. 답을 못 받았으면\n * (REVERT_UNREACHABLE) 같은 `requestId` 로 다시 묻는다: 서버는 같은 되돌리기로 답하고 두 번 하지 않는다.\n */\nexport async function revertFigureVersion(\n id: string,\n version: number,\n requestId: string,\n expectedSource: string\n): Promise<SaveResult & { kept: KeptDraft }> {\n const response = await reached(\n client.mutate({\n mutation: gql`\n mutation RevertFigureVersion($id: String!, $version: Float!, $requestId: String!, $expectedSource: String!) {\n revertFigureVersion(id: $id, version: $version, requestId: $requestId, expectedSource: $expectedSource) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n kept { ${KEPT_FIELDS} }\n }\n }\n `,\n variables: { id, version, requestId, expectedSource }\n }),\n 'REVERT_UNREACHABLE'\n )\n refusedIn(response)\n return unwrap<SaveResult & { kept: KeptDraft }>(response, 'revertFigureVersion')\n}\n\n/** 되돌리기 취소 -- 보관한 초안을 되살린다. 되돌린 뒤 모델이 바뀌었으면 서버가 거절하고 보관본은 남는다. */\nexport async function undoFigureRevert(keptId: string, requestId: string): Promise<SaveResult & { kept: KeptDraft }> {\n const response = await reached(\n client.mutate({\n mutation: gql`\n mutation UndoFigureRevert($keptId: String!, $requestId: String!) {\n undoFigureRevert(keptId: $keptId, requestId: $requestId) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n kept { ${KEPT_FIELDS} }\n }\n }\n `,\n variables: { keptId, requestId }\n }),\n 'REVERT_UNREACHABLE'\n )\n refusedIn(response)\n return unwrap<SaveResult & { kept: KeptDraft }>(response, 'undoFigureRevert')\n}\n\n/** A figure an AI proposal was saved into (ADR-0097 §5.6 item 5). */\nexport interface ProposalOutcome {\n figureId: string\n type?: string\n name?: string\n recordedAt?: string\n}\n\n/**\n * 제안이 무엇이 됐나 -- 그 제안을 담은 저장이 들어간 피규어들. 비었으면 저장되지 않았다(적용만 하고 저장 전이거나, 되돌렸거나,\n * 적용하지 않았다). 도크의 「결과 확인」이 이것을 묻는다: 도크의 기억이 아니라 서버의 기록이다.\n */\nexport async function fetchProposalOutcome(proposalKey: string): Promise<ProposalOutcome[]> {\n const response = await client.query({\n query: gql`\n query FigureProposalOutcome($proposalKey: String!) {\n figureProposalOutcome(proposalKey: $proposalKey) { figureId type name recordedAt }\n }\n `,\n variables: { proposalKey },\n fetchPolicy: 'network-only'\n })\n return unwrap<ProposalOutcome[]>(response, 'figureProposalOutcome') ?? []\n}\n\n/** 되돌리기가 보관한 초안들, 새것부터 -- 다시 접속해도 여기서 찾는다. */\nexport async function fetchReplacedDrafts(id: string): Promise<KeptDraft[]> {\n const response = await client.query({\n query: gql`\n query FigureReplacedDrafts($id: String!) {\n figureReplacedDrafts(id: $id) { ${KEPT_FIELDS} }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n return unwrap<KeptDraft[]>(response, 'figureReplacedDrafts')\n}\n\n/**\n * 발행해도 되나 — **누르기 전에** 묻는다.\n *\n * 막는 것은 서버의 `releaseFigure` 이고 이것은 이유를 미리 보여 주기 위한 것이다. 허가증이\n * 아니므로 이 답이 통과라 해도 발행은 다시 판정을 받는다.\n */\nexport async function inspectFigure(id: string): Promise<FigureInspection> {\n const response = await client.query({\n query: gql`\n query InspectFigure($id: String!) {\n inspectFigure(id: $id) {\n blocked\n findings {\n code\n message\n why\n how\n at\n blocking\n }\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureInspection>(response, 'inspectFigure')\n}\n\n/**\n * 편집 중인 원본의 발행 판정 — 저장하지 않은 것을 잰다.\n *\n * 발행 패널의 `inspectFigure` 는 저장된 원본을 재므로 고친 결과를 저장한 뒤에야 보여 준다. 편집하면서 막히는\n * 것을 보려면 편집 중인 원본을 보내야 한다. 판정은 서버의 같은 문(`inspectAnySource`)이 하고 문장도 같다 —\n * 화면이 제 판정을 따로 가지면 두 자리가 다른 말을 한다. `id` 가 있으면 서버가 그 행의 타입과 직전 발행 버전을 읽는다.\n */\nexport async function inspectFigureDraft(source: string, id?: string): Promise<FigureInspection> {\n const response = await client.query({\n query: gql`\n query InspectFigureDraft($source: String!, $id: String) {\n inspectFigureDraft(source: $source, id: $id) {\n blocked\n findings {\n code\n message\n why\n how\n at\n blocking\n }\n }\n }\n `,\n variables: { source, id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureInspection>(response, 'inspectFigureDraft')\n}\n\n/** 발행된 버전들 — 최근 것부터 열 개. */\n/**\n * 직전 발행 버전의 정본. 한 번도 발행 안 했으면 `undefined`.\n *\n * 저작 중에 「이 고침이 이미 놓인 것을 깨나」를 그 자리에서 보여 주려면 견줄 것이 필요하다. 저장\n * 전 초안은 서버가 모르므로 판정도 화면에서 한다 — 형식의 `contractChanges` 를 같이 쓴다.\n */\nexport async function fetchReleasedSource(id: string): Promise<string | undefined> {\n return (await fetchReleasedFigure(id))?.source\n}\n\n/** Read-only catalogue preview: source and version come from the same released snapshot. */\nexport async function fetchReleasedFigure(id: string): Promise<{ version: number; source: string } | undefined> {\n const response = await client.query({\n query: gql`\n query FigureReleased($id: String!) {\n figureReleased(id: $id) {\n version\n source\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<{ version: number; source: string } | undefined>(response, 'figureReleased') ?? undefined\n}\n\nexport async function fetchFigureVersions(id: string): Promise<FigureVersion[]> {\n const response = await client.query({\n query: gql`\n query FigureVersions($id: String!) {\n figureVersions(id: $id) {\n version\n comment\n state\n updatedAt\n updater { id name }\n score\n triangles\n groups\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureVersion[]>(response, 'figureVersions') ?? []\n}\n\n/** A recipe template as the server gives it (ADR-0095, amended): words in the language asked, the recipe as JSON. */\nexport interface RecipeTemplateRow {\n name: string\n category: string\n tags: string[]\n target: 'part' | 'figure'\n title: string\n description: string\n source: string\n hasThumbnail: boolean\n}\n\nexport async function fetchRecipeTemplates(lang: string): Promise<RecipeTemplateRow[]> {\n const response = await client.query({\n query: gql`\n query ($lang: String) {\n figureRecipeTemplates(lang: $lang) {\n name\n category\n tags\n target\n title\n description\n source\n hasThumbnail\n }\n }\n `,\n variables: { lang }\n })\n return unwrap<RecipeTemplateRow[] | null>(response, 'figureRecipeTemplates') ?? []\n}\n\n/** One template's guide in the language asked, or '' while none is written. */\nexport async function fetchRecipeGuide(name: string, lang: string): Promise<string> {\n const response = await client.query({\n query: gql`\n query ($name: String!, $lang: String) {\n figureRecipeTemplate(name: $name, lang: $lang) {\n guide\n }\n }\n `,\n variables: { name, lang }\n })\n return unwrap<{ guide?: string } | null>(response, 'figureRecipeTemplate')?.guide ?? ''\n}\n\n/**\n * A GLB for a mesh part (ADR-0129): the server reads it, keeps it by its hash and answers what it holds. A file a board\n * cannot draw is refused with the reason in the screen's words.\n */\nexport async function uploadFigureMesh(file: File, onProgress: UploadProgress): Promise<import('../modeller/mesh-import.js').MeshUpload> {\n const response = await client.mutate({\n mutation: gql`\n mutation UploadFigureMesh($file: Upload!) {\n uploadFigureMesh(file: $file) {\n hash\n summary\n }\n }\n `,\n variables: { file },\n context: uploadContext(onProgress)\n })\n return unwrap(response, 'uploadFigureMesh')\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../client/graphql/index.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { i18next } from '@operato/i18n'\nimport { client, uploadContext, type UploadProgress } from '@operato/graphql'\n\nimport { reached, refusedIn } from './reached.js'\n\nimport type {\n Figure,\n FigureFinding,\n FigureInspection,\n FigureListResult,\n FigurePatch,\n FigureVersion,\n NewFigure\n} from '../types.js'\n\n/**\n * 응답에서 값을 꺼낸다. **서버가 말한 사유를 그대로 올린다.**\n *\n * 전에는 `response.data.figures` 처럼 바로 꺼냈다. 서버가 오류를 돌려주면 `data` 가\n * 없으므로 `Cannot read properties of undefined (reading 'figures')` 가 났고, 화면에는\n * 그 문장이 그대로 떴다. 사용자는 자기가 무엇을 잘못했는지 알 수 없다 — 실제로 AI\n * 요청에서 그렇게 났다.\n *\n * 값이 `null` 인 것은 오류가 아니다. 지운 것을 물었을 때처럼 없는 것이 답인 경우가 있다.\n * 여기서 막는 것은 **`data` 자체가 없는 것**이다.\n */\nfunction unwrap<T>(response: { data?: Record<string, unknown>; errors?: readonly { message: string }[] }, field: string): T {\n const said = response.errors?.[0]?.message\n if (said) throw new Error(said)\n\n if (!response.data) {\n /* The field name stays off the screen because the user cannot act on it; it goes to the console. */\n console.error(`[figure-ui] the server returned no data for ${field}`)\n throw new Error(i18next.t('figure.text.server-returned-no-data'))\n }\n\n return response.data[field] as T\n}\n\n\n/**\n * 목록에 필요한 필드만 가져온다 — `source` 는 무겁고 목록에서 쓰지 않는다.\n *\n * **`thumbnail` 도 여기 없다.** base64 문자열이라 목록 응답에 실으면 카탈로그를 열 때마다 그림\n * 전부가 다시 오고(표본 14개 227KB), data URL 은 브라우저가 캐시하지 못한다. 그림은 주소로\n * 부른다(`figure-thumbnail` 라우트). 대신 `thumbnailUpdatedAt` 을 받는다 — 그림이 있나 없나를\n * 그것으로 알고, 버전을 가리는 값으로도 쓴다.\n */\nconst FIGURE_LIST_FIELDS = `\n id\n namespace\n type\n name\n description\n category\n tags\n state\n version\n deprecated\n supersededBy\n public\n score\n triangles\n groups\n thumbnailUpdatedAt\n updatedAt\n updater { id name }\n`\n\n/**\n * 목록을 가져온다.\n *\n * 걸러 보기·정렬·쪽 나누기를 **그대로 넘긴다.** 화면이 `search`·`state` 같은 이름을 따로 만들어\n * filter 로 옮기던 것을 그만두었다 — 그 이름들은 격자(ox-grist)가 이미 컬럼 설정에서 만들어 주고,\n * 중간에 한 벌 더 두면 격자가 아는 조건과 서버에 가는 조건이 어긋난다.\n */\n/** How many of the domain's figures each state chip would show (draft, released), under the list's other conditions. */\nexport async function fetchFigureStateCounts(filters: unknown[], signal?: AbortSignal): Promise<Record<string, number>> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!]) {\n figureStateCounts(filters: $filters) { value count }\n }\n `,\n variables: { filters },\n fetchPolicy: 'no-cache',\n context: { fetchOptions: { signal }, queryDeduplication: false }\n })\n if (response.errors?.length) throw new Error(response.errors.map(one => one.message).join(' · '))\n return Object.fromEntries((response.data?.figureStateCounts ?? []).map((row: { value: string; count: number }) => [row.value, row.count]))\n}\n\nexport async function fetchFigureList(params: {\n page?: number\n limit?: number\n filters?: unknown[]\n sortings?: { name: string; desc?: boolean }[]\n /** 'public': other domains' public figures, with their domain (LV figure-server design G2). The domain's own by default. */\n scope?: 'own' | 'public'\n}): Promise<FigureListResult> {\n const field = params.scope === 'public' ? 'publicFigures' : 'figures'\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n ${field}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items { ${FIGURE_LIST_FIELDS} ${params.scope === 'public' ? 'domain { id name subdomain }' : ''} }\n total\n }\n }\n `,\n variables: {\n filters: params.filters ?? [],\n pagination: { page: params.page ?? 1, limit: params.limit ?? 30 },\n sortings: params.sortings?.length ? params.sortings : [{ name: 'updatedAt', desc: true }]\n },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureListResult>(response, field)\n}\n\n/** 저작면에 필요한 전부 — `source` 를 포함한다. */\nexport async function fetchFigure(id: string): Promise<Figure> {\n const response = await client.query({\n query: gql`\n query ($id: String!) {\n figure(id: $id) {\n ${FIGURE_LIST_FIELDS}\n source\n properties\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<Figure>(response, 'figure')\n}\n\n/**\n * 이미 쓰이고 있는 타입 이름.\n *\n * `type` 은 만든 뒤에 고칠 수 없으므로 **만들기 전에** 알려 줘야 한다. 저장을 눌러\n * 거절당하고 나서 아는 것은 늦다.\n */\nexport async function fetchFigureTypeNames(): Promise<string[]> {\n const response = await client.query({\n query: gql`\n query {\n figureTypeNames\n }\n `,\n fetchPolicy: 'network-only'\n })\n\n return unwrap<string[] | null>(response, 'figureTypeNames') ?? []\n}\n\nexport interface SaveResult {\n figure: Figure\n /** 막지 않는 발견. 저장은 됐지만 화면이 보여 줘야 한다. */\n violations: FigureFinding[]\n}\n\nexport async function createFigure(figure: NewFigure): Promise<SaveResult> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($figure: NewFigure!) {\n createFigure(figure: $figure) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n }\n }\n `,\n variables: { figure }\n })\n\n return unwrap<SaveResult>(response, 'createFigure')\n}\n\nexport async function updateFigure(id: string, patch: FigurePatch): Promise<SaveResult> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $patch: FigurePatch!) {\n updateFigure(id: $id, patch: $patch) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n }\n }\n `,\n variables: { id, patch }\n })\n\n return unwrap<SaveResult>(response, 'updateFigure')\n}\n\n/** Makes a released figure public to other domains, or private again (LV figure-server design G2). */\nexport async function setFigurePublic(id: string, isPublic: boolean): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $public: Boolean!) {\n setFigurePublic(id: $id, public: $public) {\n ${FIGURE_LIST_FIELDS}\n }\n }\n `,\n variables: { id, public: isPublic }\n })\n\n return unwrap<Figure>(response, 'setFigurePublic')\n}\n\n/** Retires a released figure, naming the type to use instead, or brings it back. Release rows are not touched. */\nexport async function setFigureDeprecation(id: string, deprecated: boolean, supersededBy?: string | null): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $deprecated: Boolean!, $supersededBy: String) {\n setFigureDeprecation(id: $id, deprecated: $deprecated, supersededBy: $supersededBy) {\n ${FIGURE_LIST_FIELDS}\n }\n }\n `,\n variables: { id, deprecated, supersededBy: supersededBy || null }\n })\n\n return unwrap<Figure>(response, 'setFigureDeprecation')\n}\n\nexport async function deleteFigure(id: string): Promise<boolean> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n deleteFigure(id: $id)\n }\n `,\n variables: { id }\n })\n\n return unwrap<boolean>(response, 'deleteFigure')\n}\n\n/**\n * 발행한다 — 버전 번호가 오르고, 그 순간이 버전으로 남는다.\n *\n * 이미 발행된 것을 다시 발행하면 서버가 거절한다. 고쳐서 다시 내려면 저장이 먼저이고, 저장은\n * 발행을 푼다(초안으로 돌아온다).\n */\nexport async function releaseFigure(id: string, comment?: string): Promise<Figure> {\n const response = await client.mutate({\n mutation: gql`\n mutation ReleaseFigure($id: String!, $comment: String) {\n releaseFigure(id: $id, comment: $comment) {\n id\n version\n state\n updatedAt\n }\n }\n `,\n variables: { id, comment }\n })\n\n return unwrap<Figure>(response, 'releaseFigure')\n}\n\n/** A namespace the domain owns (LV figure-server design G1): the `{namespace}` of the full name `{namespace}/{type}`. */\nexport interface FigureNamespace {\n id: string\n name: string\n description?: string | null\n state: 'active' | 'suspended'\n isDefault: boolean\n}\n\nconst FIGURE_NAMESPACE_FIELDS = 'id name description state isDefault'\n\n/** The categories the server allows, or null when a category is free text (LV figure-server design G5). */\nexport async function fetchFigureCategories(): Promise<string[] | null> {\n const response = await client.query({\n query: gql`\n query {\n figureCategories\n }\n `,\n fetchPolicy: 'network-only'\n })\n return unwrap<string[] | null>(response, 'figureCategories') ?? null\n}\n\n/** The domain's namespaces, its default first. */\nexport async function fetchFigureNamespaces(): Promise<FigureNamespace[]> {\n const response = await client.query({\n query: gql`\n query {\n figureNamespaces { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n fetchPolicy: 'network-only'\n })\n return unwrap<FigureNamespace[]>(response, 'figureNamespaces') ?? []\n}\n\n/** Adds a namespace to the domain; the server says why when it refuses (not a namespace, another domain's). */\nexport async function createFigureNamespace(name: string, isDefault = false): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!, $isDefault: Boolean) {\n createFigureNamespace(name: $name, isDefault: $isDefault) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name, isDefault }\n })\n return unwrap<FigureNamespace>(response, 'createFigureNamespace')\n}\n\n/** Makes one of the domain's active namespaces its default. */\nexport async function setDefaultFigureNamespace(name: string): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!) {\n setDefaultFigureNamespace(name: $name) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name }\n })\n return unwrap<FigureNamespace>(response, 'setDefaultFigureNamespace')\n}\n\n/** Suspends a namespace or makes it active again. */\nexport async function setFigureNamespaceState(name: string, state: 'active' | 'suspended'): Promise<FigureNamespace> {\n const response = await client.mutate({\n mutation: gql`\n mutation ($name: String!, $state: String!) {\n setFigureNamespaceState(name: $name, state: $state) { ${FIGURE_NAMESPACE_FIELDS} }\n }\n `,\n variables: { name, state }\n })\n return unwrap<FigureNamespace>(response, 'setFigureNamespaceState')\n}\n\n/** A draft a revert kept when it wrote over it (ADR-0097 §5.6). Not a released version. */\nexport interface KeptDraft {\n id: string\n kind: 'revert' | 'undo'\n state?: string\n version?: number\n revertedToVersion?: number\n restoredAt?: string\n createdAt?: string\n creator?: { name?: string }\n}\n\nconst KEPT_FIELDS = `id kind state version revertedToVersion restoredAt createdAt creator { name }`\n\n/**\n * 옛 버전을 초안으로 되살린다. 정본·속성·그림이 돌아오고 이름·설명은 그대로다. 덮이는 초안은 같은 트랜잭션에서 서버가\n * 보관한다. `expectedSource` 는 서버가 들고 있다고 확인된 정본 -- 그 사이 바뀌었으면 거절된다. 답을 못 받았으면\n * (REVERT_UNREACHABLE) 같은 `requestId` 로 다시 묻는다: 서버는 같은 되돌리기로 답하고 두 번 하지 않는다.\n */\nexport async function revertFigureVersion(\n id: string,\n version: number,\n requestId: string,\n expectedSource: string\n): Promise<SaveResult & { kept: KeptDraft }> {\n const response = await reached(\n client.mutate({\n mutation: gql`\n mutation RevertFigureVersion($id: String!, $version: Float!, $requestId: String!, $expectedSource: String!) {\n revertFigureVersion(id: $id, version: $version, requestId: $requestId, expectedSource: $expectedSource) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n kept { ${KEPT_FIELDS} }\n }\n }\n `,\n variables: { id, version, requestId, expectedSource }\n }),\n 'REVERT_UNREACHABLE'\n )\n refusedIn(response)\n return unwrap<SaveResult & { kept: KeptDraft }>(response, 'revertFigureVersion')\n}\n\n/** 되돌리기 취소 -- 보관한 초안을 되살린다. 되돌린 뒤 모델이 바뀌었으면 서버가 거절하고 보관본은 남는다. */\nexport async function undoFigureRevert(keptId: string, requestId: string): Promise<SaveResult & { kept: KeptDraft }> {\n const response = await reached(\n client.mutate({\n mutation: gql`\n mutation UndoFigureRevert($keptId: String!, $requestId: String!) {\n undoFigureRevert(keptId: $keptId, requestId: $requestId) {\n figure { ${FIGURE_LIST_FIELDS} source }\n violations { code message at }\n kept { ${KEPT_FIELDS} }\n }\n }\n `,\n variables: { keptId, requestId }\n }),\n 'REVERT_UNREACHABLE'\n )\n refusedIn(response)\n return unwrap<SaveResult & { kept: KeptDraft }>(response, 'undoFigureRevert')\n}\n\n/** A figure an AI proposal was saved into (ADR-0097 §5.6 item 5). */\nexport interface ProposalOutcome {\n figureId: string\n type?: string\n name?: string\n recordedAt?: string\n}\n\n/**\n * 제안이 무엇이 됐나 -- 그 제안을 담은 저장이 들어간 피규어들. 비었으면 저장되지 않았다(적용만 하고 저장 전이거나, 되돌렸거나,\n * 적용하지 않았다). 도크의 「결과 확인」이 이것을 묻는다: 도크의 기억이 아니라 서버의 기록이다.\n */\nexport async function fetchProposalOutcome(proposalKey: string): Promise<ProposalOutcome[]> {\n const response = await client.query({\n query: gql`\n query FigureProposalOutcome($proposalKey: String!) {\n figureProposalOutcome(proposalKey: $proposalKey) { figureId type name recordedAt }\n }\n `,\n variables: { proposalKey },\n fetchPolicy: 'network-only'\n })\n return unwrap<ProposalOutcome[]>(response, 'figureProposalOutcome') ?? []\n}\n\n/** 되돌리기가 보관한 초안들, 새것부터 -- 다시 접속해도 여기서 찾는다. */\nexport async function fetchReplacedDrafts(id: string): Promise<KeptDraft[]> {\n const response = await client.query({\n query: gql`\n query FigureReplacedDrafts($id: String!) {\n figureReplacedDrafts(id: $id) { ${KEPT_FIELDS} }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n return unwrap<KeptDraft[]>(response, 'figureReplacedDrafts')\n}\n\n/**\n * 발행해도 되나 — **누르기 전에** 묻는다.\n *\n * 막는 것은 서버의 `releaseFigure` 이고 이것은 이유를 미리 보여 주기 위한 것이다. 허가증이\n * 아니므로 이 답이 통과라 해도 발행은 다시 판정을 받는다.\n */\nexport async function inspectFigure(id: string): Promise<FigureInspection> {\n const response = await client.query({\n query: gql`\n query InspectFigure($id: String!) {\n inspectFigure(id: $id) {\n blocked\n findings {\n code\n message\n why\n how\n at\n blocking\n }\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureInspection>(response, 'inspectFigure')\n}\n\n/**\n * 편집 중인 원본의 발행 판정 — 저장하지 않은 것을 잰다.\n *\n * 발행 패널의 `inspectFigure` 는 저장된 원본을 재므로 고친 결과를 저장한 뒤에야 보여 준다. 편집하면서 막히는\n * 것을 보려면 편집 중인 원본을 보내야 한다. 판정은 서버의 같은 문(`inspectAnySource`)이 하고 문장도 같다 —\n * 화면이 제 판정을 따로 가지면 두 자리가 다른 말을 한다. `id` 가 있으면 서버가 그 행의 타입과 직전 발행 버전을 읽는다.\n */\nexport async function inspectFigureDraft(source: string, id?: string): Promise<FigureInspection> {\n const response = await client.query({\n query: gql`\n query InspectFigureDraft($source: String!, $id: String) {\n inspectFigureDraft(source: $source, id: $id) {\n blocked\n findings {\n code\n message\n why\n how\n at\n blocking\n }\n }\n }\n `,\n variables: { source, id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureInspection>(response, 'inspectFigureDraft')\n}\n\n/** 발행된 버전들 — 최근 것부터 열 개. */\n/**\n * 직전 발행 버전의 정본. 한 번도 발행 안 했으면 `undefined`.\n *\n * 저작 중에 「이 고침이 이미 놓인 것을 깨나」를 그 자리에서 보여 주려면 견줄 것이 필요하다. 저장\n * 전 초안은 서버가 모르므로 판정도 화면에서 한다 — 형식의 `contractChanges` 를 같이 쓴다.\n */\nexport async function fetchReleasedSource(id: string): Promise<string | undefined> {\n return (await fetchReleasedFigure(id))?.source\n}\n\n/** Read-only catalogue preview: source and version come from the same released snapshot. */\nexport async function fetchReleasedFigure(id: string): Promise<{ version: number; source: string } | undefined> {\n const response = await client.query({\n query: gql`\n query FigureReleased($id: String!) {\n figureReleased(id: $id) {\n version\n source\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<{ version: number; source: string } | undefined>(response, 'figureReleased') ?? undefined\n}\n\nexport async function fetchFigureVersions(id: string): Promise<FigureVersion[]> {\n const response = await client.query({\n query: gql`\n query FigureVersions($id: String!) {\n figureVersions(id: $id) {\n version\n comment\n state\n updatedAt\n updater { id name }\n score\n triangles\n groups\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'network-only'\n })\n\n return unwrap<FigureVersion[]>(response, 'figureVersions') ?? []\n}\n\n/** A recipe template as the server gives it (ADR-0095, amended): words in the language asked, the recipe as JSON. */\nexport interface RecipeTemplateRow {\n name: string\n category: string\n tags: string[]\n target: 'part' | 'figure'\n title: string\n description: string\n source: string\n hasThumbnail: boolean\n}\n\nexport async function fetchRecipeTemplates(lang: string): Promise<RecipeTemplateRow[]> {\n const response = await client.query({\n query: gql`\n query ($lang: String) {\n figureRecipeTemplates(lang: $lang) {\n name\n category\n tags\n target\n title\n description\n source\n hasThumbnail\n }\n }\n `,\n variables: { lang }\n })\n return unwrap<RecipeTemplateRow[] | null>(response, 'figureRecipeTemplates') ?? []\n}\n\n/** One template's guide in the language asked, or '' while none is written. */\nexport async function fetchRecipeGuide(name: string, lang: string): Promise<string> {\n const response = await client.query({\n query: gql`\n query ($name: String!, $lang: String) {\n figureRecipeTemplate(name: $name, lang: $lang) {\n guide\n }\n }\n `,\n variables: { name, lang }\n })\n return unwrap<{ guide?: string } | null>(response, 'figureRecipeTemplate')?.guide ?? ''\n}\n\n/**\n * A GLB for a mesh part (ADR-0129): the server reads it, keeps it by its hash and answers what it holds. A file a board\n * cannot draw is refused with the reason in the screen's words.\n */\nexport async function uploadFigureMesh(file: File, onProgress: UploadProgress): Promise<import('../modeller/mesh-import.js').MeshUpload> {\n const response = await client.mutate({\n mutation: gql`\n mutation UploadFigureMesh($file: Upload!) {\n uploadFigureMesh(file: $file) {\n hash\n summary\n }\n }\n `,\n variables: { file },\n context: uploadContext(onProgress)\n })\n return unwrap(response, 'uploadFigureMesh')\n}\n"]}
|
|
@@ -36,7 +36,6 @@ export declare class FigureListPage extends FigureListPageBase {
|
|
|
36
36
|
* only looked at, so a switch inside one list mixed two jobs. `figure-public-list-page` sets it.
|
|
37
37
|
*/
|
|
38
38
|
protected readonly scope: 'own' | 'public';
|
|
39
|
-
private stateCounts;
|
|
40
39
|
private listen?;
|
|
41
40
|
get context(): {
|
|
42
41
|
title: string;
|
|
@@ -75,6 +74,10 @@ export declare class FigureListPage extends FigureListPageBase {
|
|
|
75
74
|
total: number;
|
|
76
75
|
records: Figure[];
|
|
77
76
|
}>;
|
|
77
|
+
/** How many figures each state chip would show, under the list's other conditions - the own catalogue's only. */
|
|
78
|
+
countHandler({ filters, signal }: FetchOption): Promise<{
|
|
79
|
+
state: Record<string, number>;
|
|
80
|
+
}>;
|
|
78
81
|
/** The modeller that can edit this figure, by its format; a new figure starts in (`modeller-route.ts`). */
|
|
79
82
|
private openModeller;
|
|
80
83
|
/** `remove` 는 HTMLElement 의 메서드다 — 가리면 조용한 결함이 된다. */
|
|
@@ -78,8 +78,6 @@ let FigureListPage = class FigureListPage extends FigureListPageBase {
|
|
|
78
78
|
* only looked at, so a switch inside one list mixed two jobs. `figure-public-list-page` sets it.
|
|
79
79
|
*/
|
|
80
80
|
this.scope = 'own';
|
|
81
|
-
/* How many figures each state chip would show, under the list's other conditions - counted by the server. */
|
|
82
|
-
this.stateCounts = new Map();
|
|
83
81
|
this.cardsChanged = () => {
|
|
84
82
|
if (this.active)
|
|
85
83
|
this.grist?.fetch();
|
|
@@ -142,6 +140,7 @@ let FigureListPage = class FigureListPage extends FigureListPageBase {
|
|
|
142
140
|
@search-tag=${(e) => this.findByTag(e.detail.tag)}
|
|
143
141
|
.config=${this.gristConfig}
|
|
144
142
|
.fetchHandler=${this.fetchHandler.bind(this)}
|
|
143
|
+
.countHandler=${this.scope === 'own' ? this.countHandler.bind(this) : undefined}
|
|
145
144
|
.personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')}
|
|
146
145
|
>
|
|
147
146
|
<div slot="headroom" class="header">
|
|
@@ -320,7 +319,7 @@ let FigureListPage = class FigureListPage extends FigureListPageBase {
|
|
|
320
319
|
options: () => [
|
|
321
320
|
{ display: i18next.t('figure.label.draft'), value: 'draft' },
|
|
322
321
|
{ display: i18next.t('figure.label.figure-released'), value: 'released' }
|
|
323
|
-
]
|
|
322
|
+
]
|
|
324
323
|
}
|
|
325
324
|
: undefined,
|
|
326
325
|
width: 120
|
|
@@ -510,16 +509,13 @@ let FigureListPage = class FigureListPage extends FigureListPageBase {
|
|
|
510
509
|
* 받아 화면에 낸다 — 목록이 비어 있는 것과 못 불러온 것은 다른 사실이다.
|
|
511
510
|
*/
|
|
512
511
|
async fetchHandler({ page = 1, limit = 24, sortings = [], filters = [] }) {
|
|
513
|
-
if (this.scope === 'own')
|
|
514
|
-
fetchFigureStateCounts(filters)
|
|
515
|
-
.then(counts => {
|
|
516
|
-
this.stateCounts = counts;
|
|
517
|
-
this.renderRoot.querySelector('ox-filters-form')?.requestUpdate();
|
|
518
|
-
})
|
|
519
|
-
.catch(e => console.error(e));
|
|
520
512
|
const { items, total } = await fetchFigureList({ page, limit, filters, sortings, scope: this.scope });
|
|
521
513
|
return { total: total || 0, records: items || [] };
|
|
522
514
|
}
|
|
515
|
+
/** How many figures each state chip would show, under the list's other conditions - the own catalogue's only. */
|
|
516
|
+
async countHandler({ filters = [], signal }) {
|
|
517
|
+
return { state: await fetchFigureStateCounts(filters, signal) };
|
|
518
|
+
}
|
|
523
519
|
/** The modeller that can edit this figure, by its format; a new figure starts in (`modeller-route.ts`). */
|
|
524
520
|
openModeller(figure) {
|
|
525
521
|
navigate(modellerPathOf(figure));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-list-page.js","sourceRoot":"","sources":["../../client/pages/figure-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@material/web/icon/icon.js'\nimport '../viewparts/figure-thumb.js'\n\nimport { css, html, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport type { DataGrist, FetchOption } from '@operato/data-grist'\nimport { i18next, localize } from '@operato/i18n'\nimport { p13n } from '@operato/p13n'\nimport { auth } from '@things-factory/auth-base/dist-client'\nimport { navigate, PageView } from '@operato/shell'\nimport { notify } from '@operato/layout'\nimport { CardCatalogStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\n\nimport { capacityFrom } from '../modeller/scene-budget.js'\nimport { deleteFigure, fetchFigureList, fetchFigureStateCounts } from '../graphql/index.js'\nimport type { Figure } from '../types.js'\nimport { hasBeenReleased } from '../figure-released.js'\nimport { modellerPathOf } from '../modeller/modeller-route.js'\nimport { FIGURE_PUBLIC_CHANGED, FIGURE_RETIREMENT_CHANGED, FIGURE_THUMBNAIL_CHANGED, openFigureDetail } from '../viewparts/figure-detail-dock.js'\n\n/**\n * 이 값 아래면 점수를 색으로 눈에 띄게 한다.\n *\n * **등급 경계가 아니다.** 등급(A~D)은 `figure-model` 의 `scoreOf` 가 정하고 화면은 그것을\n * 베끼지 않는다. 이것은 「눈에 걸리게 할 선」이고, 화면의 판단이다.\n */\nconst ATTENTION_BELOW = 50\n\n/*\n * ── renderer 가 그리는 것은 이 파일의 CSS 가 닿지 않는다 ──────────────────────\n *\n * 컬럼 renderer 의 결과는 `ox-card-field` 의 shadow root 안에 그려진다. 이 페이지의 `static\n * styles` 는 그 경계를 넘지 못하므로 `code[figure-type]` 같은 선택자는 **아무 일도 하지 않는다.**\n * 넘어가는 것은 custom property 뿐이라, 색과 글꼴은 여기서 인라인으로 준다 — 값 자체는 테마\n * 토큰을 가리키므로 밝음·어둠은 따라온다. data-grist 의 image renderer 도 같은 방식이다.\n */\nconst CAPACITY = 'font-weight: 700; color: var(--md-sys-color-primary);'\nconst UNMEASURED = 'font-style: italic; color: var(--md-sys-color-outline);'\nconst RELEASED = 'font-weight: 700; color: var(--md-sys-color-primary);'\nconst DRAFT = 'color: var(--md-sys-color-tertiary);'\n/**\n * 조용히 적는 숫자. 낮은 것만 점으로 눈에 걸리게 한다.\n *\n * **`inline-flex` 를 쓰지 않는다.** 썼더니 점이 뜨는 카드에서만 이 값이 옆의 두 값과 밑줄이\n * 어긋났다 — inline-flex 상자의 밑줄은 **첫 항목**에서 오는데, 첫 항목이 글자 없는 점이라\n * 밑줄이 없어 브라우저가 상자 아래를 밑줄로 삼는다. 점이 없는 카드(50 이상)는 멀쩡했으므로\n * 한 줄에 세 값이 나란히 설 때만 눈에 띄었다.\n *\n * 그냥 인라인으로 두면 이 상자의 밑줄이 곧 숫자의 밑줄이라 옆의 둘과 맞는다. 점은 제 몫으로\n * 글자 가운데에 맞춘다.\n */\nconst SCORE = 'font-variant-numeric: tabular-nums;'\nconst LOW_DOT =\n 'display: inline-block; width: 5px; height: 5px; margin-right: 4px; vertical-align: middle; ' +\n 'border-radius: 50%; background-color: var(--md-sys-color-error);'\n\n/*\n * `as typeof PageView` 로 조이지 않는다 — 그렇게 하면 p13n 이 얹어 주는\n * `getPagePreferenceProvider` 가 타입에서 사라져 개인 설정을 붙일 수 없다.\n */\nconst FigureListPageBase = p13n(localize(i18next)(PageView))\n\n/**\n * Figure 카탈로그.\n *\n * 카드를 고르면 상세 패널에서 저장본과 발행 버전을 살펴본다. 크기와 움직임을 시험한 뒤\n * 「편집 화면 열기」로 저작면에 들어간다. 목록 질의는 자산 원본을 싣지 않는다.\n *\n * ## 왜 손으로 만든 카드가 아니라 격자인가\n *\n * 전에는 카드 격자와 걸러 보기 줄과 빈 화면을 이 파일이 직접 그렸다(200줄). 그 자리에서 빠져\n * 있던 것들은 하나같이 `ox-grist` 가 이미 가진 것이다 — 쪽 나누기, 정렬, 컬럼 걸러 보기,\n * 개인 설정(모드·정렬·쪽 크기를 사람마다 기억한다), 표 모드로 바꿔 보기, 내보내기.\n * 손으로 만든 카드는 그 중 아무것도 없었고, 목록이 늘어나면 전부 한 번에 그렸다.\n *\n * 카드에 실을 것은 `list` 가 정하고, 무엇을 어떻게 그릴지는 컬럼의 renderer 가 정한다. 같은\n * 설정이 표 모드에서도 그대로 쓰이므로 **두 모드가 다른 말을 하지 않는다.**\n */\n@customElement('figure-list-page')\nexport class FigureListPage extends FigureListPageBase {\n static styles = [\n /* The frame owns the page shell; the grist is the content it sizes (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n CardCatalogStyles,\n css`\n :host {\n background-color: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n\n /*\n 카드 · 그림 칸 · 만들기 FAB 는 모든 카드 카탈로그와 같다(@operato/styles CardCatalogStyles,\n ADR-0117 개정 2026-10-13). 여기에는 이 화면에만 있는 것만 둔다.\n */\n ox-grist {\n /* 상태와 성숙도는 짧은 표식이다 — 두 줄로 세우지 않고 한 줄에 뉜다 */\n --data-card-detail-direction: row;\n /* 표 모드의 맨 위로 단추도 만들기 단추 위로 비킨다 */\n --data-list-fab-position-vertical: 64px;\n }\n `\n ]\n\n @property({ type: Object }) gristConfig: any\n\n @query('ox-grist') private grist!: DataGrist\n\n /**\n * The domain's own figures, or other domains' public ones (LV figure-server design G2), read only. Each is a screen\n * of its own on the rail (user 2026-10-19): the own catalogue is where figures are made and changed, the public one\n * only looked at, so a switch inside one list mixed two jobs. `figure-public-list-page` sets it.\n */\n protected readonly scope: 'own' | 'public' = 'own'\n /* How many figures each state chip would show, under the list's other conditions - counted by the server. */\n private stateCounts = new Map<string, number>()\n\n private listen?: () => void\n\n get context() {\n return {\n title: i18next.t(this.scope === 'public' ? 'figure.title.public-figures' : 'figure.title.figures'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || '',\n placeholder: i18next.t('figure.text.search-figure')\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n }\n /*\n **만들기는 `actions` 가 아니라 FAB 이다.**\n\n `context.actions` 로 두면 페이지 바닥 줄에 글자 단추로 서는데, 그 줄은 「지금 화면에 대해\n 할 일」을 늘어놓는 자리다. 만들기는 이 화면의 유일한 주된 동작이므로 줄에 섞이지 않고\n 떠 있어야 한다. 카드를 가리지 않는 오른쪽 아래, 손이 가는 자리다(아래 render 의 [fab]).\n */\n }\n }\n\n render() {\n return html`\n <ox-grist\n class=\"page-fill\"\n mode=\"CARD\"\n @search-tag=${(e: CustomEvent) => this.findByTag(e.detail.tag)}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n\n ${this.scope === 'own'\n ? html`<button fab title=${i18next.t('figure.button.new-figure')} @click=${() => this.openModeller()}>\n <md-icon>add</md-icon>${i18next.t('figure.button.new-figure')}\n </button>`\n : nothing}\n `\n }\n\n /**\n * 카드의 태그 알약을 눌렀다 — **그 태그로 목록을 거른다.**\n *\n * 검색창에 그 말을 채워 넣는다. 격자에 조건만 걸고 창을 비워 두면 저작자는 **왜 목록이\n * 줄었는지 모른 채** 보게 되고, 되돌리려면 무엇을 지워야 하는지도 알 수 없다.\n *\n * 서버가 `tags` 뿐 아니라 이름·타입·설명·분류를 함께 훑으므로, 그 말이 다른 칸에 든 피규어도\n * 같이 온다. 태그만 정확히 거르는 것이 아니라 **찾기**다.\n */\n private findByTag(tag: string) {\n this.grist.searchText = tag\n /* 창의 값은 `context` 에서 나온다 — 다시 알려야 헤더가 새 값을 그린다. */\n this.updateContext()\n }\n\n async pageInitialized() {\n this.gristConfig = {\n /*\n **쪽 나누기는 선택이 아니다.** 격자에 가상 스크롤이 없어 받은 것을 전부 DOM 에 그린다.\n 카드 모드는 끝까지 내려가면 다음 쪽을 이어 붙이므로, 한 쪽이 작아도 목록은 계속 읽힌다.\n */\n pagination: { pages: [24, 48, 96] },\n\n /*\n 아직 아무것도 없을 때 하는 말. **이 자리가 이 화면에서 가장 중요하다** — 처음 온 사람은\n 여기서 이 도구가 무엇을 만드는 것인지 알게 된다. 조건이 걸려 비었을 때는 격자가 스스로\n 다른 말을 한다(「찾는 것이 없다」). 그 둘을 섞지 않는 것이 격자 쪽에 이미 들어 있다.\n */\n emptyNote: {\n icon: 'deployed_code',\n title: i18next.t('figure.text.no-figure-yet'),\n description: i18next.t('figure.text.what-a-figure-is')\n },\n\n list: {\n /* 그림 칸은 그 컬럼의 renderer 가 그린다 — 그림 없을 때의 안내까지 `figure-thumb` 안이다 */\n thumbnail: 'thumbnail',\n fields: ['name', 'type'],\n /*\n ── 무게를 모른 채 고르게 두지 않는다 ────────────────────────────────\n 이름과 그림만 실으면 저작자는 **이 형상이 무거운지 모른 채** 고른다. 그것을 저작면에\n 들어가서야 아는 것은 늦다. 그래서 격자로 옮기기 전 손 카드가 실었던 셋을 그대로 싣는다 —\n 몇 개까지 놓을 수 있나(배치 한도) · 성숙도 · 삼각형 수.\n\n 한 줄에 뉜다(`--data-card-detail-direction: row`). 이름표는 달지 않는다 — 값 자체가\n 「625개까지」·「삼각형 440개」로 읽히고, 성숙도만 숫자 하나여서 손이 갔을 때 이름이 뜬다.\n\n 상태는 이 줄에 없다. 그림 위 초안 표시가 그 일을 한다(`figure-thumb`) — 발행된 것에는\n 아무 말도 하지 않으므로 빈 칸이 생기지 않는다.\n */\n details: ['capacity', 'score', 'triangles']\n },\n\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n {\n /*\n 표 모드에서만 쓰는 삭제 칸. 카드에서는 `figure-thumb` 이 그림 위에 그리므로\n `forList: false` 로 내린다 — 카드 아래 단추 줄은 감춰도 자리가 남는다.\n */\n type: 'gutter',\n gutterName: 'button',\n icon: 'delete',\n title: i18next.t('figure.button.delete-figure'),\n danger: true,\n forList: false,\n width: 40,\n handlers: {\n click: (_columns: any, _data: any, _column: any, record: Figure) => this.removeFigure(record)\n }\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('figure.label.name'),\n record: { editable: false },\n filter: 'search',\n sortable: true,\n width: 200\n },\n {\n /*\n 타입 이름은 **저장되는 식별자**다. 표시 이름과 다르게 보이게 두어야 도면이 무엇으로\n 이 형상을 찾는지 헷갈리지 않는다.\n */\n type: 'string',\n name: 'type',\n header: i18next.t('figure.label.figure-type'),\n record: {\n editable: false,\n /* The full name a board stores: {namespace}/{type} (ADR-0114). */\n renderer: (value: string, column: unknown, record: { namespace?: string }) =>\n html`<code>${record?.namespace ? `${record.namespace}/${value}` : value}</code>`\n },\n filter: 'search',\n sortable: true,\n width: 160\n },\n {\n /*\n 태그 — **카드에서 곁줄로 보이고 검색에 걸린다.**\n\n 서버가 이미 `type`·`name`·`description`·`category`·`tags` 를 함께 훑는다. 그런데\n 화면에는 태그가 어디에도 안 보여서, 저작자가 적은 태그가 **자기 눈에 돌아오지 않았다** —\n 적어 둔 것이 쓰이는지 알 수 없으면 아무도 적지 않는다.\n\n 정렬은 걸지 않는다. 배열이라 무엇을 기준으로 줄을 세우는지 답할 수 없다.\n\n **카드에서는 이 컬럼이 그리지 않는다.** 본문에 한 줄로 두었더니 태그가 있는 카드만\n 높아져 격자가 어긋났다 — 개수가 피규어마다 다르므로 본문에 두는 한 남는 문제다.\n 카드에서는 `figure-thumb` 이 그림 위에 얹는다. 여기 남은 것은 표 모드의 칸이다.\n */\n type: 'string',\n name: 'tags',\n header: i18next.t('figure.label.tags'),\n record: {\n editable: false,\n renderer: (value: string[] | null) => (value || []).join(' · ')\n },\n filter: 'search',\n sortable: false,\n width: 180\n },\n {\n type: 'string',\n name: 'state',\n header: i18next.t('figure.label.state'),\n record: {\n editable: false,\n /*\n **발행된 것에는 아무 말도 하지 않는다.** 카탈로그에 있는 것은 대개 발행된 것이라,\n 카드마다 「발행됨」이 붙으면 그 말이 아무것도 가르지 않고 자리만 먹는다. 버전 번호도\n 고를 때 쓰는 값이 아니다 — 이력 탭에 있다.\n\n 표 모드에서는 칸에 값이 있어야 하므로 그때는 발행됨도 적는다(`wide` 가 아니라 label\n 이 붙는 자리인지로 가른다 — 카드는 label 을 달지 않았다).\n */\n renderer: (value: string, _column: any, record: Figure, _rowIndex: number, field: Element) => {\n if (value !== 'released') {\n return html`<span style=${DRAFT}>${i18next.t('figure.label.draft')}</span>`\n }\n\n /* 표에서는 칸이 비면 안 된다. 카드에서만 입을 다문다 — 그리는 자리가 알려 준다. */\n return field?.tagName === 'OX-CARD-FIELD'\n ? ''\n : html`<span style=${RELEASED}\n >${i18next.t('figure.label.figure-released')}\n ${record.version ? i18next.t('figure.text.version-number', { version: record.version }) : ''}</span\n >`\n }\n },\n /*\n 전체·초안·발행됨을 단추로 고른다 — 값이 둘뿐인 조건을 펼침 목록에 넣지 않는다.\n\n 이름표는 비워 둔다. 단추에 「초안」·「발행됨」이라고 적혀 있으니 그 앞의 「상태」는\n 같은 말을 한 번 더 하는 것이고, 걸러 보기 줄에서 자리만 먹는다.\n */\n /* Another domain's public figures are released ones only: no draft to tell apart, no choice to offer. */\n filter:\n this.scope === 'own'\n ? {\n type: 'select-buttons',\n operator: 'in',\n label: '',\n options: () =>\n [\n { display: i18next.t('figure.label.draft'), value: 'draft' },\n { display: i18next.t('figure.label.figure-released'), value: 'released' }\n ].map(option => ({ ...option, count: this.stateCounts.get(option.value) ?? 0 }))\n }\n : undefined,\n width: 120\n },\n {\n /*\n **몇 개까지 놓을 수 있나.** 카드에는 싣지 않고 표 모드의 칸으로 둔다 — 고른 뒤에\n 따지는 값이다. 서버에 없는 값이라 `groups` 와 `triangles` 에서 계산하는데, 저작면\n 머리와 **같은 함수**를 쓴다. 두 화면이 같은 형상을 다른 잣대로 말하면 무엇을 고칠지\n 모른다.\n */\n type: 'string',\n name: 'capacity',\n header: i18next.t('figure.label.placement-limit'),\n sortable: false,\n record: {\n editable: false,\n renderer: (_value: unknown, _column: any, record: Figure) => {\n const capacity = capacityFrom(record.groups ?? 0, record.triangles ?? 0)\n\n return capacity\n ? html`<span style=${CAPACITY} title=${i18next.t('figure.text.reuse-score-explained')}>\n ${i18next.t('figure.text.fits-n-instances', { n: capacity.instances.toLocaleString() })}\n </span>`\n : html`<span style=${UNMEASURED}>${i18next.t('figure.text.not-measured-yet')}</span>`\n }\n },\n width: 120\n },\n {\n type: 'float',\n name: 'score',\n header: i18next.t('figure.label.maturity'),\n record: {\n editable: false,\n /*\n 카드에 남긴 하나뿐인 숫자. **이름표를 달지 않으므로** 무엇인지는 손이 갔을 때 뜨는\n 말이 알려 준다.\n\n 색칠한 배지로 두지 않는다. 옛 draw call 한도 3 으로 재던 때는 카탈로그 거의 모두가 0 점이라\n 붉은 덩어리가 카드마다 섰고 아무것도 가르지 못했다. 이 모델은 「한 화면 N 대」 목표에 견준\n 여유라(`figureScoreOf`, 2026-09-24) 퍼지지만, 숫자는 조용히 적고 낮은 것에만 **점 하나**를 붙인다.\n\n 아직 재지 않은 것을 0 으로 보여 주지 않는다 — 0 은 「가볍다」는 뜻이 되어 버린다.\n 등급 문자(A~D)도 여기서 만들지 않는다: 경계는 `figure-model` 의 `scoreOf` · `figureScoreOf` 가 정하고,\n 화면이 그것을 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 말한다.\n */\n renderer: (value: number | null) =>\n value == null\n ? html`<span style=${UNMEASURED}>${i18next.t('figure.text.not-measured-yet')}</span>`\n : html`<span style=${SCORE} title=${i18next.t('figure.label.maturity')}>\n ${value < ATTENTION_BELOW ? html`<i style=${LOW_DOT}></i>` : ''}${Math.round(value)}\n </span>`\n },\n sortable: true,\n width: 90\n },\n {\n type: 'integer',\n name: 'triangles',\n header: i18next.t('figure.label.triangles'),\n record: {\n editable: false,\n /*\n 카드에서는 이름표 없이 서므로 숫자만 두면 옆의 성숙도와 구별되지 않는다. 무엇의\n 수인지 값이 스스로 말하게 한다 — 표 모드에서는 머리글이 그 일을 하므로 겹치지만,\n 그 겹침이 카드에서 뜻을 잃는 것보다 낫다.\n */\n renderer: (value: number | null) =>\n value == null ? '' : i18next.t('figure.text.triangle-count', { count: value })\n },\n sortable: true,\n width: 110\n },\n {\n type: 'integer',\n name: 'groups',\n header: i18next.t('figure.label.budget-groups'),\n record: { editable: false },\n hidden: true,\n width: 0\n },\n {\n /*\n **카드의 그림 칸 전체를 이 renderer 가 그린다.**\n\n 기본 image renderer 는 그림만 그리고, 그 위에 얹혀야 하는 것(초안 표시·삭제)은 카드\n 아래 gutter 줄로 밀린다. 격자로 옮기기 전 손 카드가 그것을 그림 위에 두었고 그 편이\n 맞다 — 그래서 그림 칸을 `figure-thumb` 에게 넘긴다. hover 가 필요해 컴포넌트여야\n 하는 사연은 그 파일에 적혀 있다.\n\n `renderEmpty` — 그림이 아직 없는 것도 자리를 지킨다. 그 카드에도 초안 표시와 삭제가\n 있어야 하고, 「그림 없음」이라고 말하는 것도 `figure-thumb` 이 한다.\n */\n type: 'image',\n name: 'thumbnail',\n header: i18next.t('field.thumbnail'),\n record: {\n editable: false,\n align: 'center',\n wide: true,\n renderEmpty: true,\n renderer: (_value: unknown, _column: any, record: Figure) => html`\n <figure-thumb .figure=${record} ?readonly=${this.scope === 'public'} @remove=${() => this.removeFigure(record)}></figure-thumb>\n `\n },\n hidden: true,\n width: 160\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: i18next.t('field.updated_at'),\n label: true,\n record: { editable: false },\n sortable: true,\n width: 180\n },\n {\n /*\n `resource-object` 를 쓰지 않는다 — 그 renderer 는 다른 패키지(resource-ui)가 등록하고,\n 등록되지 않은 앱에서는 조용히 글자 renderer 로 떨어져 `[object Object]` 가 된다.\n 이름 하나 꺼내는 일에 그 위험을 질 이유가 없다.\n */\n type: 'string',\n name: 'updater',\n header: i18next.t('field.updater'),\n record: {\n editable: false,\n renderer: (value: { name?: string } | null) => value?.name || ''\n },\n hidden: true,\n width: 120\n }\n ],\n\n rows: {\n selectable: false,\n appendable: false,\n handlers: {\n click: (_columns: any, _data: any, _column: any, record: Figure) => {\n if (record?.id) {\n openFigureDetail(record, this.scope === 'public')\n }\n }\n }\n },\n\n sorters: [{ name: 'updatedAt', desc: true }]\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n /*\n **로그인 정보가 도착하면 다시 불러온다.**\n\n 화면이 서는 것과 프로필이 오는 것은 순서가 정해져 있지 않고, 목록 질의는 로그인된 사람으로\n 나간다. 첫 질의가 프로필보다 앞서면 그 한 번이 실패하고, 그 뒤로 다시 묻는 사람이 없으면\n 화면은 비어 있는 채로 남는다. lite-menu 도 같은 신호로 같은 순서 문제를 푼다\n (`auth.on('profile')` — 그쪽 주석에 그 사연이 적혀 있다).\n */\n this.listen = () => {\n if (this.active) {\n this.grist?.fetch()\n }\n }\n auth.on('profile', this.listen)\n /* A picture chosen in the preview, or a figure retired or brought back: the cards are read again. */\n window.addEventListener(FIGURE_THUMBNAIL_CHANGED, this.cardsChanged)\n window.addEventListener(FIGURE_RETIREMENT_CHANGED, this.cardsChanged)\n window.addEventListener(FIGURE_PUBLIC_CHANGED, this.cardsChanged)\n }\n private cardsChanged = () => {\n if (this.active) this.grist?.fetch()\n }\n\n disconnectedCallback() {\n if (this.listen) {\n auth.off?.('profile', this.listen)\n this.listen = undefined\n }\n window.removeEventListener(FIGURE_THUMBNAIL_CHANGED, this.cardsChanged)\n window.removeEventListener(FIGURE_RETIREMENT_CHANGED, this.cardsChanged)\n window.removeEventListener(FIGURE_PUBLIC_CHANGED, this.cardsChanged)\n super.disconnectedCallback()\n }\n\n async pageUpdated() {\n if (this.active) {\n this.grist.fetch()\n }\n }\n\n /**\n * 걸러 보기·정렬·쪽을 **격자가 만든 그대로** 서버에 넘긴다.\n *\n * 여기서 이름을 바꿔 담으면 격자가 아는 조건과 서버에 가는 조건이 어긋난다. 실패는 격자가\n * 받아 화면에 낸다 — 목록이 비어 있는 것과 못 불러온 것은 다른 사실이다.\n */\n async fetchHandler({ page = 1, limit = 24, sortings = [], filters = [] }: FetchOption) {\n if (this.scope === 'own')\n fetchFigureStateCounts(filters)\n .then(counts => {\n this.stateCounts = counts\n ;(this.renderRoot.querySelector('ox-filters-form') as any)?.requestUpdate()\n })\n .catch(e => console.error(e))\n const { items, total } = await fetchFigureList({ page, limit, filters, sortings, scope: this.scope })\n\n return { total: total || 0, records: items || [] }\n }\n\n /** The modeller that can edit this figure, by its format; a new figure starts in (`modeller-route.ts`). */\n private openModeller(figure?: Figure) {\n navigate(modellerPathOf(figure))\n }\n\n /** `remove` 는 HTMLElement 의 메서드다 — 가리면 조용한 결함이 된다. */\n private async removeFigure(figure: Figure) {\n if (this.scope === 'public') return\n // 되돌릴 수 없는 조작이므로 무엇이 사라지는지 이름으로 확인한다\n if (hasBeenReleased(figure)) {\n notify({ level: 'info', message: i18next.t('figure.text.released-figure-not-deletable', { name: figure.name }) })\n return\n }\n const message = i18next.t('figure.text.delete-figure-confirm', { name: figure.name })\n if (!confirm(message)) {\n return\n }\n\n try {\n await deleteFigure(figure.id)\n } catch (e) {\n notify({ level: 'error', message: (e as Error).message })\n return\n }\n this.grist.fetch()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-list-page.js","sourceRoot":"","sources":["../../client/pages/figure-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@material/web/icon/icon.js'\nimport '../viewparts/figure-thumb.js'\n\nimport { css, html, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport type { DataGrist, FetchOption } from '@operato/data-grist'\nimport { i18next, localize } from '@operato/i18n'\nimport { p13n } from '@operato/p13n'\nimport { auth } from '@things-factory/auth-base/dist-client'\nimport { navigate, PageView } from '@operato/shell'\nimport { notify } from '@operato/layout'\nimport { CardCatalogStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\n\nimport { capacityFrom } from '../modeller/scene-budget.js'\nimport { deleteFigure, fetchFigureList, fetchFigureStateCounts } from '../graphql/index.js'\nimport type { Figure } from '../types.js'\nimport { hasBeenReleased } from '../figure-released.js'\nimport { modellerPathOf } from '../modeller/modeller-route.js'\nimport { FIGURE_PUBLIC_CHANGED, FIGURE_RETIREMENT_CHANGED, FIGURE_THUMBNAIL_CHANGED, openFigureDetail } from '../viewparts/figure-detail-dock.js'\n\n/**\n * 이 값 아래면 점수를 색으로 눈에 띄게 한다.\n *\n * **등급 경계가 아니다.** 등급(A~D)은 `figure-model` 의 `scoreOf` 가 정하고 화면은 그것을\n * 베끼지 않는다. 이것은 「눈에 걸리게 할 선」이고, 화면의 판단이다.\n */\nconst ATTENTION_BELOW = 50\n\n/*\n * ── renderer 가 그리는 것은 이 파일의 CSS 가 닿지 않는다 ──────────────────────\n *\n * 컬럼 renderer 의 결과는 `ox-card-field` 의 shadow root 안에 그려진다. 이 페이지의 `static\n * styles` 는 그 경계를 넘지 못하므로 `code[figure-type]` 같은 선택자는 **아무 일도 하지 않는다.**\n * 넘어가는 것은 custom property 뿐이라, 색과 글꼴은 여기서 인라인으로 준다 — 값 자체는 테마\n * 토큰을 가리키므로 밝음·어둠은 따라온다. data-grist 의 image renderer 도 같은 방식이다.\n */\nconst CAPACITY = 'font-weight: 700; color: var(--md-sys-color-primary);'\nconst UNMEASURED = 'font-style: italic; color: var(--md-sys-color-outline);'\nconst RELEASED = 'font-weight: 700; color: var(--md-sys-color-primary);'\nconst DRAFT = 'color: var(--md-sys-color-tertiary);'\n/**\n * 조용히 적는 숫자. 낮은 것만 점으로 눈에 걸리게 한다.\n *\n * **`inline-flex` 를 쓰지 않는다.** 썼더니 점이 뜨는 카드에서만 이 값이 옆의 두 값과 밑줄이\n * 어긋났다 — inline-flex 상자의 밑줄은 **첫 항목**에서 오는데, 첫 항목이 글자 없는 점이라\n * 밑줄이 없어 브라우저가 상자 아래를 밑줄로 삼는다. 점이 없는 카드(50 이상)는 멀쩡했으므로\n * 한 줄에 세 값이 나란히 설 때만 눈에 띄었다.\n *\n * 그냥 인라인으로 두면 이 상자의 밑줄이 곧 숫자의 밑줄이라 옆의 둘과 맞는다. 점은 제 몫으로\n * 글자 가운데에 맞춘다.\n */\nconst SCORE = 'font-variant-numeric: tabular-nums;'\nconst LOW_DOT =\n 'display: inline-block; width: 5px; height: 5px; margin-right: 4px; vertical-align: middle; ' +\n 'border-radius: 50%; background-color: var(--md-sys-color-error);'\n\n/*\n * `as typeof PageView` 로 조이지 않는다 — 그렇게 하면 p13n 이 얹어 주는\n * `getPagePreferenceProvider` 가 타입에서 사라져 개인 설정을 붙일 수 없다.\n */\nconst FigureListPageBase = p13n(localize(i18next)(PageView))\n\n/**\n * Figure 카탈로그.\n *\n * 카드를 고르면 상세 패널에서 저장본과 발행 버전을 살펴본다. 크기와 움직임을 시험한 뒤\n * 「편집 화면 열기」로 저작면에 들어간다. 목록 질의는 자산 원본을 싣지 않는다.\n *\n * ## 왜 손으로 만든 카드가 아니라 격자인가\n *\n * 전에는 카드 격자와 걸러 보기 줄과 빈 화면을 이 파일이 직접 그렸다(200줄). 그 자리에서 빠져\n * 있던 것들은 하나같이 `ox-grist` 가 이미 가진 것이다 — 쪽 나누기, 정렬, 컬럼 걸러 보기,\n * 개인 설정(모드·정렬·쪽 크기를 사람마다 기억한다), 표 모드로 바꿔 보기, 내보내기.\n * 손으로 만든 카드는 그 중 아무것도 없었고, 목록이 늘어나면 전부 한 번에 그렸다.\n *\n * 카드에 실을 것은 `list` 가 정하고, 무엇을 어떻게 그릴지는 컬럼의 renderer 가 정한다. 같은\n * 설정이 표 모드에서도 그대로 쓰이므로 **두 모드가 다른 말을 하지 않는다.**\n */\n@customElement('figure-list-page')\nexport class FigureListPage extends FigureListPageBase {\n static styles = [\n /* The frame owns the page shell; the grist is the content it sizes (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n CardCatalogStyles,\n css`\n :host {\n background-color: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n\n /*\n 카드 · 그림 칸 · 만들기 FAB 는 모든 카드 카탈로그와 같다(@operato/styles CardCatalogStyles,\n ADR-0117 개정 2026-10-13). 여기에는 이 화면에만 있는 것만 둔다.\n */\n ox-grist {\n /* 상태와 성숙도는 짧은 표식이다 — 두 줄로 세우지 않고 한 줄에 뉜다 */\n --data-card-detail-direction: row;\n /* 표 모드의 맨 위로 단추도 만들기 단추 위로 비킨다 */\n --data-list-fab-position-vertical: 64px;\n }\n `\n ]\n\n @property({ type: Object }) gristConfig: any\n\n @query('ox-grist') private grist!: DataGrist\n\n /**\n * The domain's own figures, or other domains' public ones (LV figure-server design G2), read only. Each is a screen\n * of its own on the rail (user 2026-10-19): the own catalogue is where figures are made and changed, the public one\n * only looked at, so a switch inside one list mixed two jobs. `figure-public-list-page` sets it.\n */\n protected readonly scope: 'own' | 'public' = 'own'\n\n private listen?: () => void\n\n get context() {\n return {\n title: i18next.t(this.scope === 'public' ? 'figure.title.public-figures' : 'figure.title.figures'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || '',\n placeholder: i18next.t('figure.text.search-figure')\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n }\n /*\n **만들기는 `actions` 가 아니라 FAB 이다.**\n\n `context.actions` 로 두면 페이지 바닥 줄에 글자 단추로 서는데, 그 줄은 「지금 화면에 대해\n 할 일」을 늘어놓는 자리다. 만들기는 이 화면의 유일한 주된 동작이므로 줄에 섞이지 않고\n 떠 있어야 한다. 카드를 가리지 않는 오른쪽 아래, 손이 가는 자리다(아래 render 의 [fab]).\n */\n }\n }\n\n render() {\n return html`\n <ox-grist\n class=\"page-fill\"\n mode=\"CARD\"\n @search-tag=${(e: CustomEvent) => this.findByTag(e.detail.tag)}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .countHandler=${this.scope === 'own' ? this.countHandler.bind(this) : undefined}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n\n ${this.scope === 'own'\n ? html`<button fab title=${i18next.t('figure.button.new-figure')} @click=${() => this.openModeller()}>\n <md-icon>add</md-icon>${i18next.t('figure.button.new-figure')}\n </button>`\n : nothing}\n `\n }\n\n /**\n * 카드의 태그 알약을 눌렀다 — **그 태그로 목록을 거른다.**\n *\n * 검색창에 그 말을 채워 넣는다. 격자에 조건만 걸고 창을 비워 두면 저작자는 **왜 목록이\n * 줄었는지 모른 채** 보게 되고, 되돌리려면 무엇을 지워야 하는지도 알 수 없다.\n *\n * 서버가 `tags` 뿐 아니라 이름·타입·설명·분류를 함께 훑으므로, 그 말이 다른 칸에 든 피규어도\n * 같이 온다. 태그만 정확히 거르는 것이 아니라 **찾기**다.\n */\n private findByTag(tag: string) {\n this.grist.searchText = tag\n /* 창의 값은 `context` 에서 나온다 — 다시 알려야 헤더가 새 값을 그린다. */\n this.updateContext()\n }\n\n async pageInitialized() {\n this.gristConfig = {\n /*\n **쪽 나누기는 선택이 아니다.** 격자에 가상 스크롤이 없어 받은 것을 전부 DOM 에 그린다.\n 카드 모드는 끝까지 내려가면 다음 쪽을 이어 붙이므로, 한 쪽이 작아도 목록은 계속 읽힌다.\n */\n pagination: { pages: [24, 48, 96] },\n\n /*\n 아직 아무것도 없을 때 하는 말. **이 자리가 이 화면에서 가장 중요하다** — 처음 온 사람은\n 여기서 이 도구가 무엇을 만드는 것인지 알게 된다. 조건이 걸려 비었을 때는 격자가 스스로\n 다른 말을 한다(「찾는 것이 없다」). 그 둘을 섞지 않는 것이 격자 쪽에 이미 들어 있다.\n */\n emptyNote: {\n icon: 'deployed_code',\n title: i18next.t('figure.text.no-figure-yet'),\n description: i18next.t('figure.text.what-a-figure-is')\n },\n\n list: {\n /* 그림 칸은 그 컬럼의 renderer 가 그린다 — 그림 없을 때의 안내까지 `figure-thumb` 안이다 */\n thumbnail: 'thumbnail',\n fields: ['name', 'type'],\n /*\n ── 무게를 모른 채 고르게 두지 않는다 ────────────────────────────────\n 이름과 그림만 실으면 저작자는 **이 형상이 무거운지 모른 채** 고른다. 그것을 저작면에\n 들어가서야 아는 것은 늦다. 그래서 격자로 옮기기 전 손 카드가 실었던 셋을 그대로 싣는다 —\n 몇 개까지 놓을 수 있나(배치 한도) · 성숙도 · 삼각형 수.\n\n 한 줄에 뉜다(`--data-card-detail-direction: row`). 이름표는 달지 않는다 — 값 자체가\n 「625개까지」·「삼각형 440개」로 읽히고, 성숙도만 숫자 하나여서 손이 갔을 때 이름이 뜬다.\n\n 상태는 이 줄에 없다. 그림 위 초안 표시가 그 일을 한다(`figure-thumb`) — 발행된 것에는\n 아무 말도 하지 않으므로 빈 칸이 생기지 않는다.\n */\n details: ['capacity', 'score', 'triangles']\n },\n\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n {\n /*\n 표 모드에서만 쓰는 삭제 칸. 카드에서는 `figure-thumb` 이 그림 위에 그리므로\n `forList: false` 로 내린다 — 카드 아래 단추 줄은 감춰도 자리가 남는다.\n */\n type: 'gutter',\n gutterName: 'button',\n icon: 'delete',\n title: i18next.t('figure.button.delete-figure'),\n danger: true,\n forList: false,\n width: 40,\n handlers: {\n click: (_columns: any, _data: any, _column: any, record: Figure) => this.removeFigure(record)\n }\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('figure.label.name'),\n record: { editable: false },\n filter: 'search',\n sortable: true,\n width: 200\n },\n {\n /*\n 타입 이름은 **저장되는 식별자**다. 표시 이름과 다르게 보이게 두어야 도면이 무엇으로\n 이 형상을 찾는지 헷갈리지 않는다.\n */\n type: 'string',\n name: 'type',\n header: i18next.t('figure.label.figure-type'),\n record: {\n editable: false,\n /* The full name a board stores: {namespace}/{type} (ADR-0114). */\n renderer: (value: string, column: unknown, record: { namespace?: string }) =>\n html`<code>${record?.namespace ? `${record.namespace}/${value}` : value}</code>`\n },\n filter: 'search',\n sortable: true,\n width: 160\n },\n {\n /*\n 태그 — **카드에서 곁줄로 보이고 검색에 걸린다.**\n\n 서버가 이미 `type`·`name`·`description`·`category`·`tags` 를 함께 훑는다. 그런데\n 화면에는 태그가 어디에도 안 보여서, 저작자가 적은 태그가 **자기 눈에 돌아오지 않았다** —\n 적어 둔 것이 쓰이는지 알 수 없으면 아무도 적지 않는다.\n\n 정렬은 걸지 않는다. 배열이라 무엇을 기준으로 줄을 세우는지 답할 수 없다.\n\n **카드에서는 이 컬럼이 그리지 않는다.** 본문에 한 줄로 두었더니 태그가 있는 카드만\n 높아져 격자가 어긋났다 — 개수가 피규어마다 다르므로 본문에 두는 한 남는 문제다.\n 카드에서는 `figure-thumb` 이 그림 위에 얹는다. 여기 남은 것은 표 모드의 칸이다.\n */\n type: 'string',\n name: 'tags',\n header: i18next.t('figure.label.tags'),\n record: {\n editable: false,\n renderer: (value: string[] | null) => (value || []).join(' · ')\n },\n filter: 'search',\n sortable: false,\n width: 180\n },\n {\n type: 'string',\n name: 'state',\n header: i18next.t('figure.label.state'),\n record: {\n editable: false,\n /*\n **발행된 것에는 아무 말도 하지 않는다.** 카탈로그에 있는 것은 대개 발행된 것이라,\n 카드마다 「발행됨」이 붙으면 그 말이 아무것도 가르지 않고 자리만 먹는다. 버전 번호도\n 고를 때 쓰는 값이 아니다 — 이력 탭에 있다.\n\n 표 모드에서는 칸에 값이 있어야 하므로 그때는 발행됨도 적는다(`wide` 가 아니라 label\n 이 붙는 자리인지로 가른다 — 카드는 label 을 달지 않았다).\n */\n renderer: (value: string, _column: any, record: Figure, _rowIndex: number, field: Element) => {\n if (value !== 'released') {\n return html`<span style=${DRAFT}>${i18next.t('figure.label.draft')}</span>`\n }\n\n /* 표에서는 칸이 비면 안 된다. 카드에서만 입을 다문다 — 그리는 자리가 알려 준다. */\n return field?.tagName === 'OX-CARD-FIELD'\n ? ''\n : html`<span style=${RELEASED}\n >${i18next.t('figure.label.figure-released')}\n ${record.version ? i18next.t('figure.text.version-number', { version: record.version }) : ''}</span\n >`\n }\n },\n /*\n 전체·초안·발행됨을 단추로 고른다 — 값이 둘뿐인 조건을 펼침 목록에 넣지 않는다.\n\n 이름표는 비워 둔다. 단추에 「초안」·「발행됨」이라고 적혀 있으니 그 앞의 「상태」는\n 같은 말을 한 번 더 하는 것이고, 걸러 보기 줄에서 자리만 먹는다.\n */\n /* Another domain's public figures are released ones only: no draft to tell apart, no choice to offer. */\n filter:\n this.scope === 'own'\n ? {\n type: 'select-buttons',\n operator: 'in',\n label: '',\n options: () =>\n [\n { display: i18next.t('figure.label.draft'), value: 'draft' },\n { display: i18next.t('figure.label.figure-released'), value: 'released' }\n ]\n }\n : undefined,\n width: 120\n },\n {\n /*\n **몇 개까지 놓을 수 있나.** 카드에는 싣지 않고 표 모드의 칸으로 둔다 — 고른 뒤에\n 따지는 값이다. 서버에 없는 값이라 `groups` 와 `triangles` 에서 계산하는데, 저작면\n 머리와 **같은 함수**를 쓴다. 두 화면이 같은 형상을 다른 잣대로 말하면 무엇을 고칠지\n 모른다.\n */\n type: 'string',\n name: 'capacity',\n header: i18next.t('figure.label.placement-limit'),\n sortable: false,\n record: {\n editable: false,\n renderer: (_value: unknown, _column: any, record: Figure) => {\n const capacity = capacityFrom(record.groups ?? 0, record.triangles ?? 0)\n\n return capacity\n ? html`<span style=${CAPACITY} title=${i18next.t('figure.text.reuse-score-explained')}>\n ${i18next.t('figure.text.fits-n-instances', { n: capacity.instances.toLocaleString() })}\n </span>`\n : html`<span style=${UNMEASURED}>${i18next.t('figure.text.not-measured-yet')}</span>`\n }\n },\n width: 120\n },\n {\n type: 'float',\n name: 'score',\n header: i18next.t('figure.label.maturity'),\n record: {\n editable: false,\n /*\n 카드에 남긴 하나뿐인 숫자. **이름표를 달지 않으므로** 무엇인지는 손이 갔을 때 뜨는\n 말이 알려 준다.\n\n 색칠한 배지로 두지 않는다. 옛 draw call 한도 3 으로 재던 때는 카탈로그 거의 모두가 0 점이라\n 붉은 덩어리가 카드마다 섰고 아무것도 가르지 못했다. 이 모델은 「한 화면 N 대」 목표에 견준\n 여유라(`figureScoreOf`, 2026-09-24) 퍼지지만, 숫자는 조용히 적고 낮은 것에만 **점 하나**를 붙인다.\n\n 아직 재지 않은 것을 0 으로 보여 주지 않는다 — 0 은 「가볍다」는 뜻이 되어 버린다.\n 등급 문자(A~D)도 여기서 만들지 않는다: 경계는 `figure-model` 의 `scoreOf` · `figureScoreOf` 가 정하고,\n 화면이 그것을 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 말한다.\n */\n renderer: (value: number | null) =>\n value == null\n ? html`<span style=${UNMEASURED}>${i18next.t('figure.text.not-measured-yet')}</span>`\n : html`<span style=${SCORE} title=${i18next.t('figure.label.maturity')}>\n ${value < ATTENTION_BELOW ? html`<i style=${LOW_DOT}></i>` : ''}${Math.round(value)}\n </span>`\n },\n sortable: true,\n width: 90\n },\n {\n type: 'integer',\n name: 'triangles',\n header: i18next.t('figure.label.triangles'),\n record: {\n editable: false,\n /*\n 카드에서는 이름표 없이 서므로 숫자만 두면 옆의 성숙도와 구별되지 않는다. 무엇의\n 수인지 값이 스스로 말하게 한다 — 표 모드에서는 머리글이 그 일을 하므로 겹치지만,\n 그 겹침이 카드에서 뜻을 잃는 것보다 낫다.\n */\n renderer: (value: number | null) =>\n value == null ? '' : i18next.t('figure.text.triangle-count', { count: value })\n },\n sortable: true,\n width: 110\n },\n {\n type: 'integer',\n name: 'groups',\n header: i18next.t('figure.label.budget-groups'),\n record: { editable: false },\n hidden: true,\n width: 0\n },\n {\n /*\n **카드의 그림 칸 전체를 이 renderer 가 그린다.**\n\n 기본 image renderer 는 그림만 그리고, 그 위에 얹혀야 하는 것(초안 표시·삭제)은 카드\n 아래 gutter 줄로 밀린다. 격자로 옮기기 전 손 카드가 그것을 그림 위에 두었고 그 편이\n 맞다 — 그래서 그림 칸을 `figure-thumb` 에게 넘긴다. hover 가 필요해 컴포넌트여야\n 하는 사연은 그 파일에 적혀 있다.\n\n `renderEmpty` — 그림이 아직 없는 것도 자리를 지킨다. 그 카드에도 초안 표시와 삭제가\n 있어야 하고, 「그림 없음」이라고 말하는 것도 `figure-thumb` 이 한다.\n */\n type: 'image',\n name: 'thumbnail',\n header: i18next.t('field.thumbnail'),\n record: {\n editable: false,\n align: 'center',\n wide: true,\n renderEmpty: true,\n renderer: (_value: unknown, _column: any, record: Figure) => html`\n <figure-thumb .figure=${record} ?readonly=${this.scope === 'public'} @remove=${() => this.removeFigure(record)}></figure-thumb>\n `\n },\n hidden: true,\n width: 160\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: i18next.t('field.updated_at'),\n label: true,\n record: { editable: false },\n sortable: true,\n width: 180\n },\n {\n /*\n `resource-object` 를 쓰지 않는다 — 그 renderer 는 다른 패키지(resource-ui)가 등록하고,\n 등록되지 않은 앱에서는 조용히 글자 renderer 로 떨어져 `[object Object]` 가 된다.\n 이름 하나 꺼내는 일에 그 위험을 질 이유가 없다.\n */\n type: 'string',\n name: 'updater',\n header: i18next.t('field.updater'),\n record: {\n editable: false,\n renderer: (value: { name?: string } | null) => value?.name || ''\n },\n hidden: true,\n width: 120\n }\n ],\n\n rows: {\n selectable: false,\n appendable: false,\n handlers: {\n click: (_columns: any, _data: any, _column: any, record: Figure) => {\n if (record?.id) {\n openFigureDetail(record, this.scope === 'public')\n }\n }\n }\n },\n\n sorters: [{ name: 'updatedAt', desc: true }]\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n /*\n **로그인 정보가 도착하면 다시 불러온다.**\n\n 화면이 서는 것과 프로필이 오는 것은 순서가 정해져 있지 않고, 목록 질의는 로그인된 사람으로\n 나간다. 첫 질의가 프로필보다 앞서면 그 한 번이 실패하고, 그 뒤로 다시 묻는 사람이 없으면\n 화면은 비어 있는 채로 남는다. lite-menu 도 같은 신호로 같은 순서 문제를 푼다\n (`auth.on('profile')` — 그쪽 주석에 그 사연이 적혀 있다).\n */\n this.listen = () => {\n if (this.active) {\n this.grist?.fetch()\n }\n }\n auth.on('profile', this.listen)\n /* A picture chosen in the preview, or a figure retired or brought back: the cards are read again. */\n window.addEventListener(FIGURE_THUMBNAIL_CHANGED, this.cardsChanged)\n window.addEventListener(FIGURE_RETIREMENT_CHANGED, this.cardsChanged)\n window.addEventListener(FIGURE_PUBLIC_CHANGED, this.cardsChanged)\n }\n private cardsChanged = () => {\n if (this.active) this.grist?.fetch()\n }\n\n disconnectedCallback() {\n if (this.listen) {\n auth.off?.('profile', this.listen)\n this.listen = undefined\n }\n window.removeEventListener(FIGURE_THUMBNAIL_CHANGED, this.cardsChanged)\n window.removeEventListener(FIGURE_RETIREMENT_CHANGED, this.cardsChanged)\n window.removeEventListener(FIGURE_PUBLIC_CHANGED, this.cardsChanged)\n super.disconnectedCallback()\n }\n\n async pageUpdated() {\n if (this.active) {\n this.grist.fetch()\n }\n }\n\n /**\n * 걸러 보기·정렬·쪽을 **격자가 만든 그대로** 서버에 넘긴다.\n *\n * 여기서 이름을 바꿔 담으면 격자가 아는 조건과 서버에 가는 조건이 어긋난다. 실패는 격자가\n * 받아 화면에 낸다 — 목록이 비어 있는 것과 못 불러온 것은 다른 사실이다.\n */\n async fetchHandler({ page = 1, limit = 24, sortings = [], filters = [] }: FetchOption) {\n const { items, total } = await fetchFigureList({ page, limit, filters, sortings, scope: this.scope })\n\n return { total: total || 0, records: items || [] }\n }\n\n /** How many figures each state chip would show, under the list's other conditions - the own catalogue's only. */\n async countHandler({ filters = [], signal }: FetchOption) {\n return { state: await fetchFigureStateCounts(filters, signal) }\n }\n\n /** The modeller that can edit this figure, by its format; a new figure starts in (`modeller-route.ts`). */\n private openModeller(figure?: Figure) {\n navigate(modellerPathOf(figure))\n }\n\n /** `remove` 는 HTMLElement 의 메서드다 — 가리면 조용한 결함이 된다. */\n private async removeFigure(figure: Figure) {\n if (this.scope === 'public') return\n // 되돌릴 수 없는 조작이므로 무엇이 사라지는지 이름으로 확인한다\n if (hasBeenReleased(figure)) {\n notify({ level: 'info', message: i18next.t('figure.text.released-figure-not-deletable', { name: figure.name }) })\n return\n }\n const message = i18next.t('figure.text.delete-figure-confirm', { name: figure.name })\n if (!confirm(message)) {\n return\n }\n\n try {\n await deleteFigure(figure.id)\n } catch (e) {\n notify({ level: 'error', message: (e as Error).message })\n return\n }\n this.grist.fetch()\n }\n}\n"]}
|