@operato/scene-grist 7.3.11 → 7.3.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,417 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- *
4
- * grist 컴포넌트를 보조하여 grist의 각종 동작을 수행하는 컴포넌트.
5
- */
6
- import 'ses'
7
-
8
- import { Component, ComponentNature, Properties, RectPath, ValueHolder } from '@hatiolab/things-scene'
9
- import { DataGrist } from '@operato/data-grist'
10
- import { GristData, GristRecord, SorterConfig } from '@operato/data-grist/src/types.js'
11
-
12
- import SceneGrist from './grist'
13
-
14
- export enum ACTIONS {
15
- GET_ALL_ROWS = 'getAllRows',
16
- COMMIT = 'commit',
17
- GET_SELECTED = 'getSelectedRows',
18
- GET_DIRTY = 'getDirtyRows',
19
- ADD_ROW = 'addRow',
20
- DELETE_SELECTED_ROWS = 'deleteSelectedRowsSoftly',
21
- GET_PAGE_INFO = 'getPageInfo',
22
- GET_LIST_PARAM = 'getListParam'
23
- }
24
-
25
- const NATURE: ComponentNature = {
26
- mutable: false,
27
- resizable: true,
28
- rotatable: true,
29
- properties: [
30
- {
31
- // 대상 Grist
32
- type: 'id-input',
33
- label: 'target-grist',
34
- name: 'target',
35
- property: {
36
- component: 'grist'
37
- }
38
- },
39
- {
40
- // 동작
41
- type: 'select',
42
- label: 'action',
43
- name: 'action',
44
- property: {
45
- options: [
46
- {
47
- // 페이지네이션 정보 가져오기
48
- display: 'Get page information',
49
- value: ACTIONS.GET_PAGE_INFO
50
- },
51
- {
52
- // 페이지네이션 정보 가져오기
53
- display: 'Get ListParam',
54
- value: ACTIONS.GET_LIST_PARAM
55
- },
56
- {
57
- // 모든 레코드 데이터 가져오기
58
- display: 'Get all rows',
59
- value: ACTIONS.GET_ALL_ROWS
60
- },
61
- {
62
- // 체크된 레코드 데이터 가져오기
63
- display: 'Get selected rows',
64
- value: ACTIONS.GET_SELECTED
65
- },
66
- {
67
- // 변경 사항이 있는 데이터 가져오기
68
- display: 'Get dirty rows',
69
- value: ACTIONS.GET_DIRTY
70
- },
71
- {
72
- // 행 추가
73
- display: 'Add a row',
74
- value: ACTIONS.ADD_ROW
75
- },
76
- {
77
- // 선택 행 삭제
78
- display: 'Delete selected rows',
79
- value: ACTIONS.DELETE_SELECTED_ROWS
80
- },
81
- {
82
- // 변경 사항을 데이터에 적용
83
- display: 'Commit',
84
- value: ACTIONS.COMMIT
85
- }
86
- ]
87
- }
88
- },
89
- {
90
- // 뷰어 시작 시 자동 실행 여부
91
- type: 'checkbox',
92
- label: 'run-at-startup',
93
- name: 'runAtStartup'
94
- },
95
- {
96
- // 행 추가 시의 포맷
97
- type: 'textarea',
98
- label: 'record-adder-format',
99
- name: 'recordFormat'
100
- }
101
- ],
102
- help: 'scene/component/grist-action'
103
- }
104
-
105
- export default class GristAction extends ValueHolder(RectPath(Component)) {
106
- private _data: any
107
-
108
- get nature() {
109
- return NATURE
110
- }
111
-
112
- ready() {
113
- // 뷰어 시작시에도 action 값이 getPageInfo로 되어 있을 경우 fetchHandler를 등록하기 위해 onchange를 호출함
114
- this.onchange({ action: this.state.action })
115
- if (this.state.runAtStartup) {
116
- setTimeout(() => this.doAction(), 100)
117
- }
118
- }
119
-
120
- dispose() {
121
- super.dispose()
122
- }
123
-
124
- onclick() {
125
- // 컴포넌트 클릭 시 동작
126
- this.doAction()
127
- }
128
-
129
- onchange(after: Properties) {
130
- // value 값이 바뀌면 동작
131
- if ('value' in after) {
132
- this.doAction()
133
- }
134
-
135
- // action 값이 바뀌면 getPageInfo인지 확인하고 grist에 fetchHandler를 등록하거나 폐기함
136
- if ('action' in after) {
137
- const gristComponent = this.targetGristComponent
138
- const { refid } = this.state
139
-
140
- if (gristComponent) {
141
- if (after.action == ACTIONS.GET_PAGE_INFO) {
142
- gristComponent.beforeFetchFuncs[refid] = (fetchedData: {
143
- page: number
144
- limit: number
145
- total: number
146
- records: GristRecord[]
147
- }) => {
148
- this.data = this.getPageInfoFrom(null, fetchedData)
149
- this.doDataMap()
150
- }
151
- } else if (after.action == ACTIONS.GET_LIST_PARAM) {
152
- gristComponent.beforeFetchFuncs[refid] = (fetchedData: {
153
- page: number
154
- limit: number
155
- total: number
156
- records: GristRecord[]
157
- }) => {
158
- this.data = this.getListParamFrom(null, fetchedData)
159
- this.doDataMap()
160
- }
161
- } else {
162
- delete gristComponent.beforeFetchFuncs[refid]
163
- }
164
- }
165
- }
166
- }
167
-
168
- // 데이터 매핑을 수동으로 실행하기 위해 기존의 메소드를 무효화
169
- executeMappings() {
170
- console.debug(
171
- "[@operato/data-grist] The method 'executeMappings' is overriden in the component 'grist-action', because of to prevent executing when initialize."
172
- )
173
- }
174
-
175
- // 데이터 매핑을 수동으로 조작하기 위한 새 메소드
176
- doDataMap() {
177
- super.executeMappings()
178
- }
179
-
180
- // action 값에 따라 동작
181
- doAction(action?: ACTIONS) {
182
- if (!this.app.isViewMode) {
183
- return
184
- }
185
-
186
- // 파라미터가 명시되어있지 않으면 컴포넌트 속성에서 action 값을 가져옴
187
- var { action: storedAction } = this.state
188
- action = action || storedAction
189
-
190
- // 대상 Grist 컴포넌트
191
- var grist = this.targetGristElement
192
- if (!grist) return
193
-
194
- var data
195
- switch (action) {
196
- case ACTIONS.GET_ALL_ROWS:
197
- data = grist.grist.data
198
- break
199
- case ACTIONS.COMMIT:
200
- grist.commit()
201
- break
202
- case ACTIONS.GET_SELECTED:
203
- data = {
204
- patches: this.buildPatches(grist.selected),
205
- original: grist.selected
206
- }
207
- break
208
- case ACTIONS.GET_DIRTY:
209
- data = this.assortDirties(grist)
210
- break
211
- case ACTIONS.ADD_ROW:
212
- {
213
- var records = grist.dirtyData.records || []
214
- const c = new Compartment()
215
-
216
- let recordFormat
217
- try {
218
- recordFormat = c.evaluate(`(${this.state.recordFormat})`)
219
- } catch (e) {
220
- console.log('Invalid JSON format. It will be assumed as empty object.\n', e)
221
- recordFormat = {}
222
- }
223
- records.push({ ...recordFormat, __dirty__: '+' })
224
- this.refreshGrist(grist)
225
- }
226
- break
227
- case ACTIONS.DELETE_SELECTED_ROWS:
228
- {
229
- var records = grist.dirtyData.records || []
230
-
231
- records.forEach((record, idx) => {
232
- if (record['__selected__']) {
233
- if (record['__dirty__'] == '+') delete records[idx]
234
- else record['__dirty__'] = '-'
235
- }
236
- })
237
- grist.dirtyData.records = records.flat()
238
- this.refreshGrist(grist)
239
- }
240
- break
241
- case ACTIONS.GET_PAGE_INFO:
242
- data = this.getPageInfoFrom(grist)
243
- break
244
- case ACTIONS.GET_LIST_PARAM:
245
- data = this.getListParamFrom(grist)
246
- break
247
- }
248
-
249
- // 이 컴포넌트의 data 값이 바뀌는 동작은 데이터 매핑까지 실행함
250
- if (data) {
251
- this.data = data
252
- this.doDataMap()
253
- }
254
- }
255
-
256
- // 대상 grist 컴포넌트의 레코드를 새로고침
257
- refreshGrist(grist: DataGrist) {
258
- grist = grist || this.targetGristElement
259
- if (!grist) return
260
-
261
- grist.refresh()
262
- // grist.dataProvider.onRecordChange()
263
- grist.grist.data = { ...grist.dirtyData }
264
- }
265
-
266
- // 변경 사항이 있는 레코드의 경우, CUD를 분류해서 반환함
267
- assortDirties(grist: DataGrist) {
268
- const dirties = grist.dirtyRecords
269
- var patches = this.buildPatches(dirties)
270
- var records = {
271
- original: dirties,
272
- patches,
273
- created: [] as GristRecord[],
274
- updated: [] as GristRecord[],
275
- deleted: [] as GristRecord[]
276
- }
277
-
278
- patches.forEach((record: GristRecord) => {
279
- switch (record['cuFlag']) {
280
- case 'M':
281
- records.updated.push(record)
282
- break
283
- case '+':
284
- records.created.push(record)
285
- break
286
- case '-':
287
- records.deleted.push(record)
288
- break
289
- }
290
- })
291
- return records
292
- }
293
-
294
- // 페이지네이션 정보를 가져옴
295
- getPageInfoFrom(grist: DataGrist | null, fetchedData?: GristData) {
296
- // @ts-ignore
297
- var { page = 1, limit = 20, sorters = [] } = fetchedData || (grist && grist.dataProvider) || pagination(grist!)
298
-
299
- sorters = sorters.map((sorter: SorterConfig) => {
300
- sorter.desc = sorter.desc ? true : false
301
- return sorter
302
- })
303
- return { page, limit, sorters }
304
-
305
- function pagination(grist: DataGrist) {
306
- var config = grist && grist.config && grist.config.pagination
307
- if (config)
308
- return {
309
- page: config.page,
310
- limit: config.limit || (config.pages && config.pages[0])
311
- }
312
- else return {}
313
- }
314
- }
315
-
316
- // Grist로부터 ListParam 정보를 가져옴
317
- getListParamFrom(grist: DataGrist | null, fetchedData?: GristData) {
318
- var {
319
- page = 1,
320
- limit = 20,
321
- sorters,
322
- sortings,
323
- filters = [],
324
- inherited,
325
- options
326
- // @ts-ignore
327
- } = fetchedData || (grist && grist.dataProvider) || pagination(grist!)
328
-
329
- return {
330
- pagination: { page, limit },
331
- sortings: sorters || sortings,
332
- filters,
333
- inherited,
334
- options
335
- }
336
-
337
- function pagination(grist: DataGrist) {
338
- var config = grist && grist.config && grist.config.pagination
339
- if (config)
340
- return {
341
- page: config.page,
342
- limit: config.limit || (config.pages && config.pages[0])
343
- }
344
- else return {}
345
- }
346
- }
347
-
348
- // 레코드들을 서버 공통 resolver에 맞는 포맷으로 만듦
349
- buildPatches(patches: GristRecord[]): GristRecord[] {
350
- return patches.map(patch => {
351
- let patchField: { [key: string]: any } = patch.id ? { id: patch.id } : {}
352
- const dirtyFields = patch.__dirtyfields__
353
-
354
- for (let key in dirtyFields) {
355
- patchField[key] = dirtyFields[key].after
356
- }
357
- patchField.cuFlag = patch.__dirty__
358
-
359
- return patchField
360
- })
361
- }
362
-
363
- render(context: CanvasRenderingContext2D) {
364
- var { top, left, height, width, fillStyle = 'transparent' } = this.state
365
-
366
- // background의 색상
367
- context.beginPath()
368
- context.rect(left, top, width, height)
369
-
370
- context.fillStyle = fillStyle
371
- context.fill()
372
-
373
- // value의 색상
374
- context.beginPath()
375
-
376
- var drawValue = width - (width * Math.max(Math.min(this.animValue, 100), 0)) / 100
377
- drawValue = Math.max(Math.min(drawValue, width), 0)
378
-
379
- context.rect(left + drawValue, top, width - drawValue, height)
380
-
381
- this.drawFill(context)
382
-
383
- context.closePath()
384
-
385
- context.beginPath()
386
-
387
- context.rect(left, top, width, height)
388
- }
389
-
390
- postrender(context: CanvasRenderingContext2D) {
391
- this.drawStroke(context)
392
- this.drawText(context)
393
- }
394
-
395
- get controls() {
396
- return []
397
- }
398
-
399
- get targetGristComponent(): SceneGrist {
400
- var { target } = this.state
401
- return target && (this.root.findById(target) as SceneGrist)
402
- }
403
-
404
- get targetGristElement(): DataGrist | undefined {
405
- return this.targetGristComponent?.grist
406
- }
407
-
408
- get data() {
409
- return this._data
410
- }
411
-
412
- set data(data) {
413
- this._data = data
414
- }
415
- }
416
-
417
- Component.register('grist-action', GristAction)