@things-factory/ops-master 10.1.27 → 10.1.29
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/dist-client/pages/master/master-page-base.js +3 -6
- package/dist-client/pages/master/master-page-base.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/translations/en.json +2 -1
- package/translations/ja.json +5 -4
- package/translations/ko.json +2 -1
- package/translations/ms.json +5 -4
- package/translations/zh.json +5 -4
|
@@ -10,7 +10,7 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
10
10
|
import { notify } from '@operato/layout';
|
|
11
11
|
import { p13n } from '@operato/p13n';
|
|
12
12
|
import { PageView } from '@operato/shell';
|
|
13
|
-
import { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
|
|
13
|
+
import { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
14
14
|
import { isMobileDevice } from '@operato/utils';
|
|
15
15
|
import { patchesFor, readImportRows } from './import-rows.js';
|
|
16
16
|
/** 열두 축이 공통으로 갖는 유효 기간 — ISA-95. */
|
|
@@ -31,15 +31,12 @@ export class MasterPageBase extends p13n(localize(i18next)(PageView)) {
|
|
|
31
31
|
this.ready = false;
|
|
32
32
|
}
|
|
33
33
|
static { this.styles = [
|
|
34
|
+
/* The work surface frame for a list screen (ADR-0060 decision 8). */
|
|
35
|
+
WorkSurfacePageStyles,
|
|
34
36
|
CommonGristStyles,
|
|
35
37
|
CommonHeaderStyles,
|
|
36
38
|
ScrollbarStyles,
|
|
37
39
|
css `
|
|
38
|
-
:host {
|
|
39
|
-
display: flex;
|
|
40
|
-
flex-direction: column;
|
|
41
|
-
overflow: hidden;
|
|
42
|
-
}
|
|
43
40
|
|
|
44
41
|
ox-grist {
|
|
45
42
|
overflow-y: auto;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-page-base.js","sourceRoot":"","sources":["../../../client/pages/master/master-page-base.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { p13n } from '@operato/p13n'\n\nimport type { ReferenceOptions } from './grist-reference.js'\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { ImportProblem, patchesFor, readImportRows } from './import-rows.js'\n\n/**\n * 마스터 화면이 함께 쓰는 것 — **코드 재사용은 여기서, 화면은 각자.**\n *\n * ── 왜 화면을 갈랐나 (2026-09-01) ──────────────────────────────────────────\n * 전에는 화면 하나가 `?axis=` 로 열두 축을 다 맡았다. 근거는 「열두 축이 하는 일이 같다」였는데, 그\n * 말은 **지금 자리표시자라서 같아 보이는 것**이었다. 선언을 읽으면 이미 갈라져 있다.\n *\n * 정지 사유 · 위치 계층(parentName · parentId) — 표가 아니라 나무여야 한다\n * 등급 넷 baseIds 다중 상속 — 쉼표 문자열로 편집 중이다\n * 인원 · 설비 · 자산 근무 캘린더 · 검사 결과를 JSON 원문으로 보인다\n * 자재 GTIN · 단위 · 보관처의 칸이 없어 properties JSON 이다\n * 공정 duration 이 ISO 기간, bizStep 이 EPCIS 어휘다\n * 검사 기준 컬럼이 0개다 — 항목 · 상하한 · 단위 · 방법이 들어와야 한다\n *\n * 그 자리표시자를 걷으면 열둘이 서로 다른 화면이 된다. 공용 화면에 「이 축만」 분기를 열둘 넣는 것은\n * 화면 열둘보다 나쁘다.\n *\n * ── UX 일관성과 일괄 개발 편의는 다르다 ────────────────────────────────────\n * 일관성은 **쓰는 사람이 겪는 것**이다. 같은 뜻이 같은 자리에, 같은 용어로, 같은 조작으로. 그것은\n * 어휘와 배치와 부품을 공유해서 얻는다.\n *\n * 일괄 개발의 편의는 **만드는 쪽이 겪는 것**이고, 기반 클래스로 얻으면 된다. 그것을 얻으려고 서로 다른\n * 대상을 한 화면에 묶으면 편의는 만드는 쪽이 가져가고 값은 쓰는 쪽이 치른다.\n *\n * ── MDI 에서도 갈려야 한다 ─────────────────────────────────────────────────\n * MDI 탭은 페이지 **요소**로 나뉜다(`page-mdibar.ts`). 한 라우트면 인원과 설비를 나란히 열 수 없는데,\n * 마스터 작업의 대부분이 두 항목을 비교하며 옮겨 적는 일이다. 품목을 보면서 품목 등급을 채운다.\n *\n * ── 이 클래스가 갖는 것과 갖지 않는 것 ─────────────────────────────────────\n * 갖는 것: 화면 골격 · 컬럼 설정 · 가져오기 · 저장 · 컬럼 하나를 그리는 방식.\n * 갖지 않는 것: **무엇을 보이나.** 그것은 각 화면이 `spec` 으로 말한다.\n */\n\nexport type MasterColumnType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'json'\n | 'list'\n /** 정해진 값 중에서 고른다. `options` 를 함께 준다. */\n | 'select'\n /**\n * ISO 8601 기간 — `PT30S`.\n *\n * 이름이 `duration` 이 아니다. 그 이름은 초 숫자용으로 이미 임자가 있다(`worklist`). 등록소를\n * 앱 전체가 나눠 쓰므로, 이름이 겹치면 나중에 부팅한 쪽이 오류보고없이 이긴다.\n */\n | 'iso-duration'\n /** 다른 표의 이름 하나. `reference` 를 함께 준다. */\n | 'reference'\n | 'reference-list'\n\nexport interface MasterColumn {\n name: string\n /** 화면 문구 키. `field.<이것>`. */\n label: string\n type: MasterColumnType\n /**\n * `select` 가 고를 값들.\n *\n * **여기에 손으로 적지 않는다.** `master-options.ts` 가 계약에서 가져오거나, 계약이 타입으로만\n * 주는 것은 컴파일러가 계약에 묶은 거울에서 가져온다. 화면에 값을 베껴 적으면 커널이 값을 늘렸을\n * 때 화면만 옛 목록을 보인다.\n */\n options?: readonly string[]\n /**\n * `reference` 가 어느 표에서 고르나.\n *\n * 저장되는 것은 **이름**이지 id 가 아니다 — 커널이 이름으로 주소를 잡는다.\n */\n reference?: ReferenceOptions\n width?: number\n /** 고칠 수 없는 칸. 자동으로 붙는 값이 여기 온다. */\n readonly?: boolean\n /**\n * 가로로 스크롤해도 화면에 남는 컬럼.\n *\n * 컬럼이 열 개를 넘고 폭 합이 1000px 을 넘는 축이 있다. 오른쪽 끝을 고치려고 스크롤하면 이름이 화면\n * 밖으로 나가서 **어느 행을 고치는지 알 수 없다.**\n */\n fixed?: boolean\n /**\n * 표에 그리지 않는다 — **검색에는 남는다.**\n *\n * 같은 사실을 두 번 보이지 않으려고 감추는 자리가 있다. 로케이션의 상위는 트리의 들여쓰기가 말하므로\n * 컬럼으로 또 보일 필요가 없지만, 「LINE-1 아래 있는 것」을 찾는 일은 있다.\n *\n * `searchText` 는 `filter: 'search'` 를 선언한 컬럼마다 필터를 만들고 hidden 을 보지 않는다\n * (`data-grist.ts` 의 `set searchText`). 그래서 감춘 컬럼도 검색에는 참여한다.\n *\n * 다만 컬럼 설정 목록에서는 **빠진다** — personalizer 가 페이지 설정의 hidden 을 걸러낸다\n * (`ox-grist-personalizer.ts:51`). 사용자가 켜야 할 컬럼에는 쓰지 않는다.\n */\n hidden?: boolean\n}\n\n/** 각 마스터 화면이 자기에 대해 말하는 것. */\nexport interface MasterSpec {\n /** 컬럼 설정을 사람마다 따로 저장하는 키. 화면마다 달라야 한다. */\n key: string\n /** 제목 문구 키. `title.<이것>`. */\n title: string\n /**\n * 도움말 문서 키 — `helps/<이것>.md`.\n *\n * `ox-page-title-bar` 가 이 값이 있으면 제목 옆에 도움말 아이콘을 그린다. 상세한 설명은 그 문서가\n * 갖는다 — 화면에 형식적인 소개 문장을 붙이는 것은 자리만 차지하고 도움이 안 된다.\n */\n help: string\n /** GraphQL 조회 이름 — 서버가 낸 그대로. */\n query: string\n /** GraphQL 저장 이름. */\n mutation: string\n columns: MasterColumn[]\n}\n\n/** 열두 축이 공통으로 갖는 유효 기간 — ISA-95. */\nexport const EFFECTIVE: MasterColumn[] = [\n { name: 'effectiveStart', label: 'effective-start', type: 'date', width: 150 },\n { name: 'effectiveEnd', label: 'effective-end', type: 'date', width: 150 }\n]\n\n/** 이름과 설명은 열두 축이 모두 갖는다. 이름은 스크롤해도 남는다. */\nexport const IDENTITY: MasterColumn[] = [\n { name: 'name', label: 'name', type: 'string', width: 160, fixed: true },\n { name: 'description', label: 'description', type: 'string', width: 200 }\n]\n\nexport abstract class MasterPageBase extends p13n(localize(i18next)(PageView)) {\n static styles = [\n CommonGristStyles,\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n ox-grist {\n overflow-y: auto;\n flex: 1;\n }\n\n /*\n * 헤드룸에는 「어디를 보고 있나」만 남는다. 검색은 타이틀 줄로 올라갔다(configOf 의 search).\n *\n * 범위가 없는 화면은 이 칸이 비고, 아래 규칙이 그 줄을 아예 감춘다. 빈 띠를 남기지 않는다.\n */\n .header {\n grid-template-areas: 'scope';\n grid-template-columns: 1fr;\n }\n\n .header:empty {\n display: none;\n }\n `\n ]\n\n /** 이 화면이 자기에 대해 말하는 것. 화면마다 자기 것을 준다. */\n protected abstract get spec(): MasterSpec\n\n @property({ type: Boolean }) active: boolean = false\n @property({ type: Object }) gristConfig: any\n @property({ type: String }) mode: 'CARD' | 'LIST' | 'GRID' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @state() protected ready = false\n\n @query('ox-grist') protected grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t(`title.${this.spec.title}`),\n /*\n * **파일로 한 번에 올린다.**\n *\n * 새 공장을 받으면 기준정보를 통째로 넣어야 한다. 자리 · 인원 · 설비가 각각 수백에서 수천\n * 줄이고, 화면에서 한 줄씩 넣으면 인원 1000명에 다섯 시간을 타이핑만 한다. 그런데 고객은\n * 그 자료를 이미 엑셀로 갖고 있다.\n *\n * 틀은 플랫폼이 갖고 있다(`@things-factory/import-ui`). 도구막대에 버튼을 달고 파일을\n * 읽어 줄의 배열로 준다. 우리는 그 줄을 이 화면의 열에 맞추고 저장하기만 한다.\n *\n * **이 자리에 두면 마스터 화면 전부가 한꺼번에 된다.** 화면마다 따로 만들면 열넷이 조금씩\n * 다르게 동작한다.\n */\n importable: { handler: this.importHandler.bind(this) },\n /* 제목 옆의 도움말 아이콘 — 상세한 설명은 그 문서가 갖는다. */\n help: this.spec.help,\n /*\n * 검색은 **페이지 타이틀 줄의 오른쪽 끝**에 둔다.\n *\n * 타이틀은 페이지 안의 제목 줄에 선다(ADR-0060 결정 9, 모든 앱이 같다). 그래서 그\n * 줄은 상단 앱 바가 아니라 페이지의 첫 줄이고, 거기 검색을 두면 거르는 곳과 걸러진 결과가 붙어\n * 있다 — 전에 상단 바를 마다한 이유가 여기서는 생기지 않는다.\n *\n * `ox-page-title-bar` 가 이 값을 받아 타이틀 오른쪽에 그린다. 그래서 헤드룸에는 검색을 두지\n * 않는다 — 두 벌이 되고, 두 벌은 어긋난다.\n */\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n actions: [\n {\n title: i18next.t('button.save'),\n action: this.save.bind(this),\n icon: 'save',\n /* 이 화면의 주 동작 — 채운 버튼으로 그려진다. 한 화면에 하나만 둔다. */\n emphasis: { raised: true }\n }\n ],\n exportable: {\n name: i18next.t(`title.${this.spec.title}`),\n data: () => this.grist.exportRecords()\n }\n }\n }\n\n /**\n * 지금 무엇을 보고 있는가 — 표 바로 위.\n *\n * 계층을 드릴다운으로 걷는 화면은 「어디를 보고 있나」를 말해야 한다. 대부분의 화면은 표 하나가 전부라\n * 범위가 없다 — 그런 화면은 아무것도 그리지 않고, 그 줄이 접힌다.\n */\n protected renderScope() {\n return html``\n }\n\n /**\n * 화면 골격 — 표 하나와 컬럼 설정.\n *\n * 자기 인터페이스가 필요한 화면은 이것을 덮어쓴다. 위치와 정지 사유는 계층이라 표가 아니라 나무여야\n * 하고, 그때 이 render 를 쓰지 않는다.\n */\n render() {\n return html`\n <ox-grist\n .mode=${this.mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider(`ox-grist-${this.spec.key}`)!}\n >\n <!--\n 자리를 뜻으로 구분한다.\n\n 어디를 보고 있나 빵가루 헤드룸 — 표 바로 위\n 좁히는 것 검색 타이틀 줄 오른쪽 끝\n 저지르는 것 저장 · 삭제 화면 바닥 — 셸이 모든 화면에 같은 자리로 둔다\n 고른 것에 하는 것 선택 후 동작 고른 것 옆\n\n 바닥인 이유는 목록을 위에서 아래로 훑고 줄을 고르고 저지르기 때문이다. 손과 눈이 아래에서\n 끝난다. 전에 동작 바를 헤드룸에도 두었다가 「저장」이 위아래에 하나씩 생겼다(실측: top 150 과\n top 720).\n -->\n <div slot=\"headroom\" class=\"header\">${this.renderScope()}</div>\n\n <!-- 컬럼 설정 버튼. provider 만 넘겨도 버튼은 안 생긴다. 이 요소를 화면이 놓아야 한다. -->\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n `\n }\n\n /**\n * 주소 끝의 이름 조각을 **목록 좁히기**에 쓰나.\n *\n * 다른 화면의 참조 칸에서 걸어 들어오면 주소가 `.../ops-master-material-definition/M0161-0003` 이\n * 된다. 그 조각을 아무도 안 읽으면 106줄짜리 목록 첫 장이 뜨고, 사람은 방금 누른 이름을 다시\n * 찾아야 한다 — 걸어온 보람이 없다.\n *\n * 자리 화면과 제조법 화면은 그 조각을 **파고들기**에 이미 쓰고 있다(그 이름 아래를 보여 준다).\n * 그 둘은 여기서 빠진다 — 두 뜻이 한 조각에 겹치면 어느 쪽도 제대로 안 된다.\n */\n protected get pathSegmentNarrowsList(): boolean {\n return true\n }\n\n async pageInitialized() {\n this.gristConfig = this.configOf()\n this.ready = true\n }\n\n /**\n * 셸은 `(changes, after, before)` 를 넘긴다 — 인수 없는 모양으로 좁히면 주소를 읽어야 하는 화면이\n * 이것을 덮어쓸 수 없다(`after.resourceId` 와 `before.resourceId` 를 비교하는 자리다).\n */\n async pageUpdated(_changes?: any, _after?: any, _before?: any) {\n if (this.active) {\n this.grist?.fetch()\n }\n }\n\n /*\n * 반환 타입을 밝힌다. 적지 않으면 이 자리의 리터럴이 그대로 타입이 되고, 컬럼 구성을 바꾸는 화면이\n * 이것을 재정의할 수 없다(로케이션이 실제로 막혔다).\n */\n protected configOf(): any {\n return {\n /*\n * 빈 목록이 하는 말 — **축마다 다르다.**\n *\n * 「아직 아무것도 없습니다」 하나로는 이 화면들이 할 말을 못 한다. 기준정보는 처음 오는\n * 사람이 가장 먼저 만나는 자리이고, 비어 있는 사람이 묻는 것은 「이게 뭔데 채워야 하나」다.\n * 그 답은 축마다 다르다 — 인원이 없으면 작업 스테이션에서 사람을 고를 수 없고, 근무 캘린더가\n * 없으면 가동률이 「모름」이 된다.\n *\n * 항목 파일을 고치지 않는다. spec.key 로 용어를 끌어오므로 용어만 더하면 새 축도 따라온다.\n */\n emptyNote: {\n title: i18next.t(`text.master-empty-${this.spec.key}`),\n description: i18next.t(`text.master-empty-${this.spec.key}-hint`, { defaultValue: '' }) || undefined\n },\n list: { fields: ['name', 'description'], details: [] },\n columns: [\n /* 이름을 고정하면 그 왼쪽의 거터도 함께 남아야 한다 — 아니면 체크박스가 이름 아래로 밀린다. */\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n { type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },\n ...this.spec.columns.map(column => this.columnOf(column))\n ],\n /* 새 행을 만들 수 있다 — 마스터를 채우는 것이 이 화면의 일이다. */\n rows: { appendable: true, selectable: { multiple: true } },\n sorters: [{ name: 'name', desc: false }]\n }\n }\n\n protected columnOf(column: MasterColumn) {\n const header = i18next.t(`field.${column.label}`)\n const editable = !column.readonly\n const fixed = column.fixed\n const hidden = column.hidden\n\n switch (column.type) {\n case 'number':\n return { type: 'float', name: column.name, header, record: { editable }, sortable: true, width: column.width, fixed, hidden }\n case 'boolean':\n return { type: 'boolean', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n case 'date':\n return { type: 'datetime', name: column.name, header, record: { editable }, sortable: true, width: column.width, fixed, hidden }\n /*\n * 목록과 JSON 은 **글자로 고친다.** 전용 편집기를 만들면 축마다 다른 편집기가 생기고, 그 편집기가\n * 모르는 칸이 들어오면 값이 오류 보고 없이 사라진다. 지금은 있는 그대로 보이고 그대로 고친다.\n *\n * 이것은 **자리표시자다.** 화면이 갈라진 지금은 그 축의 화면이 자기 편집기를 가질 수 있다.\n */\n case 'select':\n /*\n * **빈 줄이 없으면 되돌릴 수 없다.** 한 번 고르면 「아직 안 정했다」로 못 돌아간다. 비워 둘\n * 수 없는 칸이면 화면 쪽에서 `options` 에 빈 값을 안 넣으면 된다.\n */\n return {\n type: 'select',\n name: column.name,\n header,\n record: { editable, options: column.options ?? [] },\n filter: 'select',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'reference':\n /*\n * 다른 표에서 골라 온다. 자유 텍스트로 두면 `GUNSAN` 을 `GUNSAM` 이라고 쳐도 저장되고,\n * 그 뒤로 그 참조는 어디에서도 안 걸린다 — 화면에는 값이 있는데.\n *\n * 고르기는 팝업이 하고, 검색은 그 팝업이 갖는다. 그래서 열 자체에는 검색 필터를 안 붙인다.\n */\n return {\n type: 'reference',\n name: column.name,\n header,\n /*\n * **제목을 여기서 채운다.** 팝업 머리에 글자가 없으면 회색 띠에 검색창만 뜨고, 무엇을\n * 고르는 중인지 화면이 말하지 않는다. 편집기 자리에서는 못 채운다 — 그리드가 머리말을\n * `{ renderer }` 객체로 바꿔서 넘기기 때문에 거기서는 글자를 볼 수 없다.\n *\n * 열의 머리말을 그대로 쓴다. 「주 근무 로케이션」을 고르는 팝업의 제목이 「주 근무\n * 로케이션」이면 둘이 어긋날 수가 없다.\n */\n record: { editable, reference: { title: header, ...column.reference } },\n filter: 'search',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'iso-duration':\n /*\n * ISO 8601 기간(`PT30S`)이다. 글자로 고치면 `30s` 나 `PT30` 처럼 커널이 못 읽는 것이\n * 오류 보고 없이 저장된다. 전용 편집기가 초로 받아 표기를 만든다.\n *\n * 이 편집기는 기본 등록에 없다 — `bootstrap.ts` 가 등록한다.\n */\n return { type: 'iso-duration', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n /*\n * JSON 은 **구조를 아는 편집기로 고친다.** 글자로 고치면 괄호 하나가 빠져도 저장 순간까지\n * 모르고, 저장되면 그 칸을 읽는 쪽이 통째로 못 읽는다. `json5` 는 팝업에서 문법을 보아 준다.\n */\n case 'json':\n return { type: 'json5', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n /*\n * 목록은 아직 **글자로 고친다.** 이 칸들은 대개 다른 표의 이름을 담는데(등급 · 공정 · 상위\n * 등급), 그 표에서 골라 오는 편집기가 아직 없다. 자리표시자다.\n */\n /*\n * ── 여럿을 고르는 참조 ──────────────────────────────────────────────────\n *\n * 상위 등급 · 요구 검사 · 공정의 차례처럼 **관계를 여럿 다는 칸**이다. 그리는 것은 목록과\n * 같고(ops-list), 고치는 것은 참조 팝업이 여럿 고르기로 연다.\n *\n * 전에는 이런 칸이 전부 `list` 였다 — 즉 자유 텍스트였다. 그래서 GUNSAN 을 GUNSAM 이라고\n * 쳐도 저장되고, 그 뒤로 그 참조는 어디에서도 안 걸린다. 열 곳이 그 상태였다\n * (2026-09-05 · 사용자 지시로 전부 바꿈).\n */\n case 'reference-list':\n return {\n type: 'ops-list',\n name: column.name,\n header,\n record: {\n editable,\n /*\n * 편집기는 참조 팝업이 맡는다 — 그리기만 목록 렌더러를 쓴다.\n *\n * 열 빌더는 `column.type` 으로 편집기를 고르므로(column-builder), 여기서 함수를\n * 직접 준다. 문자열을 주면 무시되고 글자 편집기가 붙는다.\n */\n editor: getEditor('reference'),\n /*\n * 팝업으로 연다고 밝힌다. 표식(edit_square)의 판단이 열 타입을 보는데, 이 열은\n * 그리기를 목록 렌더러로 하려고 타입이 `ops-list` 다 — 그대로 두면 칸 안에서\n * 고치는 것으로 표시된다.\n */\n opensPopup: true,\n reference: { title: header, multiple: true, ...column.reference }\n },\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'list':\n /*\n * 그리기만 우리 것을 쓰고 고치기는 글자 그대로다(`ops-list` 는 렌더러만 등록한다).\n * 기본 글자 렌더러는 배열을 구분 없이 이어 붙인다.\n */\n return { type: 'ops-list', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n default:\n return {\n type: 'string',\n name: column.name,\n header,\n record: { editable },\n filter: 'search',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n }\n }\n\n async fetchHandler({ page = 1, limit = 50, sortings = [], filters = [] }: FetchOption) {\n const fields = this.spec.columns.map(column => column.name).join('\\n')\n\n /*\n * ── 주소 끝의 이름 조각으로 좁힌다 ──────────────────────────────────────\n *\n * 다른 화면의 참조 칸에서 걸어 들어오면 주소가 `.../ops-master-material-definition/M0161-0003`\n * 이 된다. 그 조각을 아무도 안 읽으면 106줄짜리 목록 첫 장이 뜨고, 사람은 방금 누른 이름을 다시\n * 찾아야 한다 — 걸어온 보람이 없다.\n *\n * **그리드의 검색어를 세우는 방식은 안 된다.** 그렇게 해 봤더니 값은 실제로 세워지는데(기억에\n * 남았다) 그 뒤 그리드가 설정을 복원하면서 지웠다. 훅 자리를 앞뒤로 옮겨도 이기지 못하는\n * 경합이다. 질의를 만드는 이 자리에서 조건을 얹으면 경합이 없다 — 언제 불려도 같은 답이다.\n * [확인함] 2026-09-04\n *\n * 자리 화면과 제조법 화면은 그 조각을 **파고들기**에 이미 쓰므로 여기서 빠진다.\n */\n const segment = this.pathSegmentNarrowsList ? (this as any).lifecycle?.resourceId : undefined\n\n if (segment) {\n filters = [...filters, { name: 'name', operator: 'eq', value: decodeURIComponent(segment) }]\n }\n\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n ${this.spec.query}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n ${fields}\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings },\n fetchPolicy: 'no-cache'\n })\n\n const payload = response.data?.[this.spec.query]\n const records = (payload?.items ?? []).map((item: any) => this.spreadJson(item))\n\n return { total: payload?.total ?? 0, records }\n }\n\n /**\n * JSON 칸을 **사람이 고칠 수 있는 글자로 편다.**\n *\n * 서버는 구조를 구조로 낸다(`ScalarObject` 로 선언하지만 **스키마에 나가는 이름은 `Object`** 다) — 그것이\n * 사실이고, 곧 붙을 전용 편집기가 원하는 모양이다.\n * 그런데 지금 이 그리드의 JSON 칸은 글자 편집기라 객체를 그대로 주면 `[object Object]` 가 된다.\n * 그래서 **화면에 들어올 때만** 편다. 스키마를 화면 사정에 맞추지 않고, 화면이 자기 몫을 한다.\n *\n * 이 옮김은 `packJson` 과 짝이다. 한쪽만 고치면 저장이 오류보고없이 망가진다.\n */\n protected spreadJson(item: any): any {\n const jsonColumns = this.spec.columns.filter(column => column.type === 'json')\n\n if (!jsonColumns.length) {\n return item\n }\n\n const spread = { ...item }\n\n for (const column of jsonColumns) {\n const value = spread[column.name]\n\n /* 비어 있는 것은 비어 있는 채로 둔다 — `null` 을 `\"null\"` 로 만들면 지운 것이 값이 된다. */\n if (value === undefined || value === null || typeof value === 'string') {\n continue\n }\n\n spread[column.name] = JSON.stringify(value, null, 0)\n }\n\n return spread\n }\n\n /**\n * 저장하기 전에 JSON 칸의 글자를 **구조로 되읽는다.**\n *\n * 읽지 못하면 **보내지 않는다.** 그냥 보내면 글자가 통째로 값이 되어, 사람이 적은 구조가 사라진 채로\n * 저장이 성공했다고 나온다. 어느 행 어느 칸인지 말해 주어야 고칠 수 있다.\n */\n protected packJson(patches: any[]): { patches: any[]; problems: string[] } {\n const jsonColumns = this.spec.columns.filter(column => column.type === 'json')\n\n if (!jsonColumns.length) {\n return { patches, problems: [] }\n }\n\n const problems: string[] = []\n\n const packed = patches.map((patch, index) => {\n const one = { ...patch }\n\n for (const column of jsonColumns) {\n const value = one[column.name]\n\n if (typeof value !== 'string') {\n /* 손대지 않은 칸은 이미 구조다. 비운 칸은 비운 채로 간다. */\n continue\n }\n\n if (value.trim() === '') {\n /* 비운 것은 「없앤다」는 뜻이다. 빈 글자로 보내면 칸의 뜻이 흐려진다. */\n one[column.name] = null\n continue\n }\n\n try {\n one[column.name] = JSON.parse(value)\n } catch (error) {\n problems.push(\n i18next.t('text.json-column-unreadable', {\n row: index + 1,\n column: i18next.t(`field.${column.label}`),\n detail: (error as Error).message\n })\n )\n }\n }\n\n return one\n })\n\n return { patches: packed, problems }\n }\n\n /**\n * 파일로 올린 줄들을 이 화면의 마스터로 넣는다.\n *\n * ── 오류보고없이 버리지 않는다 ─────────────────────────────────────────────────\n * 모르는 열 이름, 이름이 없는 줄, 중복된 이름을 **알린다.** 오류보고없이 빼면 사람은 다 올라간 줄 알고,\n * 빠진 것은 나중에 「그 설비가 왜 없지」로 나타난다.\n *\n * ── 하나라도 틀리면 아무것도 안 보낸다 ───────────────────────────────────\n * 절반만 들어가면 무엇이 들어갔는지 사람이 모른다. 파일을 고쳐 다시 올리는 편이 낫다.\n *\n * ── 새로 만들 것과 고칠 것을 이름으로 구분한다 ─────────────────────────────\n * 서버는 `+`(새로)와 `M`(고침, id 필요)을 나눠 받는다. 그러니 **올리기 전에 그 이름들이 이미\n * 있는지 물어야 한다.** 안 물으면 같은 이름이 두 벌 생긴다.\n */\n protected async importHandler(records: any[]) {\n if (!records?.length) {\n notify({ message: i18next.t('text.nothing-to-import'), level: 'info' })\n return\n }\n\n const byHeader = this.headerIndex()\n const reading = readImportRows(records, header => byHeader.get(header))\n\n if (reading.problems.length) {\n /* 열 줄까지만 보인다 — 파일이 통째로 어긋나면 문제도 줄 수만큼 나온다. */\n notify({ message: reading.problems.slice(0, 10).map(problem => this.sayProblem(problem)).join('\\n'), level: 'error' })\n return\n }\n\n const existing = await this.idsByName(reading.rows.map(row => String(row.name)))\n const patches = patchesFor(reading.rows, name => existing.get(name))\n\n const packed = this.packJson(patches)\n\n if (packed.problems.length) {\n notify({ message: packed.problems.slice(0, 10).join('\\n'), level: 'error' })\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [Object!]!) {\n ${this.spec.mutation}(patches: $patches) {\n id\n }\n }\n `,\n variables: { patches: packed.patches }\n })\n\n /*\n * 이 앱의 클라이언트는 서버가 거절해도 던지지 않고 `errors` 에 담아 준다. 여기서 보지 않으면\n * 아래의 「올렸다」가 실패한 뒤에도 그대로 뜬다. 사유는 앱의 공통 오류 처리가 이미 띄우므로\n * 여기서 다시 띄우지 않는다 — 같은 말이 두 번 뜬다.\n */\n if (response?.errors?.length) {\n return\n }\n\n const made = patches.filter(patch => patch.cuFlag === '+').length\n\n notify({\n message: i18next.t('text.import-done', { made, changed: patches.length - made }),\n level: 'info'\n })\n\n this.grist.fetch()\n }\n\n /**\n * 파일의 머리글을 이 화면의 열 이름으로 바꾼다.\n *\n * **두 가지를 다 받는다** — 열 이름 그대로(`homeLocation`)와 화면에 보이는 말(`홈 자리`).\n * 사람이 이 화면에서 내려받아 고쳐 올리면 머리글이 화면의 말이고, 다른 시스템에서 뽑아 오면\n * 열 이름이다. 한쪽만 받으면 다른 쪽이 통째로 「모르는 열」이 된다.\n */\n /** 무엇이 잘못됐는지를 사람에게 보일 문장으로 바꾼다. 줄 번호는 엑셀에서 보는 그 번호다. */\n private sayProblem(problem: ImportProblem): string {\n switch (problem.kind) {\n case 'unknown-column':\n return i18next.t('error.import-unknown-column', { line: problem.line, column: problem.column })\n case 'no-name':\n return i18next.t('error.import-no-name', { line: problem.line })\n case 'duplicate-name':\n return i18next.t('error.import-duplicate-name', { line: problem.line, name: problem.name })\n }\n }\n\n private headerIndex(): Map<string, string> {\n const found = new Map<string, string>()\n\n for (const column of this.spec.columns) {\n found.set(column.name, column.name)\n found.set(i18next.t(`field.${column.name}`), column.name)\n }\n\n return found\n }\n\n /** 이 이름들이 이미 있나 — 있으면 그 `id`. 없는 이름은 지도에 없다. */\n private async idsByName(names: string[]): Promise<Map<string, string>> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination) {\n ${this.spec.query}(filters: $filters, pagination: $pagination) {\n items {\n id\n name\n }\n }\n }\n `,\n variables: {\n filters: [{ name: 'name', operator: 'in', value: names }],\n /* 올린 줄 수만큼만 돌아오면 된다. 기본 50으로 두면 51번째부터 새로 만들어 두 벌이 된다. */\n pagination: { page: 1, limit: names.length }\n },\n fetchPolicy: 'no-cache'\n })\n\n return new Map(\n (response.data?.[this.spec.query]?.items ?? []).map((item: any) => [item.name, item.id])\n )\n }\n\n protected async save() {\n const patches = this.grist.dirtyRecords\n\n if (!patches?.length) {\n notify({ message: i18next.t('text.nothing-changed'), level: 'info' })\n return\n }\n\n const packed = this.packJson(patches)\n\n if (packed.problems.length) {\n /* 하나도 보내지 않는다. 절반만 저장되면 화면과 저장된 것이 달라진다. */\n notify({ message: packed.problems.join('\\n'), level: 'error' })\n return\n }\n\n const response = await client.mutate({\n /*\n * **타입 이름은 `Object` 다.**\n *\n * 서버가 `ScalarObject` 라는 이름으로 선언하지만 스키마에 나가는 이름은 `Object` 이고,\n * `ScalarObject` 로 적으면 「Unknown type」으로 거절된다. 2026-09-01부터 이 자리가 그렇게\n * 적혀 있어 **모든 기준정보 화면의 저장이 안 됐다.** 화면은 오류를 그대로 보여 주지도\n * 않았다 — 이 앱의 클라이언트는 서버가 거절해도 던지지 않는다.\n */\n mutation: gql`\n mutation ($patches: [Object!]!) {\n ${this.spec.mutation}(patches: $patches) {\n id\n name\n }\n }\n `,\n variables: { patches: packed.patches }\n })\n\n /*\n * 이 클라이언트는 서버가 거절해도 던지지 않는다 — 오류는 `response.errors` 에 담겨 온다.\n * 보지 않으면 저장에 실패해도 화면이 목록을 다시 읽어 「저장된 것처럼」 보인다.\n * 사유 자체는 앱의 공통 오류 처리가 띄운다.\n */\n if (response.errors?.length) {\n return\n }\n\n /* 지운 행은 사라지지 않고 유효 기간의 끝이 채워진다. 말해 주지 않으면 저장이 안 된 것으로 읽는다. */\n if (packed.patches.some((patch: any) => String(patch.cuFlag).toUpperCase() === '-')) {\n notify({ message: i18next.t('text.retired-not-deleted'), level: 'info' })\n }\n\n this.grist.fetch()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"master-page-base.js","sourceRoot":"","sources":["../../../client/pages/master/master-page-base.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { p13n } from '@operato/p13n'\n\nimport type { ReferenceOptions } from './grist-reference.js'\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { ImportProblem, patchesFor, readImportRows } from './import-rows.js'\n\n/**\n * 마스터 화면이 함께 쓰는 것 — **코드 재사용은 여기서, 화면은 각자.**\n *\n * ── 왜 화면을 갈랐나 (2026-09-01) ──────────────────────────────────────────\n * 전에는 화면 하나가 `?axis=` 로 열두 축을 다 맡았다. 근거는 「열두 축이 하는 일이 같다」였는데, 그\n * 말은 **지금 자리표시자라서 같아 보이는 것**이었다. 선언을 읽으면 이미 갈라져 있다.\n *\n * 정지 사유 · 위치 계층(parentName · parentId) — 표가 아니라 나무여야 한다\n * 등급 넷 baseIds 다중 상속 — 쉼표 문자열로 편집 중이다\n * 인원 · 설비 · 자산 근무 캘린더 · 검사 결과를 JSON 원문으로 보인다\n * 자재 GTIN · 단위 · 보관처의 칸이 없어 properties JSON 이다\n * 공정 duration 이 ISO 기간, bizStep 이 EPCIS 어휘다\n * 검사 기준 컬럼이 0개다 — 항목 · 상하한 · 단위 · 방법이 들어와야 한다\n *\n * 그 자리표시자를 걷으면 열둘이 서로 다른 화면이 된다. 공용 화면에 「이 축만」 분기를 열둘 넣는 것은\n * 화면 열둘보다 나쁘다.\n *\n * ── UX 일관성과 일괄 개발 편의는 다르다 ────────────────────────────────────\n * 일관성은 **쓰는 사람이 겪는 것**이다. 같은 뜻이 같은 자리에, 같은 용어로, 같은 조작으로. 그것은\n * 어휘와 배치와 부품을 공유해서 얻는다.\n *\n * 일괄 개발의 편의는 **만드는 쪽이 겪는 것**이고, 기반 클래스로 얻으면 된다. 그것을 얻으려고 서로 다른\n * 대상을 한 화면에 묶으면 편의는 만드는 쪽이 가져가고 값은 쓰는 쪽이 치른다.\n *\n * ── MDI 에서도 갈려야 한다 ─────────────────────────────────────────────────\n * MDI 탭은 페이지 **요소**로 나뉜다(`page-mdibar.ts`). 한 라우트면 인원과 설비를 나란히 열 수 없는데,\n * 마스터 작업의 대부분이 두 항목을 비교하며 옮겨 적는 일이다. 품목을 보면서 품목 등급을 채운다.\n *\n * ── 이 클래스가 갖는 것과 갖지 않는 것 ─────────────────────────────────────\n * 갖는 것: 화면 골격 · 컬럼 설정 · 가져오기 · 저장 · 컬럼 하나를 그리는 방식.\n * 갖지 않는 것: **무엇을 보이나.** 그것은 각 화면이 `spec` 으로 말한다.\n */\n\nexport type MasterColumnType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'json'\n | 'list'\n /** 정해진 값 중에서 고른다. `options` 를 함께 준다. */\n | 'select'\n /**\n * ISO 8601 기간 — `PT30S`.\n *\n * 이름이 `duration` 이 아니다. 그 이름은 초 숫자용으로 이미 임자가 있다(`worklist`). 등록소를\n * 앱 전체가 나눠 쓰므로, 이름이 겹치면 나중에 부팅한 쪽이 오류보고없이 이긴다.\n */\n | 'iso-duration'\n /** 다른 표의 이름 하나. `reference` 를 함께 준다. */\n | 'reference'\n | 'reference-list'\n\nexport interface MasterColumn {\n name: string\n /** 화면 문구 키. `field.<이것>`. */\n label: string\n type: MasterColumnType\n /**\n * `select` 가 고를 값들.\n *\n * **여기에 손으로 적지 않는다.** `master-options.ts` 가 계약에서 가져오거나, 계약이 타입으로만\n * 주는 것은 컴파일러가 계약에 묶은 거울에서 가져온다. 화면에 값을 베껴 적으면 커널이 값을 늘렸을\n * 때 화면만 옛 목록을 보인다.\n */\n options?: readonly string[]\n /**\n * `reference` 가 어느 표에서 고르나.\n *\n * 저장되는 것은 **이름**이지 id 가 아니다 — 커널이 이름으로 주소를 잡는다.\n */\n reference?: ReferenceOptions\n width?: number\n /** 고칠 수 없는 칸. 자동으로 붙는 값이 여기 온다. */\n readonly?: boolean\n /**\n * 가로로 스크롤해도 화면에 남는 컬럼.\n *\n * 컬럼이 열 개를 넘고 폭 합이 1000px 을 넘는 축이 있다. 오른쪽 끝을 고치려고 스크롤하면 이름이 화면\n * 밖으로 나가서 **어느 행을 고치는지 알 수 없다.**\n */\n fixed?: boolean\n /**\n * 표에 그리지 않는다 — **검색에는 남는다.**\n *\n * 같은 사실을 두 번 보이지 않으려고 감추는 자리가 있다. 로케이션의 상위는 트리의 들여쓰기가 말하므로\n * 컬럼으로 또 보일 필요가 없지만, 「LINE-1 아래 있는 것」을 찾는 일은 있다.\n *\n * `searchText` 는 `filter: 'search'` 를 선언한 컬럼마다 필터를 만들고 hidden 을 보지 않는다\n * (`data-grist.ts` 의 `set searchText`). 그래서 감춘 컬럼도 검색에는 참여한다.\n *\n * 다만 컬럼 설정 목록에서는 **빠진다** — personalizer 가 페이지 설정의 hidden 을 걸러낸다\n * (`ox-grist-personalizer.ts:51`). 사용자가 켜야 할 컬럼에는 쓰지 않는다.\n */\n hidden?: boolean\n}\n\n/** 각 마스터 화면이 자기에 대해 말하는 것. */\nexport interface MasterSpec {\n /** 컬럼 설정을 사람마다 따로 저장하는 키. 화면마다 달라야 한다. */\n key: string\n /** 제목 문구 키. `title.<이것>`. */\n title: string\n /**\n * 도움말 문서 키 — `helps/<이것>.md`.\n *\n * `ox-page-title-bar` 가 이 값이 있으면 제목 옆에 도움말 아이콘을 그린다. 상세한 설명은 그 문서가\n * 갖는다 — 화면에 형식적인 소개 문장을 붙이는 것은 자리만 차지하고 도움이 안 된다.\n */\n help: string\n /** GraphQL 조회 이름 — 서버가 낸 그대로. */\n query: string\n /** GraphQL 저장 이름. */\n mutation: string\n columns: MasterColumn[]\n}\n\n/** 열두 축이 공통으로 갖는 유효 기간 — ISA-95. */\nexport const EFFECTIVE: MasterColumn[] = [\n { name: 'effectiveStart', label: 'effective-start', type: 'date', width: 150 },\n { name: 'effectiveEnd', label: 'effective-end', type: 'date', width: 150 }\n]\n\n/** 이름과 설명은 열두 축이 모두 갖는다. 이름은 스크롤해도 남는다. */\nexport const IDENTITY: MasterColumn[] = [\n { name: 'name', label: 'name', type: 'string', width: 160, fixed: true },\n { name: 'description', label: 'description', type: 'string', width: 200 }\n]\n\nexport abstract class MasterPageBase extends p13n(localize(i18next)(PageView)) {\n static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n\n ox-grist {\n overflow-y: auto;\n flex: 1;\n }\n\n /*\n * 헤드룸에는 「어디를 보고 있나」만 남는다. 검색은 타이틀 줄로 올라갔다(configOf 의 search).\n *\n * 범위가 없는 화면은 이 칸이 비고, 아래 규칙이 그 줄을 아예 감춘다. 빈 띠를 남기지 않는다.\n */\n .header {\n grid-template-areas: 'scope';\n grid-template-columns: 1fr;\n }\n\n .header:empty {\n display: none;\n }\n `\n ]\n\n /** 이 화면이 자기에 대해 말하는 것. 화면마다 자기 것을 준다. */\n protected abstract get spec(): MasterSpec\n\n @property({ type: Boolean }) active: boolean = false\n @property({ type: Object }) gristConfig: any\n @property({ type: String }) mode: 'CARD' | 'LIST' | 'GRID' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @state() protected ready = false\n\n @query('ox-grist') protected grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t(`title.${this.spec.title}`),\n /*\n * **파일로 한 번에 올린다.**\n *\n * 새 공장을 받으면 기준정보를 통째로 넣어야 한다. 자리 · 인원 · 설비가 각각 수백에서 수천\n * 줄이고, 화면에서 한 줄씩 넣으면 인원 1000명에 다섯 시간을 타이핑만 한다. 그런데 고객은\n * 그 자료를 이미 엑셀로 갖고 있다.\n *\n * 틀은 플랫폼이 갖고 있다(`@things-factory/import-ui`). 도구막대에 버튼을 달고 파일을\n * 읽어 줄의 배열로 준다. 우리는 그 줄을 이 화면의 열에 맞추고 저장하기만 한다.\n *\n * **이 자리에 두면 마스터 화면 전부가 한꺼번에 된다.** 화면마다 따로 만들면 열넷이 조금씩\n * 다르게 동작한다.\n */\n importable: { handler: this.importHandler.bind(this) },\n /* 제목 옆의 도움말 아이콘 — 상세한 설명은 그 문서가 갖는다. */\n help: this.spec.help,\n /*\n * 검색은 **페이지 타이틀 줄의 오른쪽 끝**에 둔다.\n *\n * 타이틀은 페이지 안의 제목 줄에 선다(ADR-0060 결정 9, 모든 앱이 같다). 그래서 그\n * 줄은 상단 앱 바가 아니라 페이지의 첫 줄이고, 거기 검색을 두면 거르는 곳과 걸러진 결과가 붙어\n * 있다 — 전에 상단 바를 마다한 이유가 여기서는 생기지 않는다.\n *\n * `ox-page-title-bar` 가 이 값을 받아 타이틀 오른쪽에 그린다. 그래서 헤드룸에는 검색을 두지\n * 않는다 — 두 벌이 되고, 두 벌은 어긋난다.\n */\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n actions: [\n {\n title: i18next.t('button.save'),\n action: this.save.bind(this),\n icon: 'save',\n /* 이 화면의 주 동작 — 채운 버튼으로 그려진다. 한 화면에 하나만 둔다. */\n emphasis: { raised: true }\n }\n ],\n exportable: {\n name: i18next.t(`title.${this.spec.title}`),\n data: () => this.grist.exportRecords()\n }\n }\n }\n\n /**\n * 지금 무엇을 보고 있는가 — 표 바로 위.\n *\n * 계층을 드릴다운으로 걷는 화면은 「어디를 보고 있나」를 말해야 한다. 대부분의 화면은 표 하나가 전부라\n * 범위가 없다 — 그런 화면은 아무것도 그리지 않고, 그 줄이 접힌다.\n */\n protected renderScope() {\n return html``\n }\n\n /**\n * 화면 골격 — 표 하나와 컬럼 설정.\n *\n * 자기 인터페이스가 필요한 화면은 이것을 덮어쓴다. 위치와 정지 사유는 계층이라 표가 아니라 나무여야\n * 하고, 그때 이 render 를 쓰지 않는다.\n */\n render() {\n return html`\n <ox-grist\n .mode=${this.mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider(`ox-grist-${this.spec.key}`)!}\n >\n <!--\n 자리를 뜻으로 구분한다.\n\n 어디를 보고 있나 빵가루 헤드룸 — 표 바로 위\n 좁히는 것 검색 타이틀 줄 오른쪽 끝\n 저지르는 것 저장 · 삭제 화면 바닥 — 셸이 모든 화면에 같은 자리로 둔다\n 고른 것에 하는 것 선택 후 동작 고른 것 옆\n\n 바닥인 이유는 목록을 위에서 아래로 훑고 줄을 고르고 저지르기 때문이다. 손과 눈이 아래에서\n 끝난다. 전에 동작 바를 헤드룸에도 두었다가 「저장」이 위아래에 하나씩 생겼다(실측: top 150 과\n top 720).\n -->\n <div slot=\"headroom\" class=\"header\">${this.renderScope()}</div>\n\n <!-- 컬럼 설정 버튼. provider 만 넘겨도 버튼은 안 생긴다. 이 요소를 화면이 놓아야 한다. -->\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n `\n }\n\n /**\n * 주소 끝의 이름 조각을 **목록 좁히기**에 쓰나.\n *\n * 다른 화면의 참조 칸에서 걸어 들어오면 주소가 `.../ops-master-material-definition/M0161-0003` 이\n * 된다. 그 조각을 아무도 안 읽으면 106줄짜리 목록 첫 장이 뜨고, 사람은 방금 누른 이름을 다시\n * 찾아야 한다 — 걸어온 보람이 없다.\n *\n * 자리 화면과 제조법 화면은 그 조각을 **파고들기**에 이미 쓰고 있다(그 이름 아래를 보여 준다).\n * 그 둘은 여기서 빠진다 — 두 뜻이 한 조각에 겹치면 어느 쪽도 제대로 안 된다.\n */\n protected get pathSegmentNarrowsList(): boolean {\n return true\n }\n\n async pageInitialized() {\n this.gristConfig = this.configOf()\n this.ready = true\n }\n\n /**\n * 셸은 `(changes, after, before)` 를 넘긴다 — 인수 없는 모양으로 좁히면 주소를 읽어야 하는 화면이\n * 이것을 덮어쓸 수 없다(`after.resourceId` 와 `before.resourceId` 를 비교하는 자리다).\n */\n async pageUpdated(_changes?: any, _after?: any, _before?: any) {\n if (this.active) {\n this.grist?.fetch()\n }\n }\n\n /*\n * 반환 타입을 밝힌다. 적지 않으면 이 자리의 리터럴이 그대로 타입이 되고, 컬럼 구성을 바꾸는 화면이\n * 이것을 재정의할 수 없다(로케이션이 실제로 막혔다).\n */\n protected configOf(): any {\n return {\n /*\n * 빈 목록이 하는 말 — **축마다 다르다.**\n *\n * 「아직 아무것도 없습니다」 하나로는 이 화면들이 할 말을 못 한다. 기준정보는 처음 오는\n * 사람이 가장 먼저 만나는 자리이고, 비어 있는 사람이 묻는 것은 「이게 뭔데 채워야 하나」다.\n * 그 답은 축마다 다르다 — 인원이 없으면 작업 스테이션에서 사람을 고를 수 없고, 근무 캘린더가\n * 없으면 가동률이 「모름」이 된다.\n *\n * 항목 파일을 고치지 않는다. spec.key 로 용어를 끌어오므로 용어만 더하면 새 축도 따라온다.\n */\n emptyNote: {\n title: i18next.t(`text.master-empty-${this.spec.key}`),\n description: i18next.t(`text.master-empty-${this.spec.key}-hint`, { defaultValue: '' }) || undefined\n },\n list: { fields: ['name', 'description'], details: [] },\n columns: [\n /* 이름을 고정하면 그 왼쪽의 거터도 함께 남아야 한다 — 아니면 체크박스가 이름 아래로 밀린다. */\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n { type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },\n ...this.spec.columns.map(column => this.columnOf(column))\n ],\n /* 새 행을 만들 수 있다 — 마스터를 채우는 것이 이 화면의 일이다. */\n rows: { appendable: true, selectable: { multiple: true } },\n sorters: [{ name: 'name', desc: false }]\n }\n }\n\n protected columnOf(column: MasterColumn) {\n const header = i18next.t(`field.${column.label}`)\n const editable = !column.readonly\n const fixed = column.fixed\n const hidden = column.hidden\n\n switch (column.type) {\n case 'number':\n return { type: 'float', name: column.name, header, record: { editable }, sortable: true, width: column.width, fixed, hidden }\n case 'boolean':\n return { type: 'boolean', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n case 'date':\n return { type: 'datetime', name: column.name, header, record: { editable }, sortable: true, width: column.width, fixed, hidden }\n /*\n * 목록과 JSON 은 **글자로 고친다.** 전용 편집기를 만들면 축마다 다른 편집기가 생기고, 그 편집기가\n * 모르는 칸이 들어오면 값이 오류 보고 없이 사라진다. 지금은 있는 그대로 보이고 그대로 고친다.\n *\n * 이것은 **자리표시자다.** 화면이 갈라진 지금은 그 축의 화면이 자기 편집기를 가질 수 있다.\n */\n case 'select':\n /*\n * **빈 줄이 없으면 되돌릴 수 없다.** 한 번 고르면 「아직 안 정했다」로 못 돌아간다. 비워 둘\n * 수 없는 칸이면 화면 쪽에서 `options` 에 빈 값을 안 넣으면 된다.\n */\n return {\n type: 'select',\n name: column.name,\n header,\n record: { editable, options: column.options ?? [] },\n filter: 'select',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'reference':\n /*\n * 다른 표에서 골라 온다. 자유 텍스트로 두면 `GUNSAN` 을 `GUNSAM` 이라고 쳐도 저장되고,\n * 그 뒤로 그 참조는 어디에서도 안 걸린다 — 화면에는 값이 있는데.\n *\n * 고르기는 팝업이 하고, 검색은 그 팝업이 갖는다. 그래서 열 자체에는 검색 필터를 안 붙인다.\n */\n return {\n type: 'reference',\n name: column.name,\n header,\n /*\n * **제목을 여기서 채운다.** 팝업 머리에 글자가 없으면 회색 띠에 검색창만 뜨고, 무엇을\n * 고르는 중인지 화면이 말하지 않는다. 편집기 자리에서는 못 채운다 — 그리드가 머리말을\n * `{ renderer }` 객체로 바꿔서 넘기기 때문에 거기서는 글자를 볼 수 없다.\n *\n * 열의 머리말을 그대로 쓴다. 「주 근무 로케이션」을 고르는 팝업의 제목이 「주 근무\n * 로케이션」이면 둘이 어긋날 수가 없다.\n */\n record: { editable, reference: { title: header, ...column.reference } },\n filter: 'search',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'iso-duration':\n /*\n * ISO 8601 기간(`PT30S`)이다. 글자로 고치면 `30s` 나 `PT30` 처럼 커널이 못 읽는 것이\n * 오류 보고 없이 저장된다. 전용 편집기가 초로 받아 표기를 만든다.\n *\n * 이 편집기는 기본 등록에 없다 — `bootstrap.ts` 가 등록한다.\n */\n return { type: 'iso-duration', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n /*\n * JSON 은 **구조를 아는 편집기로 고친다.** 글자로 고치면 괄호 하나가 빠져도 저장 순간까지\n * 모르고, 저장되면 그 칸을 읽는 쪽이 통째로 못 읽는다. `json5` 는 팝업에서 문법을 보아 준다.\n */\n case 'json':\n return { type: 'json5', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n /*\n * 목록은 아직 **글자로 고친다.** 이 칸들은 대개 다른 표의 이름을 담는데(등급 · 공정 · 상위\n * 등급), 그 표에서 골라 오는 편집기가 아직 없다. 자리표시자다.\n */\n /*\n * ── 여럿을 고르는 참조 ──────────────────────────────────────────────────\n *\n * 상위 등급 · 요구 검사 · 공정의 차례처럼 **관계를 여럿 다는 칸**이다. 그리는 것은 목록과\n * 같고(ops-list), 고치는 것은 참조 팝업이 여럿 고르기로 연다.\n *\n * 전에는 이런 칸이 전부 `list` 였다 — 즉 자유 텍스트였다. 그래서 GUNSAN 을 GUNSAM 이라고\n * 쳐도 저장되고, 그 뒤로 그 참조는 어디에서도 안 걸린다. 열 곳이 그 상태였다\n * (2026-09-05 · 사용자 지시로 전부 바꿈).\n */\n case 'reference-list':\n return {\n type: 'ops-list',\n name: column.name,\n header,\n record: {\n editable,\n /*\n * 편집기는 참조 팝업이 맡는다 — 그리기만 목록 렌더러를 쓴다.\n *\n * 열 빌더는 `column.type` 으로 편집기를 고르므로(column-builder), 여기서 함수를\n * 직접 준다. 문자열을 주면 무시되고 글자 편집기가 붙는다.\n */\n editor: getEditor('reference'),\n /*\n * 팝업으로 연다고 밝힌다. 표식(edit_square)의 판단이 열 타입을 보는데, 이 열은\n * 그리기를 목록 렌더러로 하려고 타입이 `ops-list` 다 — 그대로 두면 칸 안에서\n * 고치는 것으로 표시된다.\n */\n opensPopup: true,\n reference: { title: header, multiple: true, ...column.reference }\n },\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n case 'list':\n /*\n * 그리기만 우리 것을 쓰고 고치기는 글자 그대로다(`ops-list` 는 렌더러만 등록한다).\n * 기본 글자 렌더러는 배열을 구분 없이 이어 붙인다.\n */\n return { type: 'ops-list', name: column.name, header, record: { editable }, width: column.width, fixed, hidden }\n default:\n return {\n type: 'string',\n name: column.name,\n header,\n record: { editable },\n filter: 'search',\n sortable: true,\n width: column.width,\n fixed,\n hidden\n }\n }\n }\n\n async fetchHandler({ page = 1, limit = 50, sortings = [], filters = [] }: FetchOption) {\n const fields = this.spec.columns.map(column => column.name).join('\\n')\n\n /*\n * ── 주소 끝의 이름 조각으로 좁힌다 ──────────────────────────────────────\n *\n * 다른 화면의 참조 칸에서 걸어 들어오면 주소가 `.../ops-master-material-definition/M0161-0003`\n * 이 된다. 그 조각을 아무도 안 읽으면 106줄짜리 목록 첫 장이 뜨고, 사람은 방금 누른 이름을 다시\n * 찾아야 한다 — 걸어온 보람이 없다.\n *\n * **그리드의 검색어를 세우는 방식은 안 된다.** 그렇게 해 봤더니 값은 실제로 세워지는데(기억에\n * 남았다) 그 뒤 그리드가 설정을 복원하면서 지웠다. 훅 자리를 앞뒤로 옮겨도 이기지 못하는\n * 경합이다. 질의를 만드는 이 자리에서 조건을 얹으면 경합이 없다 — 언제 불려도 같은 답이다.\n * [확인함] 2026-09-04\n *\n * 자리 화면과 제조법 화면은 그 조각을 **파고들기**에 이미 쓰므로 여기서 빠진다.\n */\n const segment = this.pathSegmentNarrowsList ? (this as any).lifecycle?.resourceId : undefined\n\n if (segment) {\n filters = [...filters, { name: 'name', operator: 'eq', value: decodeURIComponent(segment) }]\n }\n\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n ${this.spec.query}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n ${fields}\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings },\n fetchPolicy: 'no-cache'\n })\n\n const payload = response.data?.[this.spec.query]\n const records = (payload?.items ?? []).map((item: any) => this.spreadJson(item))\n\n return { total: payload?.total ?? 0, records }\n }\n\n /**\n * JSON 칸을 **사람이 고칠 수 있는 글자로 편다.**\n *\n * 서버는 구조를 구조로 낸다(`ScalarObject` 로 선언하지만 **스키마에 나가는 이름은 `Object`** 다) — 그것이\n * 사실이고, 곧 붙을 전용 편집기가 원하는 모양이다.\n * 그런데 지금 이 그리드의 JSON 칸은 글자 편집기라 객체를 그대로 주면 `[object Object]` 가 된다.\n * 그래서 **화면에 들어올 때만** 편다. 스키마를 화면 사정에 맞추지 않고, 화면이 자기 몫을 한다.\n *\n * 이 옮김은 `packJson` 과 짝이다. 한쪽만 고치면 저장이 오류보고없이 망가진다.\n */\n protected spreadJson(item: any): any {\n const jsonColumns = this.spec.columns.filter(column => column.type === 'json')\n\n if (!jsonColumns.length) {\n return item\n }\n\n const spread = { ...item }\n\n for (const column of jsonColumns) {\n const value = spread[column.name]\n\n /* 비어 있는 것은 비어 있는 채로 둔다 — `null` 을 `\"null\"` 로 만들면 지운 것이 값이 된다. */\n if (value === undefined || value === null || typeof value === 'string') {\n continue\n }\n\n spread[column.name] = JSON.stringify(value, null, 0)\n }\n\n return spread\n }\n\n /**\n * 저장하기 전에 JSON 칸의 글자를 **구조로 되읽는다.**\n *\n * 읽지 못하면 **보내지 않는다.** 그냥 보내면 글자가 통째로 값이 되어, 사람이 적은 구조가 사라진 채로\n * 저장이 성공했다고 나온다. 어느 행 어느 칸인지 말해 주어야 고칠 수 있다.\n */\n protected packJson(patches: any[]): { patches: any[]; problems: string[] } {\n const jsonColumns = this.spec.columns.filter(column => column.type === 'json')\n\n if (!jsonColumns.length) {\n return { patches, problems: [] }\n }\n\n const problems: string[] = []\n\n const packed = patches.map((patch, index) => {\n const one = { ...patch }\n\n for (const column of jsonColumns) {\n const value = one[column.name]\n\n if (typeof value !== 'string') {\n /* 손대지 않은 칸은 이미 구조다. 비운 칸은 비운 채로 간다. */\n continue\n }\n\n if (value.trim() === '') {\n /* 비운 것은 「없앤다」는 뜻이다. 빈 글자로 보내면 칸의 뜻이 흐려진다. */\n one[column.name] = null\n continue\n }\n\n try {\n one[column.name] = JSON.parse(value)\n } catch (error) {\n problems.push(\n i18next.t('text.json-column-unreadable', {\n row: index + 1,\n column: i18next.t(`field.${column.label}`),\n detail: (error as Error).message\n })\n )\n }\n }\n\n return one\n })\n\n return { patches: packed, problems }\n }\n\n /**\n * 파일로 올린 줄들을 이 화면의 마스터로 넣는다.\n *\n * ── 오류보고없이 버리지 않는다 ─────────────────────────────────────────────────\n * 모르는 열 이름, 이름이 없는 줄, 중복된 이름을 **알린다.** 오류보고없이 빼면 사람은 다 올라간 줄 알고,\n * 빠진 것은 나중에 「그 설비가 왜 없지」로 나타난다.\n *\n * ── 하나라도 틀리면 아무것도 안 보낸다 ───────────────────────────────────\n * 절반만 들어가면 무엇이 들어갔는지 사람이 모른다. 파일을 고쳐 다시 올리는 편이 낫다.\n *\n * ── 새로 만들 것과 고칠 것을 이름으로 구분한다 ─────────────────────────────\n * 서버는 `+`(새로)와 `M`(고침, id 필요)을 나눠 받는다. 그러니 **올리기 전에 그 이름들이 이미\n * 있는지 물어야 한다.** 안 물으면 같은 이름이 두 벌 생긴다.\n */\n protected async importHandler(records: any[]) {\n if (!records?.length) {\n notify({ message: i18next.t('text.nothing-to-import'), level: 'info' })\n return\n }\n\n const byHeader = this.headerIndex()\n const reading = readImportRows(records, header => byHeader.get(header))\n\n if (reading.problems.length) {\n /* 열 줄까지만 보인다 — 파일이 통째로 어긋나면 문제도 줄 수만큼 나온다. */\n notify({ message: reading.problems.slice(0, 10).map(problem => this.sayProblem(problem)).join('\\n'), level: 'error' })\n return\n }\n\n const existing = await this.idsByName(reading.rows.map(row => String(row.name)))\n const patches = patchesFor(reading.rows, name => existing.get(name))\n\n const packed = this.packJson(patches)\n\n if (packed.problems.length) {\n notify({ message: packed.problems.slice(0, 10).join('\\n'), level: 'error' })\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [Object!]!) {\n ${this.spec.mutation}(patches: $patches) {\n id\n }\n }\n `,\n variables: { patches: packed.patches }\n })\n\n /*\n * 이 앱의 클라이언트는 서버가 거절해도 던지지 않고 `errors` 에 담아 준다. 여기서 보지 않으면\n * 아래의 「올렸다」가 실패한 뒤에도 그대로 뜬다. 사유는 앱의 공통 오류 처리가 이미 띄우므로\n * 여기서 다시 띄우지 않는다 — 같은 말이 두 번 뜬다.\n */\n if (response?.errors?.length) {\n return\n }\n\n const made = patches.filter(patch => patch.cuFlag === '+').length\n\n notify({\n message: i18next.t('text.import-done', { made, changed: patches.length - made }),\n level: 'info'\n })\n\n this.grist.fetch()\n }\n\n /**\n * 파일의 머리글을 이 화면의 열 이름으로 바꾼다.\n *\n * **두 가지를 다 받는다** — 열 이름 그대로(`homeLocation`)와 화면에 보이는 말(`홈 자리`).\n * 사람이 이 화면에서 내려받아 고쳐 올리면 머리글이 화면의 말이고, 다른 시스템에서 뽑아 오면\n * 열 이름이다. 한쪽만 받으면 다른 쪽이 통째로 「모르는 열」이 된다.\n */\n /** 무엇이 잘못됐는지를 사람에게 보일 문장으로 바꾼다. 줄 번호는 엑셀에서 보는 그 번호다. */\n private sayProblem(problem: ImportProblem): string {\n switch (problem.kind) {\n case 'unknown-column':\n return i18next.t('error.import-unknown-column', { line: problem.line, column: problem.column })\n case 'no-name':\n return i18next.t('error.import-no-name', { line: problem.line })\n case 'duplicate-name':\n return i18next.t('error.import-duplicate-name', { line: problem.line, name: problem.name })\n }\n }\n\n private headerIndex(): Map<string, string> {\n const found = new Map<string, string>()\n\n for (const column of this.spec.columns) {\n found.set(column.name, column.name)\n found.set(i18next.t(`field.${column.name}`), column.name)\n }\n\n return found\n }\n\n /** 이 이름들이 이미 있나 — 있으면 그 `id`. 없는 이름은 지도에 없다. */\n private async idsByName(names: string[]): Promise<Map<string, string>> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination) {\n ${this.spec.query}(filters: $filters, pagination: $pagination) {\n items {\n id\n name\n }\n }\n }\n `,\n variables: {\n filters: [{ name: 'name', operator: 'in', value: names }],\n /* 올린 줄 수만큼만 돌아오면 된다. 기본 50으로 두면 51번째부터 새로 만들어 두 벌이 된다. */\n pagination: { page: 1, limit: names.length }\n },\n fetchPolicy: 'no-cache'\n })\n\n return new Map(\n (response.data?.[this.spec.query]?.items ?? []).map((item: any) => [item.name, item.id])\n )\n }\n\n protected async save() {\n const patches = this.grist.dirtyRecords\n\n if (!patches?.length) {\n notify({ message: i18next.t('text.nothing-changed'), level: 'info' })\n return\n }\n\n const packed = this.packJson(patches)\n\n if (packed.problems.length) {\n /* 하나도 보내지 않는다. 절반만 저장되면 화면과 저장된 것이 달라진다. */\n notify({ message: packed.problems.join('\\n'), level: 'error' })\n return\n }\n\n const response = await client.mutate({\n /*\n * **타입 이름은 `Object` 다.**\n *\n * 서버가 `ScalarObject` 라는 이름으로 선언하지만 스키마에 나가는 이름은 `Object` 이고,\n * `ScalarObject` 로 적으면 「Unknown type」으로 거절된다. 2026-09-01부터 이 자리가 그렇게\n * 적혀 있어 **모든 기준정보 화면의 저장이 안 됐다.** 화면은 오류를 그대로 보여 주지도\n * 않았다 — 이 앱의 클라이언트는 서버가 거절해도 던지지 않는다.\n */\n mutation: gql`\n mutation ($patches: [Object!]!) {\n ${this.spec.mutation}(patches: $patches) {\n id\n name\n }\n }\n `,\n variables: { patches: packed.patches }\n })\n\n /*\n * 이 클라이언트는 서버가 거절해도 던지지 않는다 — 오류는 `response.errors` 에 담겨 온다.\n * 보지 않으면 저장에 실패해도 화면이 목록을 다시 읽어 「저장된 것처럼」 보인다.\n * 사유 자체는 앱의 공통 오류 처리가 띄운다.\n */\n if (response.errors?.length) {\n return\n }\n\n /* 지운 행은 사라지지 않고 유효 기간의 끝이 채워진다. 말해 주지 않으면 저장이 안 된 것으로 읽는다. */\n if (packed.patches.some((patch: any) => String(patch.cuFlag).toUpperCase() === '-')) {\n notify({ message: i18next.t('text.retired-not-deleted'), level: 'info' })\n }\n\n this.grist.fetch()\n }\n}\n"]}
|