@operato/app 10.7.0 → 10.8.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ### [10.8.1](https://github.com/hatiolab/operato/compare/v10.8.0...v10.8.1) (2026-09-04)
7
+
8
+ **Note:** Version bump only for package @operato/app
9
+
10
+
11
+
12
+
13
+
14
+ ## [10.8.0](https://github.com/hatiolab/operato/compare/v10.7.0...v10.8.0) (2026-09-04)
15
+
16
+
17
+ ### :sparkles: Styling
18
+
19
+ * **popup:** 참조 팝업의 모양을 다듬고 모서리 규칙을 토큰으로 세운다 ([f8244c0](https://github.com/hatiolab/operato/commit/f8244c0acca2241b3777ae80cd3c25c53a837404))
20
+
21
+
22
+
6
23
  ## [10.7.0](https://github.com/hatiolab/operato/compare/v10.6.0...v10.7.0) (2026-09-02)
7
24
 
8
25
  **Note:** Version bump only for package @operato/app
@@ -1,6 +1,6 @@
1
1
  import '@material/web/icon/icon.js';
2
2
  import '@operato/data-grist';
3
- import { LitElement } from 'lit';
3
+ import { LitElement, PropertyValues } from 'lit';
4
4
  import { DataGrist, FetchHandler, GristData, GristRecord, InheritedValueType } from '@operato/data-grist';
5
5
  export declare class OxSelectorResourceObject extends LitElement {
6
6
  static styles: import("lit").CSSResult[];
@@ -28,6 +28,8 @@ export declare class OxSelectorResourceObject extends LitElement {
28
28
  };
29
29
  list: any;
30
30
  valueField: string | ((item: any) => any);
31
+ /** 설정을 한 번 세웠나 — 열·질의가 바뀔 때만 다시 세운다. */
32
+ private _configured;
31
33
  grist: DataGrist;
32
34
  render(): import("lit-html").TemplateResult<1>;
33
35
  searchText(value: string): void;
@@ -36,7 +38,18 @@ export declare class OxSelectorResourceObject extends LitElement {
36
38
  onCancel(): void;
37
39
  onConfirm(): void;
38
40
  fetchHandler: FetchHandler;
39
- firstUpdated(): Promise<void>;
41
+ /**
42
+ * 표의 설정을 **첫 렌더 전에** 세운다.
43
+ *
44
+ * ── 왜 firstUpdated 가 아닌가 ──────────────────────────────────────────────
45
+ * 여기 있던 것을 `firstUpdated` 에서 만들고 있었다. 그러면 `<ox-grist>` 와 그 안의 필터 폼이
46
+ * **먼저 붙고** 설정이 나중에 온다. 필터 폼은 붙는 순간의 설정을 한 번 읽어 두므로, 그 스냅숏이
47
+ * 병합 전 것이었다 — 열 일곱 개 중 넷만 든 설정이라 필터가 하나도 없었고, 그래서 필터 영역이
48
+ * 빈 채로 32px 만 서 있었다.
49
+ *
50
+ * `willUpdate` 는 렌더 전에 돈다. 폼이 붙을 때 이미 완성된 설정을 읽는다.
51
+ */
52
+ willUpdate(changed: PropertyValues<this>): void;
40
53
  getQueryFields(): string;
41
54
  get selected(): GristRecord | undefined;
42
55
  }
@@ -18,6 +18,8 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
18
18
  this.selectedRecords = [];
19
19
  this.columns = [];
20
20
  this.valueField = 'id';
21
+ /** 설정을 한 번 세웠나 — 열·질의가 바뀔 때만 다시 세운다. */
22
+ this._configured = false;
21
23
  this.fetchHandler = async ({ filters = [], page, limit, sortings = [], inherited }) => {
22
24
  var _a, _b;
23
25
  if ((_a = this.basicArgs) === null || _a === void 0 ? void 0 : _a.filters) {
@@ -83,20 +85,45 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
83
85
  >
84
86
  <div class="header" slot="headroom">
85
87
  <div class="filters">
88
+ <!--
89
+ **검색은 이 영역이 그리지 않는다.**
90
+ 찾기는 화면의 제목줄이 든다(페이지의 표준이 그렇다 — 제목 왼쪽, 찾기 오른쪽 끝).
91
+ 여기서도 그리면 검색창이 둘이 된다. 실제로 한 번 그렇게 됐다.
92
+
93
+ 이 영역은 **찾기가 아닌 필터**의 자리다. 그것이 하나도 없으면 아래 hideHeadroom 이
94
+ 영역째 감춘다 — 열 것이 없는 문을 두지 않는다.
95
+ -->
86
96
  <ox-filters-form autofocus without-search></ox-filters-form>
87
97
  </div>
88
98
  </div>
89
99
  </ox-grist>
90
100
 
101
+ <!--
102
+ 바닥 — **세 동작의 무게가 다르다.**
103
+
104
+ 지정 안 함 이 칸에 아무것도 넣지 않는다. 왼쪽 끝에 따로 선다 — 확정과 나란히 두면 잘못 누른다
105
+ 닫기 아무것도 하지 않고 나간다. 글자만
106
+ 확인 이 팝업이 하러 온 일. 하나만 채운다
107
+
108
+ 아이콘을 떼었다. 「비우기」에는 체크박스 글리프가 붙어 있었는데, 그것은 **입력칸의
109
+ 글리프**여서 동작이 아니라 「끄고 켜는 것」으로 읽혔다. 닫기의 ⊗ 와 확인의 ✓ 도 걷는다 —
110
+ 낱말이 이미 그 일을 말하고, 곁 단추에 아이콘이 붙으면 무게가 주 동작과 비슷해진다.
111
+ -->
91
112
  <div class="footer">
92
- <button @click=${this.onEmpty.bind(this)}>
93
- <md-icon>check_box_outline_blank</md-icon>${i18next.t('button.empty')}
94
- </button>
113
+ <!--
114
+ 「비우기」였다. **무엇을** 비우는지 말하지 않는다 — 팝업 안에 목록도 검색창도 있어서
115
+ 「목록을 비우나」로도 읽힌다. 이 단추가 하는 일은 그 칸을 빈 값으로 두고 닫는 것이다.
116
+
117
+ button.empty 를 그대로 쓰지 않는 이유: 그 문자열은 여러 개를 고르는 팝업들도 함께 쓴다
118
+ (결재자 · 수신자 편집기). 거기서는 「고른 것 전부 지우기」이고, 그것은 「지정 안 함」과
119
+ 다른 말이다. 한 문자열이 두 뜻을 겸하고 있었다.
120
+ -->
121
+ <button @click=${this.onEmpty.bind(this)} clear>${i18next.t('button.unset')}</button>
95
122
 
96
123
  <div filler></div>
97
124
 
98
- <button @click=${this.onCancel.bind(this)}><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>
99
- <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
125
+ <button @click=${this.onCancel.bind(this)}>${i18next.t('button.cancel')}</button>
126
+ <button @click=${this.onConfirm.bind(this)} done>${i18next.t('button.confirm')}</button>
100
127
  </div>
101
128
  `;
102
129
  }
@@ -117,7 +144,23 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
117
144
  this.confirmCallback && this.confirmCallback(this.selected);
118
145
  closePopup(this);
119
146
  }
120
- async firstUpdated() {
147
+ /**
148
+ * 표의 설정을 **첫 렌더 전에** 세운다.
149
+ *
150
+ * ── 왜 firstUpdated 가 아닌가 ──────────────────────────────────────────────
151
+ * 여기 있던 것을 `firstUpdated` 에서 만들고 있었다. 그러면 `<ox-grist>` 와 그 안의 필터 폼이
152
+ * **먼저 붙고** 설정이 나중에 온다. 필터 폼은 붙는 순간의 설정을 한 번 읽어 두므로, 그 스냅숏이
153
+ * 병합 전 것이었다 — 열 일곱 개 중 넷만 든 설정이라 필터가 하나도 없었고, 그래서 필터 영역이
154
+ * 빈 채로 32px 만 서 있었다.
155
+ *
156
+ * `willUpdate` 는 렌더 전에 돈다. 폼이 붙을 때 이미 완성된 설정을 읽는다.
157
+ */
158
+ willUpdate(changed) {
159
+ /* 열·질의가 바뀌면 다시 세운다. 그 밖의 변화에는 손대지 않는다. */
160
+ if (this._configured && !changed.has('columns') && !changed.has('queryName') && !changed.has('list')) {
161
+ return;
162
+ }
163
+ this._configured = true;
121
164
  const config = {
122
165
  list: this.list,
123
166
  columns: [
@@ -172,11 +215,30 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
172
215
  },
173
216
  sortable: true,
174
217
  filter: 'search',
175
- width: 300
218
+ /*
219
+ * 남는 폭을 이 열이 채운다.
220
+ *
221
+ * 열 폭은 grid-template-columns 에 그대로 들어가므로 문자열도 된다(data-grist 의
222
+ * setGridTemplateColumns). 고정 300px 이었을 때는 오른쪽에 200px 가까운 죽은 자리와
223
+ * 세로선 하나가 남았다 — 목록이 상자 한쪽에 몰려 보인다.
224
+ */
225
+ width: 'minmax(240px, 1fr)'
176
226
  }
177
227
  ];
228
+ /*
229
+ * **밖에서 준 설정을 덮어쓰지 않는다.**
230
+ *
231
+ * 여기서 `this.config` 를 통째로 갈아 끼우고 있었다. 그래서 부르는 쪽이 `config` 를 주어도
232
+ * 사라졌다 — 빈 목록에 무슨 말을 할지(`emptyNote`)를 밖에서 정할 길이 없었다.
233
+ *
234
+ * 빈 목록은 **두 가지 다른 사실**을 말해야 하는 자리다. 「이 표에 아직 아무것도 없다」와
235
+ * 「검색에 걸린 것이 없다」는 다르고, 하나로 합치면 결함이 「고를 게 없다」로 보인다. 실제로
236
+ * 그런 일이 있었다(배열 모양이 달라 목록이 비었는데 아무도 결함인 줄 몰랐다).
237
+ */
238
+ const given = this.config || {};
178
239
  this.config = {
179
240
  ...config,
241
+ ...given,
180
242
  columns: [
181
243
  ...config.columns,
182
244
  ...columns.map(selectField => {
@@ -189,11 +251,24 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
189
251
  })
190
252
  ]
191
253
  };
254
+ /*
255
+ * 걸러 볼 것이 하나도 없으면 그 영역을 감춘다.
256
+ *
257
+ * **병합된 설정으로 판단한다.** 전에는 밖에서 받은 `columns` 만 보았는데, 기본 열(이름·설명)이
258
+ * 이미 검색 필터를 갖고 있어서 그 판단이 실제와 달랐다.
259
+ */
192
260
  requestAnimationFrame(() => {
193
- /* 필터 컬럼이 있으면 headroom을 기본 표시, 없으면 숨김 */
194
- const hasFilterColumns = columns.some((col) => col.filter);
195
- if (!hasFilterColumns) {
196
- this.grist.hideHeadroom();
261
+ var _a;
262
+ /*
263
+ * **찾기가 아닌 필터**가 하나라도 있나로 판단한다. 찾기는 이 영역이 안 그리므로(위 주석),
264
+ * `search` 형 필터만 있는 표에서는 여기 그릴 것이 없다.
265
+ */
266
+ const filterable = this.config.columns.some((column) => {
267
+ const filter = column.filter;
268
+ return filter && filter !== 'search' && (filter === null || filter === void 0 ? void 0 : filter.operator) !== 'search';
269
+ });
270
+ if (!filterable) {
271
+ (_a = this.grist) === null || _a === void 0 ? void 0 : _a.hideHeadroom();
197
272
  }
198
273
  });
199
274
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ox-selector-resource-object.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport {\n DataGrist,\n FetchHandler,\n GristData,\n GristEventHandler,\n GristRecord,\n ZERO_DATA,\n InheritedValueType\n} from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { adjustFilters, isMobileDevice } from '@operato/utils'\nimport { ButtonContainerStyles, CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object')\nexport class OxSelectorResourceObject extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n\n width: var(--overlay-center-normal-width, 50%);\n height: var(--overlay-center-normal-height, 50%);\n }\n\n ox-grist {\n flex: 1;\n }\n\n .header {\n grid-template-areas: 'filters actions';\n }\n\n [filler] {\n margin-left: auto;\n }\n `\n ]\n\n @property({ type: String }) value?: string\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: Partial<GristRecord>) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) columns: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) pagination?: {\n limit: number\n pages: number[]\n }\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n @query('ox-grist') grist!: DataGrist\n\n render() {\n return html`\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .data=${this.data}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n >\n <div class=\"header\" slot=\"headroom\">\n <div class=\"filters\">\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <div class=\"footer\">\n <button @click=${this.onEmpty.bind(this)}>\n <md-icon>check_box_outline_blank</md-icon>${i18next.t('button.empty')}\n </button>\n\n <div filler></div>\n\n <button @click=${this.onCancel.bind(this)}><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>\n <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>\n </div>\n `\n }\n\n searchText(value: string) {\n this.grist.searchText = value\n }\n\n toggleFilter() {\n this.grist.toggleHeadroom()\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n this.confirmCallback && this.confirmCallback(this.selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters = [], page, limit, sortings = [], inherited }) => {\n if (this.basicArgs?.filters) {\n filters = adjustFilters(filters, this.basicArgs.filters)\n }\n // basicArgs.sorters가 있으면 기본 정렬로 병합\n if (this.basicArgs?.sorters && sortings.length === 0) {\n sortings = [...this.basicArgs.sorters]\n }\n const pagination = { page, limit }\n\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited) {\n ${this.getQueryFields()}\n }\n }\n `,\n variables: {\n filters,\n pagination,\n sortings,\n inherited: inherited || this.inherited\n },\n context: gqlContext()\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n if (this.value && this.value === rowValue) {\n this.selectedRecords = [item]\n item['__selected__'] = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n async firstUpdated() {\n const config = {\n list: this.list,\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: false\n }\n ],\n rows: {\n selectable: {\n multiple: false\n },\n handlers: {\n click: 'select-row',\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n },\n appendable: false\n },\n pagination: this.pagination\n }\n\n const columns = this.columns || [\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n width: 300\n }\n ]\n\n this.config = {\n ...config,\n columns: [\n ...config.columns,\n ...columns.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n\n requestAnimationFrame(() => {\n /* 필터 컬럼이 있으면 headroom을 기본 표시, 없으면 숨김 */\n const hasFilterColumns = columns.some((col: any) => col.filter)\n if (!hasFilterColumns) {\n this.grist.hideHeadroom()\n }\n })\n }\n\n getQueryFields() {\n if (this.columns && this.columns.length > 0) {\n return `items {\n ${this.columns.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n get selected() {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected\n\n return selected && selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}
1
+ {"version":3,"file":"ox-selector-resource-object.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport {\n DataGrist,\n FetchHandler,\n GristData,\n GristEventHandler,\n GristRecord,\n ZERO_DATA,\n InheritedValueType\n} from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { adjustFilters, isMobileDevice } from '@operato/utils'\nimport { ButtonContainerStyles, CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object')\nexport class OxSelectorResourceObject extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n\n width: var(--overlay-center-normal-width, 50%);\n height: var(--overlay-center-normal-height, 50%);\n }\n\n ox-grist {\n flex: 1;\n }\n\n .header {\n grid-template-areas: 'filters actions';\n }\n\n [filler] {\n margin-left: auto;\n }\n `\n ]\n\n @property({ type: String }) value?: string\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: Partial<GristRecord>) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) columns: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) pagination?: {\n limit: number\n pages: number[]\n }\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n /** 설정을 한 번 세웠나 — 열·질의가 바뀔 때만 다시 세운다. */\n private _configured = false\n\n @query('ox-grist') grist!: DataGrist\n\n render() {\n return html`\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .data=${this.data}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n >\n <div class=\"header\" slot=\"headroom\">\n <div class=\"filters\">\n <!--\n **검색은 이 영역이 그리지 않는다.**\n 찾기는 화면의 제목줄이 든다(페이지의 표준이 그렇다 — 제목 왼쪽, 찾기 오른쪽 끝).\n 여기서도 그리면 검색창이 둘이 된다. 실제로 한 번 그렇게 됐다.\n\n 이 영역은 **찾기가 아닌 필터**의 자리다. 그것이 하나도 없으면 아래 hideHeadroom 이\n 영역째 감춘다 — 열 것이 없는 문을 두지 않는다.\n -->\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <!--\n 바닥 — **세 동작의 무게가 다르다.**\n\n 지정 안 함 이 칸에 아무것도 넣지 않는다. 왼쪽 끝에 따로 선다 — 확정과 나란히 두면 잘못 누른다\n 닫기 아무것도 하지 않고 나간다. 글자만\n 확인 이 팝업이 하러 온 일. 하나만 채운다\n\n 아이콘을 떼었다. 「비우기」에는 체크박스 글리프가 붙어 있었는데, 그것은 **입력칸의\n 글리프**여서 동작이 아니라 「끄고 켜는 것」으로 읽혔다. 닫기의 ⊗ 와 확인의 ✓ 도 걷는다 —\n 낱말이 이미 그 일을 말하고, 곁 단추에 아이콘이 붙으면 무게가 주 동작과 비슷해진다.\n -->\n <div class=\"footer\">\n <!--\n 「비우기」였다. **무엇을** 비우는지 말하지 않는다 — 팝업 안에 목록도 검색창도 있어서\n 「목록을 비우나」로도 읽힌다. 이 단추가 하는 일은 그 칸을 빈 값으로 두고 닫는 것이다.\n\n button.empty 를 그대로 쓰지 않는 이유: 그 문자열은 여러 개를 고르는 팝업들도 함께 쓴다\n (결재자 · 수신자 편집기). 거기서는 「고른 것 전부 지우기」이고, 그것은 「지정 안 함」과\n 다른 말이다. 한 문자열이 두 뜻을 겸하고 있었다.\n -->\n <button @click=${this.onEmpty.bind(this)} clear>${i18next.t('button.unset')}</button>\n\n <div filler></div>\n\n <button @click=${this.onCancel.bind(this)}>${i18next.t('button.cancel')}</button>\n <button @click=${this.onConfirm.bind(this)} done>${i18next.t('button.confirm')}</button>\n </div>\n `\n }\n\n searchText(value: string) {\n this.grist.searchText = value\n }\n\n toggleFilter() {\n this.grist.toggleHeadroom()\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n this.confirmCallback && this.confirmCallback(this.selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters = [], page, limit, sortings = [], inherited }) => {\n if (this.basicArgs?.filters) {\n filters = adjustFilters(filters, this.basicArgs.filters)\n }\n // basicArgs.sorters가 있으면 기본 정렬로 병합\n if (this.basicArgs?.sorters && sortings.length === 0) {\n sortings = [...this.basicArgs.sorters]\n }\n const pagination = { page, limit }\n\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited) {\n ${this.getQueryFields()}\n }\n }\n `,\n variables: {\n filters,\n pagination,\n sortings,\n inherited: inherited || this.inherited\n },\n context: gqlContext()\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n if (this.value && this.value === rowValue) {\n this.selectedRecords = [item]\n item['__selected__'] = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n /**\n * 표의 설정을 **첫 렌더 전에** 세운다.\n *\n * ── 왜 firstUpdated 가 아닌가 ──────────────────────────────────────────────\n * 여기 있던 것을 `firstUpdated` 에서 만들고 있었다. 그러면 `<ox-grist>` 와 그 안의 필터 폼이\n * **먼저 붙고** 설정이 나중에 온다. 필터 폼은 붙는 순간의 설정을 한 번 읽어 두므로, 그 스냅숏이\n * 병합 전 것이었다 — 열 일곱 개 중 넷만 든 설정이라 필터가 하나도 없었고, 그래서 필터 영역이\n * 빈 채로 32px 만 서 있었다.\n *\n * `willUpdate` 는 렌더 전에 돈다. 폼이 붙을 때 이미 완성된 설정을 읽는다.\n */\n willUpdate(changed: PropertyValues<this>) {\n /* 열·질의가 바뀌면 다시 세운다. 그 밖의 변화에는 손대지 않는다. */\n if (this._configured && !changed.has('columns') && !changed.has('queryName') && !changed.has('list')) {\n return\n }\n\n this._configured = true\n\n const config = {\n list: this.list,\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: false\n }\n ],\n rows: {\n selectable: {\n multiple: false\n },\n handlers: {\n click: 'select-row',\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n },\n appendable: false\n },\n pagination: this.pagination\n }\n\n const columns = this.columns || [\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n /*\n * 남는 폭을 이 열이 채운다.\n *\n * 열 폭은 grid-template-columns 에 그대로 들어가므로 문자열도 된다(data-grist 의\n * setGridTemplateColumns). 고정 300px 이었을 때는 오른쪽에 200px 가까운 죽은 자리와\n * 세로선 하나가 남았다 — 목록이 상자 한쪽에 몰려 보인다.\n */\n width: 'minmax(240px, 1fr)'\n }\n ]\n\n /*\n * **밖에서 준 설정을 덮어쓰지 않는다.**\n *\n * 여기서 `this.config` 를 통째로 갈아 끼우고 있었다. 그래서 부르는 쪽이 `config` 를 주어도\n * 사라졌다 — 빈 목록에 무슨 말을 할지(`emptyNote`)를 밖에서 정할 길이 없었다.\n *\n * 빈 목록은 **두 가지 다른 사실**을 말해야 하는 자리다. 「이 표에 아직 아무것도 없다」와\n * 「검색에 걸린 것이 없다」는 다르고, 하나로 합치면 결함이 「고를 게 없다」로 보인다. 실제로\n * 그런 일이 있었다(배열 모양이 달라 목록이 비었는데 아무도 결함인 줄 몰랐다).\n */\n const given = this.config || {}\n\n this.config = {\n ...config,\n ...given,\n columns: [\n ...config.columns,\n ...columns.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n\n /*\n * 걸러 볼 것이 하나도 없으면 그 영역을 감춘다.\n *\n * **병합된 설정으로 판단한다.** 전에는 밖에서 받은 `columns` 만 보았는데, 기본 열(이름·설명)이\n * 이미 검색 필터를 갖고 있어서 그 판단이 실제와 달랐다.\n */\n requestAnimationFrame(() => {\n /*\n * **찾기가 아닌 필터**가 하나라도 있나로 판단한다. 찾기는 이 영역이 안 그리므로(위 주석),\n * `search` 형 필터만 있는 표에서는 여기 그릴 것이 없다.\n */\n const filterable = this.config.columns.some((column: any) => {\n const filter = column.filter\n return filter && filter !== 'search' && filter?.operator !== 'search'\n })\n\n if (!filterable) {\n this.grist?.hideHeadroom()\n }\n })\n }\n\n getQueryFields() {\n if (this.columns && this.columns.length > 0) {\n return `items {\n ${this.columns.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n get selected() {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected\n\n return selected && selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}