@operato/data-grist 10.29.30 → 10.29.36

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.
@@ -17,6 +17,8 @@ export declare class DataProvider {
17
17
  private _attachPageHandler;
18
18
  private _fetchHandlerWrap;
19
19
  private _fetchOptions;
20
+ /** Which fetch is the latest - an answer to an earlier one is dropped (fetch). */
21
+ private _fetchSequence;
20
22
  constructor(consumer: DataConsumer);
21
23
  dispose(): void;
22
24
  onAttachPage(): void;
@@ -30,6 +30,8 @@ export class DataProvider {
30
30
  this._fetchParamsChangeHandler = this.onFetchParamsChange.bind(this);
31
31
  this._recordChangeHandler = this.onRecordChange.bind(this);
32
32
  this._attachPageHandler = this.onAttachPage.bind(this);
33
+ /** Which fetch is the latest - an answer to an earlier one is dropped (fetch). */
34
+ this._fetchSequence = 0;
33
35
  this.consumer = consumer;
34
36
  this.fetchHandler = consumer.fetchHandler;
35
37
  this.consumer.addEventListener('attach-page', this._attachPageHandler);
@@ -82,7 +84,8 @@ export class DataProvider {
82
84
  }
83
85
  get fetchHandler() {
84
86
  if (!this._fetchHandlerWrap) {
85
- this._fetchHandlerWrap = async (options) => {
87
+ /* `current` says whether this read is still the one the grid shows - a replaced read tells the grid nothing. */
88
+ this._fetchHandlerWrap = async (options, current = () => true) => {
86
89
  var _a, _b, _c, _d, _e, _f;
87
90
  if (!this._fetchHandler) {
88
91
  return;
@@ -90,7 +93,7 @@ export class DataProvider {
90
93
  try {
91
94
  (_a = this.consumer) === null || _a === void 0 ? void 0 : _a.showSpinner();
92
95
  const result = await (this._fetchHandler || EMPTY_FETCHHANDLER)(options);
93
- (_c = (_b = this.consumer) === null || _b === void 0 ? void 0 : _b.fetchSucceeded) === null || _c === void 0 ? void 0 : _c.call(_b);
96
+ current() && ((_c = (_b = this.consumer) === null || _b === void 0 ? void 0 : _b.fetchSucceeded) === null || _c === void 0 ? void 0 : _c.call(_b));
94
97
  return result;
95
98
  }
96
99
  catch (error) {
@@ -98,7 +101,7 @@ export class DataProvider {
98
101
  * A failed read is not an empty list. The grid is told, so it can say "could not load"
99
102
  * instead of "nothing to show" - and the error still reaches whoever awaited the fetch.
100
103
  */
101
- (_e = (_d = this.consumer) === null || _d === void 0 ? void 0 : _d.fetchFailed) === null || _e === void 0 ? void 0 : _e.call(_d, error);
104
+ current() && ((_e = (_d = this.consumer) === null || _d === void 0 ? void 0 : _d.fetchFailed) === null || _e === void 0 ? void 0 : _e.call(_d, error));
102
105
  throw error;
103
106
  }
104
107
  finally {
@@ -168,11 +171,20 @@ export class DataProvider {
168
171
  sorters = sorters || sortings || this.sorters;
169
172
  filters = filters || this.filters;
170
173
  this.sorters = sorters;
171
- return this._update({
172
- /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */
173
- limit,
174
- page,
175
- ...(await this.fetchHandler.call(null, {
174
+ /*
175
+ * **The last fetch asked is the one the grid shows.**
176
+ *
177
+ * Two fetches can be out at once - the grid reading its address, then the screen laying its own conditions
178
+ * over it a moment later. `_update` keeps the first answer to arrive and ignores the rest, so whichever came
179
+ * back first stood: a ledger opened from the dashboard's 이번 달 순현금흐름 showed all 2,908 lines, the answer
180
+ * to the read with no conditions, under a headroom that said October (2026-10-16). An answer to a fetch that a
181
+ * later one has replaced - or its failure - is dropped, and the later answer is the one kept.
182
+ */
183
+ const sequence = ++this._fetchSequence;
184
+ const current = () => sequence === this._fetchSequence;
185
+ let answer;
186
+ try {
187
+ answer = await this.fetchHandler.call(null, {
176
188
  page,
177
189
  limit,
178
190
  sorters,
@@ -181,7 +193,20 @@ export class DataProvider {
181
193
  ...(this._search ? { search: this._search } : {}),
182
194
  filters,
183
195
  options: this.fetchOptions
184
- }))
196
+ }, current);
197
+ }
198
+ catch (error) {
199
+ if (!current())
200
+ return;
201
+ throw error;
202
+ }
203
+ if (!current())
204
+ return;
205
+ return this._update({
206
+ /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */
207
+ limit,
208
+ page,
209
+ ...answer
185
210
  });
186
211
  }
187
212
  async _update({ page, limit, total, records }, reset) {
@@ -1 +1 @@
1
- {"version":3,"file":"data-provider.js","sourceRoot":"","sources":["../../src/data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZERO_RECORDS } from './configure/zero-config.js'\nimport { DataConsumer } from './data-consumer.js'\nimport { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types.js'\n\nfunction EMPTY_FETCHHANDLER() {\n return {\n total: 0,\n records: []\n }\n}\n\nfunction _calculateTotalPage(limit: number, total: number) {\n /*\n * total page는 1이상이어야 한다.\n * 즉, 레코드가 하나도 없어도, 페이지 갯수는 1이 되어야 한다.\n */\n return Math.max(1, Math.ceil(total / limit))\n}\n\n/*\n * For fetches nobody awaits (page and limit changes, filter and option changes). This does not hide a\n * failure: fetchFailed has already drawn it on the grid before the rejection gets here. It only stops\n * the same failure from also escaping as an unhandled rejection. Do not copy it to a place where the\n * failure is not already shown.\n */\nconst shownByConsumer = () => {}\n\nexport class DataProvider {\n page: number = 1\n limit: number = 20\n total: number = 0\n records: GristRecord[] = []\n\n private consumer?: DataConsumer\n private _fetchHandler?: FetchHandler\n private _sorters?: SorterConfig[]\n private _filters?: FilterValue[]\n /*\n * 검색 낱말 — `search-mode=\"term\"` 에서만 찬다. 옛 길은 낱말을 칸별 필터로 바꿔 `_filters` 에\n * 넣으므로 이 자리는 비어 있고, 그래서 두 길이 한 화면에서 같이 서지 않는다.\n */\n private _search?: string\n\n private _pageChangeHandler: EventListener = this.onPageChange.bind(this)\n private _limitChangeHandler = this.onLimitChange.bind(this)\n private _fetchParamsChangeHandler = this.onFetchParamsChange.bind(this)\n private _recordChangeHandler = this.onRecordChange.bind(this)\n private _attachPageHandler: EventListener = this.onAttachPage.bind(this)\n\n private _fetchHandlerWrap: any\n private _fetchOptions: any\n\n constructor(consumer: DataConsumer) {\n this.consumer = consumer\n\n this.fetchHandler = consumer.fetchHandler\n\n this.consumer.addEventListener('attach-page', this._attachPageHandler)\n this.consumer.addEventListener('page-change', this._pageChangeHandler)\n this.consumer.addEventListener('limit-change', this._limitChangeHandler)\n this.consumer.addEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer.addEventListener('record-change', this._recordChangeHandler)\n }\n\n dispose() {\n this.consumer?.removeEventListener('attach-page', this._attachPageHandler)\n this.consumer?.removeEventListener('page-change', this._pageChangeHandler)\n this.consumer?.removeEventListener('limit-change', this._limitChangeHandler)\n this.consumer?.removeEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer?.removeEventListener('record-change', this._recordChangeHandler)\n }\n\n onAttachPage() {\n this.attach().catch(shownByConsumer)\n }\n\n onPageChange(e: Event) {\n var page = (e as CustomEvent).detail\n this.fetch({ page }).catch(shownByConsumer)\n }\n\n onLimitChange(e: Event) {\n var limit = (e as CustomEvent).detail\n this.fetch({ limit }).catch(shownByConsumer)\n }\n\n onFetchParamsChange(e: Event) {\n const { sorters, filters, search, from } = (e as CustomEvent).detail || {}\n\n sorters && (this.sorters = sorters)\n filters && (this.filters = filters)\n /* 빈 낱말도 값이다 — 「검색을 지웠다」를 지난 낱말로 덮으면 목록이 안 돌아온다. */\n search !== undefined && (this._search = search)\n\n if (this.consumer?.mode !== 'GRID') {\n this.page = 0\n }\n\n from !== 'config' && this.fetch().catch(shownByConsumer)\n }\n\n onRecordChange(e: Event) {\n this.consumer?.checkDirties()\n }\n\n get fetchOptions() {\n return this._fetchOptions\n }\n\n set fetchOptions(fetchOptions) {\n this._fetchOptions = fetchOptions\n\n this.fetch().catch(shownByConsumer)\n }\n\n get fetchHandler() {\n if (!this._fetchHandlerWrap) {\n this._fetchHandlerWrap = async (options: FetchOption) => {\n if (!this._fetchHandler) {\n return\n }\n\n try {\n this.consumer?.showSpinner()\n const result = await (this._fetchHandler || EMPTY_FETCHHANDLER)(options)\n this.consumer?.fetchSucceeded?.()\n return result\n } catch (error) {\n /*\n * A failed read is not an empty list. The grid is told, so it can say \"could not load\"\n * instead of \"nothing to show\" - and the error still reaches whoever awaited the fetch.\n */\n this.consumer?.fetchFailed?.(error)\n throw error\n } finally {\n this.consumer?.hideSpinner()\n }\n }\n }\n\n return this._fetchHandlerWrap\n }\n\n set fetchHandler(fetchHandler) {\n this._fetchHandler = fetchHandler\n delete this._fetchHandlerWrap\n }\n\n get sorters() {\n return this._sorters\n }\n\n set sorters(sorters) {\n this._sorters = sorters\n }\n\n /* alias for sorters */\n get sortings() {\n return this._sorters\n }\n\n set sortings(sorters) {\n this._sorters = sorters\n }\n\n get filters() {\n return this._filters\n }\n\n set filters(filters) {\n this._filters = filters\n }\n\n async attach(reset = false) {\n var { page = 0, limit = 20 } = this\n\n /*\n * page는 0 based index가 아님에 주의한다.\n * 즉, page 값이 1 은 첫페이지를 의미한다.\n */\n if (reset) {\n this.records = ZERO_RECORDS\n page = 1\n } else {\n /* attach의 경우는 grist data의 변경상태를 유지하기 위해서, grist._data 를 기반으로 한다. */\n this.records = this.consumer?._data ? this.consumer._data.records : ZERO_RECORDS\n page = page + 1\n }\n\n return this._update(\n {\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters: this.sorters,\n sortings: this.sorters,\n filters: this.filters,\n options: this.fetchOptions\n }))\n },\n reset\n )\n }\n\n async fetch({\n page = this.page,\n limit = this.limit,\n sorters,\n sortings,\n filters\n }: {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: FilterValue[]\n } = {}) {\n /* sortings property is only for things-factory server-side list parameter convention */\n /* fetchHandler should reture { page, limit, total, records } */\n this.records = ZERO_RECORDS\n\n sorters = sorters || sortings || this.sorters\n filters = filters || this.filters\n\n this.sorters = sorters\n\n return this._update({\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters,\n sortings: sorters,\n /* 안 쓰는 화면에 빈 칸을 보내지 않는다 — 옛 길 소비자의 fetchHandler 가 그날 안 바뀐다. */\n ...(this._search ? { search: this._search } : {}),\n filters,\n options: this.fetchOptions\n }))\n })\n }\n\n async _update(\n {\n page,\n limit,\n total,\n records\n }: {\n page: number\n limit: number\n total: number\n records: GristRecord[]\n },\n reset?: boolean\n ): Promise<void> {\n // total을 감안해서 page가 최대값을 넘지 않도록 한다.\n var maxpage = _calculateTotalPage(limit, total)\n if (maxpage < page) {\n return await this.fetch({ page: maxpage, limit })\n }\n\n // page와 limit이 없는 경우 records 검사 전에 초기화\n this.page = this.page || page\n this.limit = this.limit || limit\n\n if (!records) {\n return\n }\n\n if (this.records === ZERO_RECORDS) {\n this.records = records\n } else if (this.page < page) {\n // attach인 경우에는 records를 append한다.\n this.records = [...this.records, ...records]\n } else {\n return\n }\n\n this.limit = limit\n this.total = total\n this.page = page\n\n this.consumer &&\n (this.consumer.data = {\n page: this.page,\n limit: this.limit,\n total: this.total,\n\n records: this.records\n })\n }\n}\n"]}
1
+ {"version":3,"file":"data-provider.js","sourceRoot":"","sources":["../../src/data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZERO_RECORDS } from './configure/zero-config.js'\nimport { DataConsumer } from './data-consumer.js'\nimport { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types.js'\n\nfunction EMPTY_FETCHHANDLER() {\n return {\n total: 0,\n records: []\n }\n}\n\nfunction _calculateTotalPage(limit: number, total: number) {\n /*\n * total page는 1이상이어야 한다.\n * 즉, 레코드가 하나도 없어도, 페이지 갯수는 1이 되어야 한다.\n */\n return Math.max(1, Math.ceil(total / limit))\n}\n\n/*\n * For fetches nobody awaits (page and limit changes, filter and option changes). This does not hide a\n * failure: fetchFailed has already drawn it on the grid before the rejection gets here. It only stops\n * the same failure from also escaping as an unhandled rejection. Do not copy it to a place where the\n * failure is not already shown.\n */\nconst shownByConsumer = () => {}\n\nexport class DataProvider {\n page: number = 1\n limit: number = 20\n total: number = 0\n records: GristRecord[] = []\n\n private consumer?: DataConsumer\n private _fetchHandler?: FetchHandler\n private _sorters?: SorterConfig[]\n private _filters?: FilterValue[]\n /*\n * 검색 낱말 — `search-mode=\"term\"` 에서만 찬다. 옛 길은 낱말을 칸별 필터로 바꿔 `_filters` 에\n * 넣으므로 이 자리는 비어 있고, 그래서 두 길이 한 화면에서 같이 서지 않는다.\n */\n private _search?: string\n\n private _pageChangeHandler: EventListener = this.onPageChange.bind(this)\n private _limitChangeHandler = this.onLimitChange.bind(this)\n private _fetchParamsChangeHandler = this.onFetchParamsChange.bind(this)\n private _recordChangeHandler = this.onRecordChange.bind(this)\n private _attachPageHandler: EventListener = this.onAttachPage.bind(this)\n\n private _fetchHandlerWrap: any\n private _fetchOptions: any\n /** Which fetch is the latest - an answer to an earlier one is dropped (fetch). */\n private _fetchSequence = 0\n\n constructor(consumer: DataConsumer) {\n this.consumer = consumer\n\n this.fetchHandler = consumer.fetchHandler\n\n this.consumer.addEventListener('attach-page', this._attachPageHandler)\n this.consumer.addEventListener('page-change', this._pageChangeHandler)\n this.consumer.addEventListener('limit-change', this._limitChangeHandler)\n this.consumer.addEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer.addEventListener('record-change', this._recordChangeHandler)\n }\n\n dispose() {\n this.consumer?.removeEventListener('attach-page', this._attachPageHandler)\n this.consumer?.removeEventListener('page-change', this._pageChangeHandler)\n this.consumer?.removeEventListener('limit-change', this._limitChangeHandler)\n this.consumer?.removeEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer?.removeEventListener('record-change', this._recordChangeHandler)\n }\n\n onAttachPage() {\n this.attach().catch(shownByConsumer)\n }\n\n onPageChange(e: Event) {\n var page = (e as CustomEvent).detail\n this.fetch({ page }).catch(shownByConsumer)\n }\n\n onLimitChange(e: Event) {\n var limit = (e as CustomEvent).detail\n this.fetch({ limit }).catch(shownByConsumer)\n }\n\n onFetchParamsChange(e: Event) {\n const { sorters, filters, search, from } = (e as CustomEvent).detail || {}\n\n sorters && (this.sorters = sorters)\n filters && (this.filters = filters)\n /* 빈 낱말도 값이다 — 「검색을 지웠다」를 지난 낱말로 덮으면 목록이 안 돌아온다. */\n search !== undefined && (this._search = search)\n\n if (this.consumer?.mode !== 'GRID') {\n this.page = 0\n }\n\n from !== 'config' && this.fetch().catch(shownByConsumer)\n }\n\n onRecordChange(e: Event) {\n this.consumer?.checkDirties()\n }\n\n get fetchOptions() {\n return this._fetchOptions\n }\n\n set fetchOptions(fetchOptions) {\n this._fetchOptions = fetchOptions\n\n this.fetch().catch(shownByConsumer)\n }\n\n get fetchHandler() {\n if (!this._fetchHandlerWrap) {\n /* `current` says whether this read is still the one the grid shows - a replaced read tells the grid nothing. */\n this._fetchHandlerWrap = async (options: FetchOption, current: () => boolean = () => true) => {\n if (!this._fetchHandler) {\n return\n }\n\n try {\n this.consumer?.showSpinner()\n const result = await (this._fetchHandler || EMPTY_FETCHHANDLER)(options)\n current() && this.consumer?.fetchSucceeded?.()\n return result\n } catch (error) {\n /*\n * A failed read is not an empty list. The grid is told, so it can say \"could not load\"\n * instead of \"nothing to show\" - and the error still reaches whoever awaited the fetch.\n */\n current() && this.consumer?.fetchFailed?.(error)\n throw error\n } finally {\n this.consumer?.hideSpinner()\n }\n }\n }\n\n return this._fetchHandlerWrap\n }\n\n set fetchHandler(fetchHandler) {\n this._fetchHandler = fetchHandler\n delete this._fetchHandlerWrap\n }\n\n get sorters() {\n return this._sorters\n }\n\n set sorters(sorters) {\n this._sorters = sorters\n }\n\n /* alias for sorters */\n get sortings() {\n return this._sorters\n }\n\n set sortings(sorters) {\n this._sorters = sorters\n }\n\n get filters() {\n return this._filters\n }\n\n set filters(filters) {\n this._filters = filters\n }\n\n async attach(reset = false) {\n var { page = 0, limit = 20 } = this\n\n /*\n * page는 0 based index가 아님에 주의한다.\n * 즉, page 값이 1 은 첫페이지를 의미한다.\n */\n if (reset) {\n this.records = ZERO_RECORDS\n page = 1\n } else {\n /* attach의 경우는 grist data의 변경상태를 유지하기 위해서, grist._data 를 기반으로 한다. */\n this.records = this.consumer?._data ? this.consumer._data.records : ZERO_RECORDS\n page = page + 1\n }\n\n return this._update(\n {\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters: this.sorters,\n sortings: this.sorters,\n filters: this.filters,\n options: this.fetchOptions\n }))\n },\n reset\n )\n }\n\n async fetch({\n page = this.page,\n limit = this.limit,\n sorters,\n sortings,\n filters\n }: {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: FilterValue[]\n } = {}) {\n /* sortings property is only for things-factory server-side list parameter convention */\n /* fetchHandler should reture { page, limit, total, records } */\n this.records = ZERO_RECORDS\n\n sorters = sorters || sortings || this.sorters\n filters = filters || this.filters\n\n this.sorters = sorters\n\n /*\n * **The last fetch asked is the one the grid shows.**\n *\n * Two fetches can be out at once - the grid reading its address, then the screen laying its own conditions\n * over it a moment later. `_update` keeps the first answer to arrive and ignores the rest, so whichever came\n * back first stood: a ledger opened from the dashboard's 이번 달 순현금흐름 showed all 2,908 lines, the answer\n * to the read with no conditions, under a headroom that said October (2026-10-16). An answer to a fetch that a\n * later one has replaced - or its failure - is dropped, and the later answer is the one kept.\n */\n const sequence = ++this._fetchSequence\n const current = () => sequence === this._fetchSequence\n let answer\n try {\n answer = await this.fetchHandler.call(null, {\n page,\n limit,\n sorters,\n sortings: sorters,\n /* 안 쓰는 화면에 빈 칸을 보내지 않는다 — 옛 길 소비자의 fetchHandler 가 그날 안 바뀐다. */\n ...(this._search ? { search: this._search } : {}),\n filters,\n options: this.fetchOptions\n }, current)\n } catch (error) {\n if (!current()) return\n throw error\n }\n if (!current()) return\n\n return this._update({\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...answer\n })\n }\n\n async _update(\n {\n page,\n limit,\n total,\n records\n }: {\n page: number\n limit: number\n total: number\n records: GristRecord[]\n },\n reset?: boolean\n ): Promise<void> {\n // total을 감안해서 page가 최대값을 넘지 않도록 한다.\n var maxpage = _calculateTotalPage(limit, total)\n if (maxpage < page) {\n return await this.fetch({ page: maxpage, limit })\n }\n\n // page와 limit이 없는 경우 records 검사 전에 초기화\n this.page = this.page || page\n this.limit = this.limit || limit\n\n if (!records) {\n return\n }\n\n if (this.records === ZERO_RECORDS) {\n this.records = records\n } else if (this.page < page) {\n // attach인 경우에는 records를 append한다.\n this.records = [...this.records, ...records]\n } else {\n return\n }\n\n this.limit = limit\n this.total = total\n this.page = page\n\n this.consumer &&\n (this.consumer.data = {\n page: this.page,\n limit: this.limit,\n total: this.total,\n\n records: this.records\n })\n }\n}\n"]}
@@ -7,7 +7,7 @@ export const FilterCheckbox = (column, value, owner) => {
7
7
  ? filterLabel
8
8
  : typeof label === 'object' && label.renderer
9
9
  ? label.renderer(column)
10
- : header.renderer(column) || name;
10
+ : header.text || header.renderer(column) || name;
11
11
  // 텍스트 형태로 받았을시 의도가 boolean이면 boolean 타입으로 변환
12
12
  if (value === 'false') {
13
13
  value = false;
@@ -1 +1 @@
1
- {"version":3,"file":"filter-checkbox.js","sourceRoot":"","sources":["../../../src/filters/filter-checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,+BAA+B,CAAA;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAI/B,MAAM,CAAC,MAAM,cAAc,GAAyB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAC3E,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAE9C,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAA6B,CAAA;IAEtE,MAAM,SAAS,GACb,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ;YAC3C,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAA;IAEvC,6CAA6C;IAC7C,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,KAAK,GAAG,KAAK,CAAC;IAChB,CAAC;SAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,KAAK,GAAG,IAAI,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAA;;aAEA,MAAM,CAAC,IAAI;iBACP,KAAK;;uBAEC,KAAK,KAAK,SAAS;;gBAE1B,CAAC,CAAc,EAAE,EAAE;QAC3B,CAAC;QAAC,CAAC,CAAC,MAAsB,CAAC,aAAa,CACtC,IAAI,WAAW,CAAC,eAAe,EAAE;YAC/B,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,IAAI;gBACJ,QAAQ;gBACR,KAAK,EAAG,CAAC,CAAC,MAAqD,CAAC,OAAO;aACxE;SACF,CAAC,CACH,CAAA;IACH,CAAC;mCAC4B,SAAS;;GAEzC,CAAA;AACH,CAAC,CAAA","sourcesContent":["import '@operato/input/ox-checkbox.js'\n\nimport { html } from 'lit-html'\n\nimport { FilterConfigObject, FilterSelectRenderer } from '../types.js'\n\nexport const FilterCheckbox: FilterSelectRenderer = (column, value, owner) => {\n const { name, header, label, filter } = column\n\n const { label: filterLabel, operator } = filter! as FilterConfigObject\n\n const labelText =\n filterLabel !== undefined\n ? filterLabel\n : typeof label === 'object' && label.renderer\n ? label.renderer(column)\n : header.renderer(column) || name\n\n // 텍스트 형태로 받았을시 의도가 boolean이면 boolean 타입으로 변환\n if (value === 'false') {\n value = false;\n } else if (value === 'true') {\n value = true;\n }\n\n return html`\n <ox-checkbox\n name=${column.name}\n ?checked=${value}\n indeterminatable\n ?indeterminate=${value === undefined}\n left-label\n @change=${(e: CustomEvent) => {\n ;(e.target as HTMLElement).dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator,\n value: (e.target as Element & { checked: boolean | undefined }).checked\n }\n })\n )\n }}\n ><label filter-title><span>${labelText}</span></label></ox-checkbox\n >\n `\n}\n"]}
1
+ {"version":3,"file":"filter-checkbox.js","sourceRoot":"","sources":["../../../src/filters/filter-checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,+BAA+B,CAAA;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAI/B,MAAM,CAAC,MAAM,cAAc,GAAyB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAC3E,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAE9C,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAA6B,CAAA;IAEtE,MAAM,SAAS,GACb,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ;YAC3C,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;YACxB,CAAC,CAAE,MAA4B,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAA;IAE7E,6CAA6C;IAC7C,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,KAAK,GAAG,KAAK,CAAC;IAChB,CAAC;SAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,KAAK,GAAG,IAAI,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAA;;aAEA,MAAM,CAAC,IAAI;iBACP,KAAK;;uBAEC,KAAK,KAAK,SAAS;;gBAE1B,CAAC,CAAc,EAAE,EAAE;QAC3B,CAAC;QAAC,CAAC,CAAC,MAAsB,CAAC,aAAa,CACtC,IAAI,WAAW,CAAC,eAAe,EAAE;YAC/B,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,IAAI;gBACJ,QAAQ;gBACR,KAAK,EAAG,CAAC,CAAC,MAAqD,CAAC,OAAO;aACxE;SACF,CAAC,CACH,CAAA;IACH,CAAC;mCAC4B,SAAS;;GAEzC,CAAA;AACH,CAAC,CAAA","sourcesContent":["import '@operato/input/ox-checkbox.js'\n\nimport { html } from 'lit-html'\n\nimport { FilterConfigObject, FilterSelectRenderer } from '../types.js'\n\nexport const FilterCheckbox: FilterSelectRenderer = (column, value, owner) => {\n const { name, header, label, filter } = column\n\n const { label: filterLabel, operator } = filter! as FilterConfigObject\n\n const labelText =\n filterLabel !== undefined\n ? filterLabel\n : typeof label === 'object' && label.renderer\n ? label.renderer(column)\n : (header as { text?: string }).text || header.renderer(column) || name\n\n // 텍스트 형태로 받았을시 의도가 boolean이면 boolean 타입으로 변환\n if (value === 'false') {\n value = false;\n } else if (value === 'true') {\n value = true;\n }\n\n return html`\n <ox-checkbox\n name=${column.name}\n ?checked=${value}\n indeterminatable\n ?indeterminate=${value === undefined}\n left-label\n @change=${(e: CustomEvent) => {\n ;(e.target as HTMLElement).dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator,\n value: (e.target as Element & { checked: boolean | undefined }).checked\n }\n })\n )\n }}\n ><label filter-title><span>${labelText}</span></label></ox-checkbox\n >\n `\n}\n"]}
@@ -160,7 +160,7 @@ let OxFiltersForm = class OxFiltersForm extends LitElement {
160
160
  ? filterLabel
161
161
  : typeof label === 'object' && label.renderer
162
162
  ? label.renderer(column)
163
- : header.renderer(column) || name;
163
+ : header.text || header.renderer(column) || name;
164
164
  const idx = operator === 'between' ? 1 : 0;
165
165
  const renderer = getFilterRenderer(operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
166
166
  ? 'text'
@@ -1 +1 @@
1
- {"version":3,"file":"filters-form.js","sourceRoot":"","sources":["../../../src/filters/filters-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/input/ox-checkbox.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, PropertyValues, TemplateResult, nothing } from 'lit'\nimport { customElement, property, queryAsync, state } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\nimport { isMobileDevice } from '@operato/utils'\nimport { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles.js'\n\nimport { PagePreferenceProvider } from '@operato/p13n'\nimport { getDefaultValue } from '@operato/time-calculator'\n\nimport {\n ColumnConfig,\n FilterConfigObject,\n FilterPreference,\n FilterOperator,\n FilterValue,\n GristConfig,\n PersonalGristPreference\n} from '../types.js'\nimport { DataGrist } from '../data-grist.js'\nimport { FilterStyles } from './filter-styles.js'\nimport { getFilterRenderer } from './registry.js'\n\nexport type QueryFilterRangeValue = [from: number, to: number]\n\nexport type QueryFilter = {\n name: string\n operator: FilterOperator\n value: any\n}\n\n@customElement('ox-filters-form')\nexport class OxFiltersForm extends LitElement {\n static styles = [\n MDTypeScaleStyles,\n FilterStyles,\n css`\n :host {\n display: flex;\n padding: var(--spacing-small);\n }\n\n form {\n flex: 1;\n\n display: flex;\n flex-flow: row wrap;\n gap: var(--ox-filters-form-gap);\n }\n\n form > * {\n display: flex;\n align-items: center;\n gap: var(--input-intra-gap, 7px);\n }\n\n label span {\n display: block;\n }\n\n /* 모바일 필터 아코디언 토글 */\n .filters-toggle {\n display: none;\n }\n\n .filters-mobile-fold {\n flex: 1;\n display: contents;\n }\n\n @media only screen and (max-width: 460px) {\n :host([mobile-fold]) {\n flex-direction: column;\n }\n\n form {\n flex-direction: column;\n flex-flow: column;\n }\n\n :host([mobile-fold]) .filters-toggle {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 0;\n cursor: pointer;\n font-size: 14px;\n color: var(--secondary-color, #666);\n }\n\n :host([mobile-fold]) .filters-toggle md-icon {\n font-size: 18px;\n transition: transform 0.2s;\n }\n\n :host([mobile-fold]) .filters-toggle[open] md-icon {\n transform: rotate(180deg);\n }\n\n :host([mobile-fold]) .filters-mobile-fold {\n display: block;\n overflow: hidden;\n max-height: 0;\n transition: max-height 0.3s ease;\n }\n\n :host([mobile-fold]) .filters-mobile-fold[open] {\n max-height: 500px;\n }\n }\n `\n ]\n\n @property({ type: Array }) value: FilterValue[] = []\n @property({ type: Boolean, attribute: 'without-search' }) withoutSearch: boolean = false\n @property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true\n @property({ type: Boolean, attribute: 'empty', reflect: true }) empty: boolean = true\n @property({ type: Boolean, attribute: 'mobile-fold', reflect: true }) mobileFold: boolean = false\n\n @state() private _filtersOpen: boolean = true\n\n @state() personalConfigProvider?: PagePreferenceProvider\n @state() personalConfig?: PersonalGristPreference\n @state() personalFilters?: FilterPreference[]\n\n @state() config!: GristConfig\n @state() filterColumns: ColumnConfig[] = []\n @state() searchColumns: ColumnConfig[] = []\n\n @queryAsync('form') form!: HTMLFormElement\n\n private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}\n private objectValue?: object\n\n connectedCallback(): void {\n super.connectedCallback()\n\n /* 모바일에서 mobile-fold 모드일 때 필터 접힌 상태로 시작 */\n if (this.mobileFold && isMobileDevice()) {\n this._filtersOpen = false\n }\n\n const grist = this.closest('ox-grist') as DataGrist\n\n if (grist) {\n this.config = grist.compiledConfig\n this.personalConfigProvider = grist.personalConfigProvider\n\n grist.addEventListener('config-change', (e: Event) => {\n this.config = (e as CustomEvent).detail\n })\n\n grist.addEventListener('fetch-params-change', (e: Event) => {\n const { filters, from } = (e as CustomEvent).detail || {}\n if (from === 'filters-form') {\n return\n }\n\n this.value = filters\n })\n\n this.renderRoot.addEventListener('change', async (e: Event) => {\n const { target, detail: value } = e as CustomEvent\n const name = (target as HTMLInputElement).name\n const { filter } = this.filterColumns.find(filter => filter.name == name) || {}\n\n if (this.autoUpdateTargetsOnChange[name]) {\n /* 일단은 심플하게, boundTo로 연결된 필터값이 바뀌면, 폼 전체를 update하도록 함. */\n ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {\n const target = this.renderRoot.querySelector(`[name='${name}']`)\n if (target) {\n ;(target as HTMLInputElement).value = ''\n }\n })\n\n await this.updateObjectValues()\n this.requestUpdate()\n }\n\n const onchange = typeof filter == 'object' ? filter.onchange : null\n const keepGoing = onchange ? await onchange.call(null, value ?? (target as HTMLInputElement).value, this) : true\n\n keepGoing &&\n this.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n bubbles: true,\n composed: true,\n detail: {\n filters: await this.getQueryFilters(),\n from: 'filters-form'\n }\n })\n )\n })\n }\n\n // filter에 있는 캘린더 타입 input에 클릭 시 캘린더 오픈 이벤트 추가\n this.renderRoot.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLInputElement\n if (target.matches('[type=\"date\"], [type=\"time\"], [type=\"datetime-local\"], [type=\"month\"], [type=\"week\"]')) {\n target.showPicker()\n }\n })\n\n if (this.autofocus) {\n setTimeout(() => {\n this.focusFirstFormControl()\n }, 100)\n }\n }\n\n buildDefaultValue(operator: FilterOperator, defaultValue: any) {\n if (defaultValue === undefined) {\n return\n }\n if (operator == 'between') {\n return (defaultValue as Array<any>).map(v => getDefaultValue(v, this))\n } else {\n return getDefaultValue(defaultValue, this)\n }\n }\n\n async updated(changes: PropertyValues<this>) {\n /*\n * ── 둘을 함께 본다 — `else if` 가 설정 변화를 삼켰다 ───────────────────────\n *\n * 이 폼은 붙는 순간(`connectedCallback`)에 표에게서 설정과 개인 설정 제공자를 **한 번에**\n * 받는다. 그래서 첫 갱신에는 두 변화가 같은 주기에 들어온다.\n *\n * `else if` 였을 때는 앞 가지가 이겨서 **그 주기의 설정 변화가 버려졌다.** 표가 설정을 늦게\n * 주는 화면(참조 고르기 팝업)에서 필터 영역이 빈 채로 남던 이유가 이것이다.\n */\n if (changes.has('personalConfigProvider') && this.personalConfigProvider) {\n this.personalConfig = await this.personalConfigProvider.load()\n }\n\n if (changes.has('config') || changes.has('personalConfig')) {\n this.applyUpdatedConfiguration()\n }\n }\n\n render(): TemplateResult {\n const searchValue =\n (this.value?.find(filter => filter.operator === 'search')?.value as string)?.match(/^\\%(.*)\\%$/)?.[1] || ''\n\n return this.empty\n ? html``\n : html`\n <div\n class=\"filters-toggle\"\n ?open=${this._filtersOpen}\n @click=${() => {\n this._filtersOpen = !this._filtersOpen\n this.requestUpdate()\n }}\n >\n <md-icon>expand_more</md-icon>\n ${i18next.t('label.filter')}\n </div>\n <div class=\"filters-mobile-fold\" ?open=${this._filtersOpen}>\n <form\n class=\"md-typescale-body-medium-prominent\"\n @submit=${(e: Event) => {\n e.stopPropagation()\n e.preventDefault()\n\n const grist = this.closest('ox-grist') as DataGrist\n\n /* fetchFailed has already drawn a failure on the grid; this only stops an unhandled rejection. */\n grist && grist.fetch().catch(() => {})\n }}\n >\n ${this.filterColumns\n .filter(column => !(column.filter as FilterConfigObject).hidden)\n .map((column: ColumnConfig) => {\n const { name, header, label, filter } = column\n\n const type = (filter as FilterConfigObject).type\n\n if (type == 'search') {\n return html`\n <ox-input-search name=\"search\" .value=${searchValue} ?autofocus=${this.autofocus}></ox-input-search>\n `\n }\n\n const operator = (filter as FilterConfigObject).operator\n const filterLabel = (filter as FilterConfigObject).label\n\n const labelText =\n filterLabel !== undefined\n ? filterLabel\n : typeof label === 'object' && label.renderer\n ? label.renderer(column)\n : header.renderer(column) || name\n\n const idx = operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(\n operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'\n ? 'text'\n : type\n )[idx]\n const value =\n this.value?.find(filter => filter.name == name)?.value ??\n this.buildDefaultValue(operator!, (filter as FilterConfigObject)?.value)\n\n if (!renderer) {\n return html``\n }\n\n if (type === 'boolean' || type === 'checkbox') {\n return renderer(column, value, this)\n }\n\n const chooser =\n type !== 'select'\n ? renderer(column, value, this)\n : html`\n <ox-select\n name=${name}\n .value=${value}\n @change=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n detail: {\n name,\n operator,\n value: e.detail\n }\n })\n )}\n >\n ${operator === 'in'\n ? html`<ox-popup-list multiple attr-selected=\"checked\" with-search>\n ${renderer(column, value, this)}\n </ox-popup-list>`\n : html`<ox-popup-list with-search> ${renderer(column, value, this)} </ox-popup-list>`}\n </ox-select>\n `\n\n /*\n * Every filter says what it filters, beside its chooser - a select too. A select used to carry its\n * name only as a placeholder, which a chosen value replaces: the bar then showed 「진행 중」 with\n * nothing saying it was the status.\n */\n return labelText\n ? html`<label filter-title ?between=${operator === 'between'}><span>${labelText}</span> ${chooser}</label> `\n : chooser\n })}\n </form>\n </div>\n <slot name=\"setting\"></slot>\n `\n }\n\n applyUpdatedConfiguration() {\n if (!this.config) {\n return\n }\n\n const filters = this.config.columns.filter(columnConfig => !!columnConfig.filter)\n\n this.filterColumns = filters.filter((columnConfig: ColumnConfig) => {\n const filter = columnConfig.filter as FilterConfigObject\n return filter!.operator !== 'search'\n })\n this.searchColumns = filters.filter(columnConfig => {\n const filter = columnConfig.filter as FilterConfigObject\n return filter!.operator === 'search'\n })\n\n if (this.searchColumns.length > 0 && !this.withoutSearch) {\n this.filterColumns.unshift({ name: 'search', filter: { type: 'search' } } as any)\n }\n\n if (!this.personalConfig) {\n this.personalFilters = this.filterColumns.map(column => {\n return { name: column.name }\n })\n } else {\n const { filters: personalFilters = [] } = this.personalConfig\n\n if (personalFilters) {\n const xfilters = this.filterColumns.map(column => {\n return personalFilters.find(pFilter => pFilter.name == column.name) || { name: column.name }\n })\n\n function reorderList(a: FilterPreference[], b: FilterPreference[]): FilterPreference[] {\n // 결과 배열 초기화, a 배열 길이만큼 undefined로 채움\n const result = new Array(a.length)\n\n // b 배열에 없는 아이템은 원래 위치로 채움\n a.forEach((item, index) => {\n if (!item.name || !b.find(bi => bi.name == item.name)) {\n result[index] = item\n }\n })\n\n b.forEach(item => {\n const ai = a.find(ai => ai.name == item.name)\n if (ai) {\n result[result.findIndex(slot => slot === undefined)] = ai\n }\n })\n\n return result\n }\n\n // 배열 재정렬 실행\n this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterPreference[]\n\n this.filterColumns = this.personalFilters\n .map(filter => {\n const column = this.filterColumns.find(column => column.name == filter.name)\n if (column?.filter) {\n ;(column.filter as FilterConfigObject)!.hidden = filter.hidden\n }\n return column\n })\n .filter(Boolean) as ColumnConfig[]\n }\n }\n\n const grist = this.closest('ox-grist') as DataGrist\n\n this.value = (grist?.filters || []).map(filter => {\n return {\n ...filter,\n value: this.buildDefaultValue(filter!.operator, filter!.value)\n }\n })\n\n this.empty = (this.searchColumns.length === 0 || this.withoutSearch) && this.filterColumns.length === 0\n\n this.autoUpdateTargetsOnChange = {}\n this.filterColumns\n ?.filter(({ filter }) => {\n return typeof filter == 'object' && filter.boundTo && filter.boundTo.length > 0\n })\n .map(({ name, filter }) => {\n const boundTo = (filter as FilterConfigObject).boundTo\n\n boundTo!.forEach(to => {\n const origin = this.autoUpdateTargetsOnChange[to] || []\n if (name && !origin.includes(name)) {\n this.autoUpdateTargetsOnChange[to] = [...origin, name]\n }\n })\n })\n }\n\n async getQueryFilters(): Promise<QueryFilter[]> {\n const form = await this.form\n if (!form) return []\n\n const formData = new FormData(form)\n const search: string | undefined = formData.get('search')?.toString()\n\n var filters = this.filterColumns\n .filter(column => column.name !== 'search' && !(column.filter as FilterConfigObject)!.hidden)\n .map((column: ColumnConfig) => {\n const { name, type, filter } = column\n const operator = (filter as FilterConfigObject).operator\n\n var value = formData.getAll(name)\n if (value.length == 0) {\n return\n }\n\n if (-1 === value.findIndex(v => v !== '')) {\n return\n }\n\n const filterValue = value.map(v => {\n const value = v.toString()\n\n /* TODO registry에서 타입별로 parsing 방법을 지정할 수 있도록 해야한다. */\n switch (type) {\n case 'integer':\n case 'float':\n case 'number':\n case 'progress':\n case 'checkbox':\n case 'boolean':\n return !value ? undefined : JSON.parse(value)\n default:\n return value\n }\n })\n\n return {\n name,\n operator,\n value: filterValue.length === 1 ? filterValue[0] : filterValue\n }\n })\n .filter(result => result !== undefined) as QueryFilter[]\n\n if (search) {\n filters = filters.concat(\n this.searchColumns.map((column: ColumnConfig) => {\n const { name } = column\n\n return {\n name,\n operator: 'search',\n value: `%${search}%`\n }\n })\n )\n }\n\n return filters\n }\n\n public setInputValue(name: string, value: any) {\n const input = this.renderRoot.querySelector(`form [name=\"${name}\"]`) as HTMLInputElement\n if (input) {\n input.value = value\n input.dispatchEvent(new Event('change', { bubbles: true }))\n }\n }\n\n public getInputValue(name: string): any {\n const input = this.renderRoot.querySelector(`form [name=\"${name}\"]`) as HTMLInputElement\n return input?.value\n }\n\n private async focusFirstFormControl() {\n const form = await this.form\n if (!form) return\n\n // 첫번째가 input이면 autofocus, ox-input-search는 프로퍼티로 포커스 셋팅\n const target = form.querySelector('ox-input-search, input:not([type=\"hidden\"]):not(:disabled)') as HTMLInputElement\n if (target && target.tagName !== 'OX-INPUT-SEARCH') {\n target.focus()\n }\n }\n\n private async updateObjectValues() {\n const form = await this.form\n if (!form) return []\n\n const formData = new FormData(form)\n\n const object = {} as any\n formData.forEach((value, key) => {\n const prev = object[key]\n\n if (key in object) {\n object[key] = prev instanceof Array ? [...prev, value] : [prev, value]\n } else {\n object[key] = value\n }\n })\n\n this.objectValue = object\n }\n\n public getFormObjectValue() {\n return this.objectValue\n }\n\n reset() {\n this.form\n .then((form: HTMLFormElement) => {\n form.reset()\n })\n .catch((error: any) => {\n console.error('Error resetting the form:', error)\n })\n }\n}\n"]}
1
+ {"version":3,"file":"filters-form.js","sourceRoot":"","sources":["../../../src/filters/filters-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/input/ox-checkbox.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, PropertyValues, TemplateResult, nothing } from 'lit'\nimport { customElement, property, queryAsync, state } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\nimport { isMobileDevice } from '@operato/utils'\nimport { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles.js'\n\nimport { PagePreferenceProvider } from '@operato/p13n'\nimport { getDefaultValue } from '@operato/time-calculator'\n\nimport {\n ColumnConfig,\n FilterConfigObject,\n FilterPreference,\n FilterOperator,\n FilterValue,\n GristConfig,\n PersonalGristPreference\n} from '../types.js'\nimport { DataGrist } from '../data-grist.js'\nimport { FilterStyles } from './filter-styles.js'\nimport { getFilterRenderer } from './registry.js'\n\nexport type QueryFilterRangeValue = [from: number, to: number]\n\nexport type QueryFilter = {\n name: string\n operator: FilterOperator\n value: any\n}\n\n@customElement('ox-filters-form')\nexport class OxFiltersForm extends LitElement {\n static styles = [\n MDTypeScaleStyles,\n FilterStyles,\n css`\n :host {\n display: flex;\n padding: var(--spacing-small);\n }\n\n form {\n flex: 1;\n\n display: flex;\n flex-flow: row wrap;\n gap: var(--ox-filters-form-gap);\n }\n\n form > * {\n display: flex;\n align-items: center;\n gap: var(--input-intra-gap, 7px);\n }\n\n label span {\n display: block;\n }\n\n /* 모바일 필터 아코디언 토글 */\n .filters-toggle {\n display: none;\n }\n\n .filters-mobile-fold {\n flex: 1;\n display: contents;\n }\n\n @media only screen and (max-width: 460px) {\n :host([mobile-fold]) {\n flex-direction: column;\n }\n\n form {\n flex-direction: column;\n flex-flow: column;\n }\n\n :host([mobile-fold]) .filters-toggle {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 0;\n cursor: pointer;\n font-size: 14px;\n color: var(--secondary-color, #666);\n }\n\n :host([mobile-fold]) .filters-toggle md-icon {\n font-size: 18px;\n transition: transform 0.2s;\n }\n\n :host([mobile-fold]) .filters-toggle[open] md-icon {\n transform: rotate(180deg);\n }\n\n :host([mobile-fold]) .filters-mobile-fold {\n display: block;\n overflow: hidden;\n max-height: 0;\n transition: max-height 0.3s ease;\n }\n\n :host([mobile-fold]) .filters-mobile-fold[open] {\n max-height: 500px;\n }\n }\n `\n ]\n\n @property({ type: Array }) value: FilterValue[] = []\n @property({ type: Boolean, attribute: 'without-search' }) withoutSearch: boolean = false\n @property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true\n @property({ type: Boolean, attribute: 'empty', reflect: true }) empty: boolean = true\n @property({ type: Boolean, attribute: 'mobile-fold', reflect: true }) mobileFold: boolean = false\n\n @state() private _filtersOpen: boolean = true\n\n @state() personalConfigProvider?: PagePreferenceProvider\n @state() personalConfig?: PersonalGristPreference\n @state() personalFilters?: FilterPreference[]\n\n @state() config!: GristConfig\n @state() filterColumns: ColumnConfig[] = []\n @state() searchColumns: ColumnConfig[] = []\n\n @queryAsync('form') form!: HTMLFormElement\n\n private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}\n private objectValue?: object\n\n connectedCallback(): void {\n super.connectedCallback()\n\n /* 모바일에서 mobile-fold 모드일 때 필터 접힌 상태로 시작 */\n if (this.mobileFold && isMobileDevice()) {\n this._filtersOpen = false\n }\n\n const grist = this.closest('ox-grist') as DataGrist\n\n if (grist) {\n this.config = grist.compiledConfig\n this.personalConfigProvider = grist.personalConfigProvider\n\n grist.addEventListener('config-change', (e: Event) => {\n this.config = (e as CustomEvent).detail\n })\n\n grist.addEventListener('fetch-params-change', (e: Event) => {\n const { filters, from } = (e as CustomEvent).detail || {}\n if (from === 'filters-form') {\n return\n }\n\n this.value = filters\n })\n\n this.renderRoot.addEventListener('change', async (e: Event) => {\n const { target, detail: value } = e as CustomEvent\n const name = (target as HTMLInputElement).name\n const { filter } = this.filterColumns.find(filter => filter.name == name) || {}\n\n if (this.autoUpdateTargetsOnChange[name]) {\n /* 일단은 심플하게, boundTo로 연결된 필터값이 바뀌면, 폼 전체를 update하도록 함. */\n ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {\n const target = this.renderRoot.querySelector(`[name='${name}']`)\n if (target) {\n ;(target as HTMLInputElement).value = ''\n }\n })\n\n await this.updateObjectValues()\n this.requestUpdate()\n }\n\n const onchange = typeof filter == 'object' ? filter.onchange : null\n const keepGoing = onchange ? await onchange.call(null, value ?? (target as HTMLInputElement).value, this) : true\n\n keepGoing &&\n this.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n bubbles: true,\n composed: true,\n detail: {\n filters: await this.getQueryFilters(),\n from: 'filters-form'\n }\n })\n )\n })\n }\n\n // filter에 있는 캘린더 타입 input에 클릭 시 캘린더 오픈 이벤트 추가\n this.renderRoot.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLInputElement\n if (target.matches('[type=\"date\"], [type=\"time\"], [type=\"datetime-local\"], [type=\"month\"], [type=\"week\"]')) {\n target.showPicker()\n }\n })\n\n if (this.autofocus) {\n setTimeout(() => {\n this.focusFirstFormControl()\n }, 100)\n }\n }\n\n buildDefaultValue(operator: FilterOperator, defaultValue: any) {\n if (defaultValue === undefined) {\n return\n }\n if (operator == 'between') {\n return (defaultValue as Array<any>).map(v => getDefaultValue(v, this))\n } else {\n return getDefaultValue(defaultValue, this)\n }\n }\n\n async updated(changes: PropertyValues<this>) {\n /*\n * ── 둘을 함께 본다 — `else if` 가 설정 변화를 삼켰다 ───────────────────────\n *\n * 이 폼은 붙는 순간(`connectedCallback`)에 표에게서 설정과 개인 설정 제공자를 **한 번에**\n * 받는다. 그래서 첫 갱신에는 두 변화가 같은 주기에 들어온다.\n *\n * `else if` 였을 때는 앞 가지가 이겨서 **그 주기의 설정 변화가 버려졌다.** 표가 설정을 늦게\n * 주는 화면(참조 고르기 팝업)에서 필터 영역이 빈 채로 남던 이유가 이것이다.\n */\n if (changes.has('personalConfigProvider') && this.personalConfigProvider) {\n this.personalConfig = await this.personalConfigProvider.load()\n }\n\n if (changes.has('config') || changes.has('personalConfig')) {\n this.applyUpdatedConfiguration()\n }\n }\n\n render(): TemplateResult {\n const searchValue =\n (this.value?.find(filter => filter.operator === 'search')?.value as string)?.match(/^\\%(.*)\\%$/)?.[1] || ''\n\n return this.empty\n ? html``\n : html`\n <div\n class=\"filters-toggle\"\n ?open=${this._filtersOpen}\n @click=${() => {\n this._filtersOpen = !this._filtersOpen\n this.requestUpdate()\n }}\n >\n <md-icon>expand_more</md-icon>\n ${i18next.t('label.filter')}\n </div>\n <div class=\"filters-mobile-fold\" ?open=${this._filtersOpen}>\n <form\n class=\"md-typescale-body-medium-prominent\"\n @submit=${(e: Event) => {\n e.stopPropagation()\n e.preventDefault()\n\n const grist = this.closest('ox-grist') as DataGrist\n\n /* fetchFailed has already drawn a failure on the grid; this only stops an unhandled rejection. */\n grist && grist.fetch().catch(() => {})\n }}\n >\n ${this.filterColumns\n .filter(column => !(column.filter as FilterConfigObject).hidden)\n .map((column: ColumnConfig) => {\n const { name, header, label, filter } = column\n\n const type = (filter as FilterConfigObject).type\n\n if (type == 'search') {\n return html`\n <ox-input-search name=\"search\" .value=${searchValue} ?autofocus=${this.autofocus}></ox-input-search>\n `\n }\n\n const operator = (filter as FilterConfigObject).operator\n const filterLabel = (filter as FilterConfigObject).label\n\n const labelText =\n filterLabel !== undefined\n ? filterLabel\n : typeof label === 'object' && label.renderer\n ? label.renderer(column)\n : (header as { text?: string }).text || header.renderer(column) || name\n\n const idx = operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(\n operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'\n ? 'text'\n : type\n )[idx]\n const value =\n this.value?.find(filter => filter.name == name)?.value ??\n this.buildDefaultValue(operator!, (filter as FilterConfigObject)?.value)\n\n if (!renderer) {\n return html``\n }\n\n if (type === 'boolean' || type === 'checkbox') {\n return renderer(column, value, this)\n }\n\n const chooser =\n type !== 'select'\n ? renderer(column, value, this)\n : html`\n <ox-select\n name=${name}\n .value=${value}\n @change=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n detail: {\n name,\n operator,\n value: e.detail\n }\n })\n )}\n >\n ${operator === 'in'\n ? html`<ox-popup-list multiple attr-selected=\"checked\" with-search>\n ${renderer(column, value, this)}\n </ox-popup-list>`\n : html`<ox-popup-list with-search> ${renderer(column, value, this)} </ox-popup-list>`}\n </ox-select>\n `\n\n /*\n * Every filter says what it filters, beside its chooser - a select too. A select used to carry its\n * name only as a placeholder, which a chosen value replaces: the bar then showed 「진행 중」 with\n * nothing saying it was the status.\n */\n return labelText\n ? html`<label filter-title ?between=${operator === 'between'}><span>${labelText}</span> ${chooser}</label> `\n : chooser\n })}\n </form>\n </div>\n <slot name=\"setting\"></slot>\n `\n }\n\n applyUpdatedConfiguration() {\n if (!this.config) {\n return\n }\n\n const filters = this.config.columns.filter(columnConfig => !!columnConfig.filter)\n\n this.filterColumns = filters.filter((columnConfig: ColumnConfig) => {\n const filter = columnConfig.filter as FilterConfigObject\n return filter!.operator !== 'search'\n })\n this.searchColumns = filters.filter(columnConfig => {\n const filter = columnConfig.filter as FilterConfigObject\n return filter!.operator === 'search'\n })\n\n if (this.searchColumns.length > 0 && !this.withoutSearch) {\n this.filterColumns.unshift({ name: 'search', filter: { type: 'search' } } as any)\n }\n\n if (!this.personalConfig) {\n this.personalFilters = this.filterColumns.map(column => {\n return { name: column.name }\n })\n } else {\n const { filters: personalFilters = [] } = this.personalConfig\n\n if (personalFilters) {\n const xfilters = this.filterColumns.map(column => {\n return personalFilters.find(pFilter => pFilter.name == column.name) || { name: column.name }\n })\n\n function reorderList(a: FilterPreference[], b: FilterPreference[]): FilterPreference[] {\n // 결과 배열 초기화, a 배열 길이만큼 undefined로 채움\n const result = new Array(a.length)\n\n // b 배열에 없는 아이템은 원래 위치로 채움\n a.forEach((item, index) => {\n if (!item.name || !b.find(bi => bi.name == item.name)) {\n result[index] = item\n }\n })\n\n b.forEach(item => {\n const ai = a.find(ai => ai.name == item.name)\n if (ai) {\n result[result.findIndex(slot => slot === undefined)] = ai\n }\n })\n\n return result\n }\n\n // 배열 재정렬 실행\n this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterPreference[]\n\n this.filterColumns = this.personalFilters\n .map(filter => {\n const column = this.filterColumns.find(column => column.name == filter.name)\n if (column?.filter) {\n ;(column.filter as FilterConfigObject)!.hidden = filter.hidden\n }\n return column\n })\n .filter(Boolean) as ColumnConfig[]\n }\n }\n\n const grist = this.closest('ox-grist') as DataGrist\n\n this.value = (grist?.filters || []).map(filter => {\n return {\n ...filter,\n value: this.buildDefaultValue(filter!.operator, filter!.value)\n }\n })\n\n this.empty = (this.searchColumns.length === 0 || this.withoutSearch) && this.filterColumns.length === 0\n\n this.autoUpdateTargetsOnChange = {}\n this.filterColumns\n ?.filter(({ filter }) => {\n return typeof filter == 'object' && filter.boundTo && filter.boundTo.length > 0\n })\n .map(({ name, filter }) => {\n const boundTo = (filter as FilterConfigObject).boundTo\n\n boundTo!.forEach(to => {\n const origin = this.autoUpdateTargetsOnChange[to] || []\n if (name && !origin.includes(name)) {\n this.autoUpdateTargetsOnChange[to] = [...origin, name]\n }\n })\n })\n }\n\n async getQueryFilters(): Promise<QueryFilter[]> {\n const form = await this.form\n if (!form) return []\n\n const formData = new FormData(form)\n const search: string | undefined = formData.get('search')?.toString()\n\n var filters = this.filterColumns\n .filter(column => column.name !== 'search' && !(column.filter as FilterConfigObject)!.hidden)\n .map((column: ColumnConfig) => {\n const { name, type, filter } = column\n const operator = (filter as FilterConfigObject).operator\n\n var value = formData.getAll(name)\n if (value.length == 0) {\n return\n }\n\n if (-1 === value.findIndex(v => v !== '')) {\n return\n }\n\n const filterValue = value.map(v => {\n const value = v.toString()\n\n /* TODO registry에서 타입별로 parsing 방법을 지정할 수 있도록 해야한다. */\n switch (type) {\n case 'integer':\n case 'float':\n case 'number':\n case 'progress':\n case 'checkbox':\n case 'boolean':\n return !value ? undefined : JSON.parse(value)\n default:\n return value\n }\n })\n\n return {\n name,\n operator,\n value: filterValue.length === 1 ? filterValue[0] : filterValue\n }\n })\n .filter(result => result !== undefined) as QueryFilter[]\n\n if (search) {\n filters = filters.concat(\n this.searchColumns.map((column: ColumnConfig) => {\n const { name } = column\n\n return {\n name,\n operator: 'search',\n value: `%${search}%`\n }\n })\n )\n }\n\n return filters\n }\n\n public setInputValue(name: string, value: any) {\n const input = this.renderRoot.querySelector(`form [name=\"${name}\"]`) as HTMLInputElement\n if (input) {\n input.value = value\n input.dispatchEvent(new Event('change', { bubbles: true }))\n }\n }\n\n public getInputValue(name: string): any {\n const input = this.renderRoot.querySelector(`form [name=\"${name}\"]`) as HTMLInputElement\n return input?.value\n }\n\n private async focusFirstFormControl() {\n const form = await this.form\n if (!form) return\n\n // 첫번째가 input이면 autofocus, ox-input-search는 프로퍼티로 포커스 셋팅\n const target = form.querySelector('ox-input-search, input:not([type=\"hidden\"]):not(:disabled)') as HTMLInputElement\n if (target && target.tagName !== 'OX-INPUT-SEARCH') {\n target.focus()\n }\n }\n\n private async updateObjectValues() {\n const form = await this.form\n if (!form) return []\n\n const formData = new FormData(form)\n\n const object = {} as any\n formData.forEach((value, key) => {\n const prev = object[key]\n\n if (key in object) {\n object[key] = prev instanceof Array ? [...prev, value] : [prev, value]\n } else {\n object[key] = value\n }\n })\n\n this.objectValue = object\n }\n\n public getFormObjectValue() {\n return this.objectValue\n }\n\n reset() {\n this.form\n .then((form: HTMLFormElement) => {\n form.reset()\n })\n .catch((error: any) => {\n console.error('Error resetting the form:', error)\n })\n }\n}\n"]}
@@ -56,5 +56,33 @@ describe('필터 라벨', () => {
56
56
  expect((_b = (_a = label.querySelector('span')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()).to.equal(name);
57
57
  }
58
58
  });
59
+ /*
60
+ * A header may draw more than its words - a help `?` beside them. The filter is not the header: it names the column
61
+ * by its words, or a press on that `?` would also tick the checkbox around it.
62
+ */
63
+ it('names a filter by the header words when the header draws more', async () => {
64
+ const drawn = [
65
+ { type: 'checkbox', name: 'flag', header: { text: 'flag', renderer: () => html `flag <button class="extra">?</button>` }, filter: true },
66
+ { type: 'select', name: 'kind', header: { text: 'kind', renderer: () => html `kind <button class="extra">?</button>` }, record: { options: ['', 'A'] }, filter: true }
67
+ ];
68
+ const el = (await fixture(html `
69
+ <ox-grist
70
+ style="height: 300px"
71
+ mode="GRID"
72
+ .config=${{ columns: drawn, pagination: { pages: [20] } }}
73
+ .fetchHandler=${async () => ({ page: 1, limit: 20, total: 0, records: [] })}
74
+ >
75
+ <div slot="headroom"><ox-filters-form without-search></ox-filters-form></div>
76
+ </ox-grist>
77
+ `));
78
+ await settle();
79
+ const form = el.querySelector('ox-filters-form');
80
+ await form.updateComplete;
81
+ const root = form.renderRoot;
82
+ const deep = (node) => Array.from(node.querySelectorAll('*')).some(one => one.matches('button.extra') || (!!one.shadowRoot && deep(one.shadowRoot)));
83
+ expect(deep(root), 'the header drawing is not in the filter form').to.equal(false);
84
+ expect(root.textContent).to.contain('flag');
85
+ expect(root.textContent).to.contain('kind');
86
+ });
59
87
  });
60
88
  //# sourceMappingURL=filter-labels.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter-labels.test.js","sourceRoot":"","sources":["../../test/filter-labels.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */\nimport { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport '../src/data-grist.js'\nimport '../src/filters/filters-form.js'\n\n/*\n * Every filter in the form says what it filters, beside its chooser. A select once carried its name only as a\n * placeholder, which a chosen value replaces - the bar then showed 「진행 중」 with nothing saying it was the status.\n */\n\nconst columns = [\n { type: 'string', name: 'name', header: 'name', filter: 'i_like' },\n { type: 'select', name: 'status', header: 'status', record: { options: ['', 'OPEN', 'CLOSED'] }, filter: 'in' },\n { type: 'select', name: 'kind', header: 'kind', record: { options: ['', 'A', 'B'] }, filter: true },\n { type: 'date', name: 'day', header: 'day', filter: 'between' }\n]\n\nconst settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms))\n\ndescribe('필터 라벨', () => {\n const ignoreResizeLoop = (e: ErrorEvent) => {\n if (String(e.message).includes('ResizeObserver loop')) {\n e.stopImmediatePropagation()\n e.preventDefault()\n }\n }\n let previousOnError: OnErrorEventHandler = null\n\n before(() => {\n window.addEventListener('error', ignoreResizeLoop, true)\n previousOnError = window.onerror\n window.onerror = (message, ...rest) =>\n String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)\n })\n\n after(() => {\n window.removeEventListener('error', ignoreResizeLoop, true)\n window.onerror = previousOnError\n })\n\n it('every filter, a select too, sits in a label that names it', async () => {\n const el = (await fixture(html`\n <ox-grist\n style=\"height: 300px\"\n mode=\"GRID\"\n .config=${{ columns, pagination: { pages: [20] } }}\n .fetchHandler=${async () => ({ page: 1, limit: 20, total: 0, records: [] })}\n >\n <div slot=\"headroom\"><ox-filters-form without-search></ox-filters-form></div>\n </ox-grist>\n `)) as any\n await settle()\n\n const form = el.querySelector('ox-filters-form') as any\n await form.updateComplete\n const root = form.renderRoot as ShadowRoot\n const named = (name: string) => root.querySelector(`[name=\"${name}\"]`)\n for (const name of ['name', 'status', 'kind', 'day']) {\n const chooser = named(name)\n expect(!!chooser, `${name} is rendered`).to.equal(true)\n const label = chooser!.closest('label[filter-title]')\n expect(!!label, `${name} sits in a label`).to.equal(true)\n expect(label!.querySelector('span')?.textContent?.trim()).to.equal(name)\n }\n })\n})\n"]}
1
+ {"version":3,"file":"filter-labels.test.js","sourceRoot":"","sources":["../../test/filter-labels.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */\nimport { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport '../src/data-grist.js'\nimport '../src/filters/filters-form.js'\n\n/*\n * Every filter in the form says what it filters, beside its chooser. A select once carried its name only as a\n * placeholder, which a chosen value replaces - the bar then showed 「진행 중」 with nothing saying it was the status.\n */\n\nconst columns = [\n { type: 'string', name: 'name', header: 'name', filter: 'i_like' },\n { type: 'select', name: 'status', header: 'status', record: { options: ['', 'OPEN', 'CLOSED'] }, filter: 'in' },\n { type: 'select', name: 'kind', header: 'kind', record: { options: ['', 'A', 'B'] }, filter: true },\n { type: 'date', name: 'day', header: 'day', filter: 'between' }\n]\n\nconst settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms))\n\ndescribe('필터 라벨', () => {\n const ignoreResizeLoop = (e: ErrorEvent) => {\n if (String(e.message).includes('ResizeObserver loop')) {\n e.stopImmediatePropagation()\n e.preventDefault()\n }\n }\n let previousOnError: OnErrorEventHandler = null\n\n before(() => {\n window.addEventListener('error', ignoreResizeLoop, true)\n previousOnError = window.onerror\n window.onerror = (message, ...rest) =>\n String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)\n })\n\n after(() => {\n window.removeEventListener('error', ignoreResizeLoop, true)\n window.onerror = previousOnError\n })\n\n it('every filter, a select too, sits in a label that names it', async () => {\n const el = (await fixture(html`\n <ox-grist\n style=\"height: 300px\"\n mode=\"GRID\"\n .config=${{ columns, pagination: { pages: [20] } }}\n .fetchHandler=${async () => ({ page: 1, limit: 20, total: 0, records: [] })}\n >\n <div slot=\"headroom\"><ox-filters-form without-search></ox-filters-form></div>\n </ox-grist>\n `)) as any\n await settle()\n\n const form = el.querySelector('ox-filters-form') as any\n await form.updateComplete\n const root = form.renderRoot as ShadowRoot\n const named = (name: string) => root.querySelector(`[name=\"${name}\"]`)\n for (const name of ['name', 'status', 'kind', 'day']) {\n const chooser = named(name)\n expect(!!chooser, `${name} is rendered`).to.equal(true)\n const label = chooser!.closest('label[filter-title]')\n expect(!!label, `${name} sits in a label`).to.equal(true)\n expect(label!.querySelector('span')?.textContent?.trim()).to.equal(name)\n }\n })\n\n /*\n * A header may draw more than its words - a help `?` beside them. The filter is not the header: it names the column\n * by its words, or a press on that `?` would also tick the checkbox around it.\n */\n it('names a filter by the header words when the header draws more', async () => {\n const drawn = [\n { type: 'checkbox', name: 'flag', header: { text: 'flag', renderer: () => html`flag <button class=\"extra\">?</button>` }, filter: true },\n { type: 'select', name: 'kind', header: { text: 'kind', renderer: () => html`kind <button class=\"extra\">?</button>` }, record: { options: ['', 'A'] }, filter: true }\n ]\n const el = (await fixture(html`\n <ox-grist\n style=\"height: 300px\"\n mode=\"GRID\"\n .config=${{ columns: drawn, pagination: { pages: [20] } }}\n .fetchHandler=${async () => ({ page: 1, limit: 20, total: 0, records: [] })}\n >\n <div slot=\"headroom\"><ox-filters-form without-search></ox-filters-form></div>\n </ox-grist>\n `)) as any\n await settle()\n\n const form = el.querySelector('ox-filters-form') as any\n await form.updateComplete\n const root = form.renderRoot as ShadowRoot\n const deep = (node: ParentNode): boolean =>\n Array.from(node.querySelectorAll('*')).some(one => one.matches('button.extra') || (!!one.shadowRoot && deep(one.shadowRoot)))\n expect(deep(root), 'the header drawing is not in the filter form').to.equal(false)\n expect(root.textContent).to.contain('flag')\n expect(root.textContent).to.contain('kind')\n })\n})\n"]}
@@ -0,0 +1 @@
1
+ import '../src/data-grist.js';
@@ -0,0 +1,91 @@
1
+ import { expect, fixture } from '@open-wc/testing';
2
+ import { html } from 'lit';
3
+ import '../src/data-grist.js';
4
+ /**
5
+ * The last fetch asked is the one the grid shows.
6
+ *
7
+ * A ledger opened from a dashboard card asked twice in a row - once with no conditions as it read its address,
8
+ * then with the month the card named. The grid kept whichever answer arrived first - the read with no conditions -
9
+ * and showed every line under a headroom that said October (2026-10-16).
10
+ */
11
+ const config = {
12
+ columns: [
13
+ { type: 'string', name: 'id', hidden: true },
14
+ { type: 'string', name: 'name', header: 'name' }
15
+ ],
16
+ pagination: { pages: [20] }
17
+ };
18
+ const answer = (total) => ({
19
+ total,
20
+ records: Array.from({ length: Math.min(total, 20) }, (_, i) => ({ id: `${total}-${i}`, name: `row ${i}` }))
21
+ });
22
+ const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
23
+ describe('ox-grist with two fetches out at once', () => {
24
+ /* Resizing inside a fixture trips Chrome's benign ResizeObserver loop error; it says nothing about fetching. */
25
+ const ignoreResizeLoop = (e) => {
26
+ if (String(e.message).includes('ResizeObserver loop')) {
27
+ e.stopImmediatePropagation();
28
+ e.preventDefault();
29
+ }
30
+ };
31
+ let previousOnError = null;
32
+ before(() => {
33
+ window.addEventListener('error', ignoreResizeLoop, true);
34
+ previousOnError = window.onerror;
35
+ window.onerror = (message, ...rest) => String(message).includes('ResizeObserver loop') ? true : previousOnError === null || previousOnError === void 0 ? void 0 : previousOnError.call(window, message, ...rest);
36
+ });
37
+ after(() => {
38
+ window.removeEventListener('error', ignoreResizeLoop, true);
39
+ window.onerror = previousOnError;
40
+ });
41
+ /*
42
+ * The answer depends on the conditions, as on the ledger: the read with none, asked first, comes back first; the
43
+ * month's comes back after it. The grid fetches once by itself when attached; the test starts after that settled.
44
+ */
45
+ const MONTH = [{ name: 'month', operator: 'eq', value: 10 }];
46
+ const byConditions = (failUnfiltered = false) => async ({ filters }) => {
47
+ if (!(filters === null || filters === void 0 ? void 0 : filters.length)) {
48
+ await wait(20);
49
+ if (failUnfiltered)
50
+ throw new Error('the unfiltered read failed');
51
+ return answer(2908);
52
+ }
53
+ await wait(300);
54
+ return answer(4);
55
+ };
56
+ async function attached(handler) {
57
+ const el = (await fixture(html `<ox-grist style="height: 300px" .config=${config} .fetchHandler=${handler}></ox-grist>`));
58
+ await wait(400);
59
+ return el;
60
+ }
61
+ it('shows the answer to the later fetch, though the earlier one came back first', async () => {
62
+ const el = await attached(byConditions());
63
+ el.filters = [];
64
+ const unfiltered = el.fetch();
65
+ el.filters = MONTH;
66
+ const month = el.fetch();
67
+ await Promise.all([unfiltered, month]);
68
+ await el.updateComplete;
69
+ expect(el.data.total).to.equal(4);
70
+ });
71
+ it('does not report the failure of a fetch a later one replaced', async () => {
72
+ const el = await attached(byConditions(true));
73
+ el.filters = [];
74
+ const unfiltered = el.fetch().then(() => 'kept quiet', () => 'reported');
75
+ el.filters = MONTH;
76
+ await el.fetch();
77
+ expect(await unfiltered).to.equal('kept quiet');
78
+ await el.updateComplete;
79
+ expect(el.data.total).to.equal(4);
80
+ /* The grid draws "could not load" from fetchFailed - a replaced read must not make it say so. */
81
+ const body = el.renderRoot.querySelector('#grist');
82
+ expect(!!(body === null || body === void 0 ? void 0 : body.renderRoot.querySelector('ox-empty-note'))).to.equal(false);
83
+ });
84
+ it('still shows a single fetch as before', async () => {
85
+ const el = (await fixture(html `<ox-grist style="height: 300px" .config=${config} .fetchHandler=${async () => answer(7)}></ox-grist>`));
86
+ await el.fetch();
87
+ await el.updateComplete;
88
+ expect(el.data.total).to.equal(7);
89
+ });
90
+ });
91
+ //# sourceMappingURL=latest-fetch-wins.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latest-fetch-wins.test.js","sourceRoot":"","sources":["../../test/latest-fetch-wins.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAE1B,OAAO,sBAAsB,CAAA;AAE7B;;;;;;GAMG;AAEH,MAAM,MAAM,GAAG;IACb,OAAO,EAAE;QACP,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAC5C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;KACjD;IACD,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE;CAC5B,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC;IACjC,KAAK;IACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;CAC5G,CAAC,CAAA;AAEF,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AAI5E,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACrD,gHAAgH;IAChH,MAAM,gBAAgB,GAAG,CAAC,CAAa,EAAE,EAAE;QACzC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;YACtD,CAAC,CAAC,wBAAwB,EAAE,CAAA;YAC5B,CAAC,CAAC,cAAc,EAAE,CAAA;QACpB,CAAC;IACH,CAAC,CAAA;IACD,IAAI,eAAe,GAAwB,IAAI,CAAA;IAC/C,MAAM,CAAC,GAAG,EAAE;QACV,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAA;QACxD,eAAe,GAAG,MAAM,CAAC,OAAO,CAAA;QAChC,MAAM,CAAC,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,CACpC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;IAC5G,CAAC,CAAC,CAAA;IACF,KAAK,CAAC,GAAG,EAAE;QACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,GAAG,eAAe,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF;;;OAGG;IACH,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IAC5D,MAAM,YAAY,GAAG,CAAC,cAAc,GAAG,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,OAAO,EAA2B,EAAE,EAAE;QAC9F,IAAI,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,CAAA,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,EAAE,CAAC,CAAA;YACd,IAAI,cAAc;gBAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;YACjE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;QACf,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;IAClB,CAAC,CAAA;IAED,KAAK,UAAU,QAAQ,CAAC,OAAY;QAClC,MAAM,EAAE,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAA,2CAA2C,MAAM,kBAAkB,OAAO,cAAc,CAAC,CAGtH,CAAA;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;QACf,OAAO,EAAE,CAAA;IACX,CAAC;IAED,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAA;QAEzC,EAAE,CAAC,OAAO,GAAG,EAAE,CAAA;QACf,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,EAAE,CAAA;QAC7B,EAAE,CAAC,OAAO,GAAG,KAAK,CAAA;QAClB,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAA;QACxB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAA;QACtC,MAAM,EAAE,CAAC,cAAc,CAAA;QAEvB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;QAE7C,EAAE,CAAC,OAAO,GAAG,EAAE,CAAA;QACf,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAChC,GAAG,EAAE,CAAC,YAAY,EAClB,GAAG,EAAE,CAAC,UAAU,CACjB,CAAA;QACD,EAAE,CAAC,OAAO,GAAG,KAAK,CAAA;QAClB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAA;QAEhB,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAC/C,MAAM,EAAE,CAAC,cAAc,CAAA;QACvB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACjC,iGAAiG;QACjG,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAsD,CAAA;QACvG,MAAM,CAAC,CAAC,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,CAAC,aAAa,CAAC,eAAe,CAAC,CAAA,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,EAAE,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAA,2CAA2C,MAAM,kBAAkB,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAU,CAAA;QAC/I,MAAM,EAAE,CAAC,KAAK,EAAE,CAAA;QAChB,MAAM,EAAE,CAAC,cAAc,CAAA;QAEvB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport '../src/data-grist.js'\n\n/**\n * The last fetch asked is the one the grid shows.\n *\n * A ledger opened from a dashboard card asked twice in a row - once with no conditions as it read its address,\n * then with the month the card named. The grid kept whichever answer arrived first - the read with no conditions -\n * and showed every line under a headroom that said October (2026-10-16).\n */\n\nconst config = {\n columns: [\n { type: 'string', name: 'id', hidden: true },\n { type: 'string', name: 'name', header: 'name' }\n ],\n pagination: { pages: [20] }\n}\n\nconst answer = (total: number) => ({\n total,\n records: Array.from({ length: Math.min(total, 20) }, (_, i) => ({ id: `${total}-${i}`, name: `row ${i}` }))\n})\n\nconst wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))\n\ntype Grist = HTMLElement & { fetch(): Promise<void>; data: { total: number }; updateComplete: Promise<unknown> }\n\ndescribe('ox-grist with two fetches out at once', () => {\n /* Resizing inside a fixture trips Chrome's benign ResizeObserver loop error; it says nothing about fetching. */\n const ignoreResizeLoop = (e: ErrorEvent) => {\n if (String(e.message).includes('ResizeObserver loop')) {\n e.stopImmediatePropagation()\n e.preventDefault()\n }\n }\n let previousOnError: OnErrorEventHandler = null\n before(() => {\n window.addEventListener('error', ignoreResizeLoop, true)\n previousOnError = window.onerror\n window.onerror = (message, ...rest) =>\n String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)\n })\n after(() => {\n window.removeEventListener('error', ignoreResizeLoop, true)\n window.onerror = previousOnError\n })\n\n /*\n * The answer depends on the conditions, as on the ledger: the read with none, asked first, comes back first; the\n * month's comes back after it. The grid fetches once by itself when attached; the test starts after that settled.\n */\n const MONTH = [{ name: 'month', operator: 'eq', value: 10 }]\n const byConditions = (failUnfiltered = false) => async ({ filters }: { filters?: unknown[] }) => {\n if (!filters?.length) {\n await wait(20)\n if (failUnfiltered) throw new Error('the unfiltered read failed')\n return answer(2908)\n }\n await wait(300)\n return answer(4)\n }\n\n async function attached(handler: any) {\n const el = (await fixture(html`<ox-grist style=\"height: 300px\" .config=${config} .fetchHandler=${handler}></ox-grist>`)) as Grist & {\n filters: unknown[]\n renderRoot: ShadowRoot\n }\n await wait(400)\n return el\n }\n\n it('shows the answer to the later fetch, though the earlier one came back first', async () => {\n const el = await attached(byConditions())\n\n el.filters = []\n const unfiltered = el.fetch()\n el.filters = MONTH\n const month = el.fetch()\n await Promise.all([unfiltered, month])\n await el.updateComplete\n\n expect(el.data.total).to.equal(4)\n })\n\n it('does not report the failure of a fetch a later one replaced', async () => {\n const el = await attached(byConditions(true))\n\n el.filters = []\n const unfiltered = el.fetch().then(\n () => 'kept quiet',\n () => 'reported'\n )\n el.filters = MONTH\n await el.fetch()\n\n expect(await unfiltered).to.equal('kept quiet')\n await el.updateComplete\n expect(el.data.total).to.equal(4)\n /* The grid draws \"could not load\" from fetchFailed - a replaced read must not make it say so. */\n const body = el.renderRoot.querySelector('#grist') as (HTMLElement & { renderRoot: ShadowRoot }) | null\n expect(!!body?.renderRoot.querySelector('ox-empty-note')).to.equal(false)\n })\n\n it('still shows a single fetch as before', async () => {\n const el = (await fixture(html`<ox-grist style=\"height: 300px\" .config=${config} .fetchHandler=${async () => answer(7)}></ox-grist>`)) as Grist\n await el.fetch()\n await el.updateComplete\n\n expect(el.data.total).to.equal(7)\n })\n})\n"]}