@things-factory/meta-ui 8.0.0-beta.9 → 8.0.2

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.
Files changed (115) hide show
  1. package/client/bootstrap.ts +170 -0
  2. package/client/component/filter/filter-form-meta-code-select.ts +102 -0
  3. package/client/component/filter/filter-form-meta-object-select.ts +107 -0
  4. package/client/component/filter/filter-grist-meta-code-select.ts +97 -0
  5. package/client/component/filter/filter-grist-meta-object-select.ts +102 -0
  6. package/client/component/grist/editor/grist-editor-code-input.js +96 -0
  7. package/client/component/grist/editor/grist-editor-meta-code-selector.js +157 -0
  8. package/client/component/grist/editor/grist-editor-meta-object-selector.js +122 -0
  9. package/client/component/grist/renderer/grist-renderer-code-input.js +20 -0
  10. package/client/component/grist/renderer/grist-renderer-meta-code-selector.js +28 -0
  11. package/client/component/grist/renderer/grist-renderer-meta-object-selector.js +25 -0
  12. package/client/component/popup/code-input-editor-popup.js +111 -0
  13. package/client/component/popup/file-upload-popup.js +129 -0
  14. package/client/component/popup/meta-object-selector-popup.ts +356 -0
  15. package/client/component/popup/record-based-code-editor-popup.ts +141 -0
  16. package/client/dynamic-menus.ts +38 -0
  17. package/client/index.ts +18 -0
  18. package/client/load-components.ts +17 -0
  19. package/client/mixin/meta-base-mixin.js +323 -0
  20. package/client/mixin/meta-basic-grist-mixin.js +283 -0
  21. package/client/mixin/meta-button-mixin.js +116 -0
  22. package/client/mixin/meta-form-mixin.js +435 -0
  23. package/client/mixin/meta-grist-tab-mixin.js +335 -0
  24. package/client/mixin/meta-main-tab-mixin.js +267 -0
  25. package/client/mixin/meta-master-detail-mixin.js +395 -0
  26. package/client/mixin/meta-service-mixin.js +306 -0
  27. package/client/mixin/meta-tab-detail-mixin.js +283 -0
  28. package/client/mixin/meta-tab-mixin.js +190 -0
  29. package/client/pages/activity/meta-activity-define-page.js +422 -0
  30. package/client/pages/activity/meta-activity-list-page.js +262 -0
  31. package/client/pages/activity/meta-activity-viewer-element.js +35 -0
  32. package/client/pages/activity/meta-activity-writer-element.js +48 -0
  33. package/client/pages/activity/meta-activiy-mixin.js +79 -0
  34. package/client/pages/button-role/button-role-detail.js +50 -0
  35. package/client/pages/button-role/button-role-page.js +25 -0
  36. package/client/pages/doc-number/doc-number-page.js +24 -0
  37. package/client/pages/doc-number/next-doc-number-popup.js +25 -0
  38. package/client/pages/entity/config-entity.js +955 -0
  39. package/client/pages/entity/main-menu-selector.js +245 -0
  40. package/client/pages/history/history-copy-list-popup.js +145 -0
  41. package/client/pages/history/history-json-list-popup.js +159 -0
  42. package/client/pages/menu/dynamic-menu-template.js +92 -0
  43. package/client/pages/menu/dynamic-menu.ts +744 -0
  44. package/client/pages/menu/export-menu-popup.js +468 -0
  45. package/client/pages/meta-form-element.js +9 -0
  46. package/client/pages/meta-grist-element.js +12 -0
  47. package/client/pages/meta-grist-page.js +16 -0
  48. package/client/pages/meta-grist-tab-element.js +16 -0
  49. package/client/pages/meta-grist-tab-page.js +16 -0
  50. package/client/pages/meta-main-tab-element.js +12 -0
  51. package/client/pages/meta-main-tab-page.js +16 -0
  52. package/client/pages/meta-master-detail-element.js +12 -0
  53. package/client/pages/meta-master-detail-page.js +16 -0
  54. package/client/pages/meta-tab-detail-element.js +12 -0
  55. package/client/pages/meta-tab-detail-page.js +16 -0
  56. package/client/pages/meta-tab-element.js +15 -0
  57. package/client/pages/printer-device/printer-device-page.js +24 -0
  58. package/client/pages/template/doc-template-page.js +24 -0
  59. package/client/pages/template/template-file-page.js +24 -0
  60. package/client/pages/terms/config-terminology.js +214 -0
  61. package/client/pages/work-code/work-code-detail-popup.js +16 -0
  62. package/client/pages/work-code/work-code-page.js +23 -0
  63. package/client/route.ts +36 -0
  64. package/client/tsconfig.json +13 -0
  65. package/client/utils/grist-default-value.js +36 -0
  66. package/client/utils/meta-api.js +811 -0
  67. package/client/utils/meta-crypto.js +52 -0
  68. package/client/utils/meta-ui-util.js +3304 -0
  69. package/client/utils/rest-service-util.js +328 -0
  70. package/client/utils/service-util.js +1327 -0
  71. package/client/utils/terms-util.ts +119 -0
  72. package/client/utils/ui-util.js +338 -0
  73. package/client/utils/value-util.js +234 -0
  74. package/dist-client/tsconfig.tsbuildinfo +1 -1
  75. package/dist-client/utils/service-util.d.ts +2 -2
  76. package/dist-client/utils/service-util.js +4 -4
  77. package/dist-client/utils/service-util.js.map +1 -1
  78. package/dist-server/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +24 -24
  80. package/server/activity/CommonActivity.ts +68 -0
  81. package/server/index.ts +3 -0
  82. package/server/routes.ts +61 -0
  83. package/server/service/button-role/button-role-mutation.ts +105 -0
  84. package/server/service/button-role/button-role-query.ts +53 -0
  85. package/server/service/button-role/button-role-type.ts +39 -0
  86. package/server/service/button-role/button-role.ts +61 -0
  87. package/server/service/button-role/index.ts +7 -0
  88. package/server/service/dynamic-menu/dynamic-menu-query.ts +270 -0
  89. package/server/service/dynamic-menu/dynamic-menu-type.ts +74 -0
  90. package/server/service/dynamic-menu/index.ts +3 -0
  91. package/server/service/entity-event-subscriber/entity-event-subscriber.ts +80 -0
  92. package/server/service/entity-event-subscriber/index.ts +3 -0
  93. package/server/service/index.ts +41 -0
  94. package/server/service/menu-button-auth/index.ts +7 -0
  95. package/server/service/menu-button-auth/menu-button-auth-mutation.ts +133 -0
  96. package/server/service/menu-button-auth/menu-button-auth-query.ts +138 -0
  97. package/server/service/menu-button-auth/menu-button-auth-type.ts +63 -0
  98. package/server/service/menu-button-auth/menu-button-auth.ts +92 -0
  99. package/server/service/meta-activity/index.ts +5 -0
  100. package/server/service/meta-activity/meta-activity-mutation.ts +191 -0
  101. package/server/service/meta-activity/meta-activity-query.ts +43 -0
  102. package/server/service/meta-activity/meta-activity-type.ts +56 -0
  103. package/server/service/set-translations/index.ts +3 -0
  104. package/server/service/set-translations/set-translation-resolver.ts +63 -0
  105. package/server/service/work-code/index.ts +6 -0
  106. package/server/service/work-code/work-code-mutation.ts +147 -0
  107. package/server/service/work-code/work-code-query.ts +67 -0
  108. package/server/service/work-code/work-code-type.ts +60 -0
  109. package/server/service/work-code/work-code.ts +83 -0
  110. package/server/service/work-code-detail/index.ts +6 -0
  111. package/server/service/work-code-detail/work-code-detail-mutation.ts +149 -0
  112. package/server/service/work-code-detail/work-code-detail-query.ts +59 -0
  113. package/server/service/work-code-detail/work-code-detail-type.ts +50 -0
  114. package/server/service/work-code-detail/work-code-detail.ts +82 -0
  115. package/server/tsconfig.json +9 -0
@@ -0,0 +1,744 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@things-factory/form-ui'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { html } from 'lit'
6
+ import { customElement, property, state, query } from 'lit/decorators.js'
7
+
8
+ import { PageView } from '@operato/shell'
9
+ import { client } from '@operato/graphql'
10
+ import { i18next, localize } from '@operato/i18n'
11
+ import { p13n } from '@operato/p13n'
12
+ import { OxFiltersFormBase } from '@operato/form'
13
+
14
+ import { TermsUtil } from './../../utils/terms-util'
15
+ import { MetaApi } from '../../utils/meta-api'
16
+
17
+ import './dynamic-menu-template.js'
18
+ import './export-menu-popup.js'
19
+ import { ValueUtil } from '../../utils/value-util'
20
+ import { UiUtil } from '../../utils/ui-util'
21
+ import { DataGrist, FetchOption } from '@operato/data-grist'
22
+
23
+ @customElement('dynamic-menu')
24
+ export class DynamicMenu extends p13n(localize(i18next)(PageView)) {
25
+ static styles = [...MetaApi.getBasicMasterDetailGristStyle('top-down')]
26
+
27
+ @state() searchFields?: string[]
28
+ @state() groupConfig: any
29
+ @state() detailConfig: any
30
+
31
+ @query('ox-filters-form-base') searchForm!: OxFiltersFormBase
32
+ @query('#master-grist') groupGrist!: DataGrist
33
+ @query('#detail-grist') detailGrist!: DataGrist
34
+
35
+ private menuGroupId?: string
36
+
37
+ render() {
38
+ return html`
39
+ <div slot="headroom" class="header">
40
+ <div class="filters">
41
+ <ox-filters-form-base
42
+ .filters=${this.searchFields || []}
43
+ @filters-change=${e => {
44
+ this.groupGrist?.fetch()
45
+ }}
46
+ ></ox-filters-form-base>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="container">
51
+ <div class="container_detail">
52
+ <!--h2>
53
+ <md-icon>list_alt</md-icon>${TermsUtil.tTitle('menu_group')}
54
+ </h2-->
55
+ <ox-grist
56
+ id="master-grist"
57
+ .config=${this.groupConfig}
58
+ .mode=${MetaApi.isMobileEnv() ? 'LIST' : 'GRID'}
59
+ .personalConfigProvider=${this.getPagePreferenceProvider('master-grist')!}
60
+ .fetchHandler=${this.fetchGroupHandler.bind(this)}
61
+ >
62
+ <ox-grist-personalizer slot="setting"></ox-grist-personalizer>
63
+ </ox-grist>
64
+ <div class="button-container">
65
+ <button @click=${e => this.saveGroup()}><md-icon>save</md-icon>${TermsUtil.tButton('save')}</button>
66
+ <button danger @click=${e => this.deleteGroup()}>
67
+ <md-icon>delete</md-icon>${TermsUtil.tButton('delete')}
68
+ </button>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="container_detail">
73
+ <ox-grist
74
+ id="detail-grist"
75
+ .config=${this.detailConfig}
76
+ .mode=${MetaApi.isMobileEnv() ? 'LIST' : 'GRID'}
77
+ .fetchHandler=${this.fetchDetailHandler.bind(this)}
78
+ .personalConfigProvider=${this.getPagePreferenceProvider('detail-grist')!}
79
+ explcit-fetch
80
+ >
81
+ <ox-grist-personalizer slot="setting"></ox-grist-personalizer>
82
+ </ox-grist>
83
+ <div class="button-container">
84
+ <button @click=${e => this.copyMenu()}><md-icon>content_copy</md-icon>${TermsUtil.tButton('copy')}</button>
85
+ <button @click=${e => this.saveMenu()}><md-icon>save</md-icon>${TermsUtil.tButton('save')}</button>
86
+ <button danger @click=${e => this.deleteMenu()}>
87
+ <md-icon>delete</md-icon>${TermsUtil.tButton('delete')}
88
+ </button>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ `
93
+ }
94
+
95
+ get context() {
96
+ return {
97
+ title: TermsUtil.tTitle('dynamic_menu')
98
+ }
99
+ }
100
+
101
+ /*******************************************/
102
+ /* 조회 */
103
+ /*******************************************/
104
+
105
+ /**
106
+ * @description 부모 메뉴 (메뉴 그룹) 선택시 하위 메뉴 리스트 조회
107
+ *********************************
108
+ * @param {Object} param0
109
+ */
110
+ async fetchDetailHandler({ page, limit = 999999, sorters = [{ name: 'rank' }, { name: 'name' }] }: FetchOption) {
111
+ if (this.menuGroupId) {
112
+ let filters = [
113
+ {
114
+ name: 'parentId',
115
+ operator: 'eq',
116
+ value: this.menuGroupId
117
+ },
118
+ ...(await this.searchForm.getQueryFilters()).filter(x => ['templateCode', 'templateText'].includes(x.name))
119
+ ]
120
+
121
+ let selectFields = `
122
+ id
123
+ name
124
+ rank
125
+ description
126
+ menuType
127
+ category
128
+ resourceUrl
129
+ routingType
130
+ routing
131
+ hiddenFlag
132
+ iconPath
133
+ parent {
134
+ id
135
+ name
136
+ routing
137
+ }
138
+ role {
139
+ id
140
+ name
141
+ description
142
+ }
143
+ `
144
+
145
+ limit = 999999
146
+ let fetchResult = await MetaApi.searchByPagination('dynamicMenus', filters, sorters, page, limit, selectFields)
147
+
148
+ if (fetchResult && fetchResult.records) {
149
+ fetchResult.records.forEach(x => {
150
+ x.parentId = this.menuGroupId
151
+ })
152
+ }
153
+
154
+ return fetchResult
155
+ }
156
+ }
157
+
158
+ /**
159
+ * @description 부모 메뉴 (메뉴 그룹) 조회
160
+ ****************************************
161
+ * @param {Object} param0
162
+ * @returns
163
+ */
164
+ async fetchGroupHandler({ page, limit = 999999, sorters = [{ name: 'rank' }, { name: 'name' }] }: FetchOption) {
165
+ // 선택된 부모 메뉴 ID 초기화
166
+ this.menuGroupId = ''
167
+
168
+ if (this.detailGrist && this.detailGrist.data) {
169
+ this.detailGrist.data = { records: [] }
170
+ }
171
+
172
+ let filters = [...(await this.searchForm.getQueryFilters()), { name: 'parentId', operator: 'is_null', value: '' }]
173
+
174
+ let selectFields = `
175
+ id
176
+ name
177
+ rank
178
+ description
179
+ menuType
180
+ category
181
+ resourceUrl
182
+ routing
183
+ hiddenFlag
184
+ iconPath
185
+ role {
186
+ id
187
+ name
188
+ description
189
+ }
190
+ `
191
+ limit = 999999
192
+ return await MetaApi.searchByPagination('dynamicMenus', filters, sorters, page, limit, selectFields)
193
+ }
194
+
195
+ /*******************************************/
196
+ /* 트랜잭션 (저장 , 삭제) */
197
+ /*******************************************/
198
+
199
+ /**
200
+ * 메뉴 그룹 Create / Update
201
+ */
202
+ async saveGroup() {
203
+ var patches = this.groupGrist.dirtyRecords
204
+
205
+ if (ValueUtil.isNotEmpty(patches)) {
206
+ patches = patches.map(patch => {
207
+ const {
208
+ creator,
209
+ updater,
210
+ createdAt,
211
+ updatedAt,
212
+ __dirty__,
213
+ __dirtyfields__,
214
+ __origin__,
215
+ __seq__,
216
+ __selected__,
217
+ ...others
218
+ } = patch
219
+
220
+ patch = others
221
+
222
+ if (patch.hiddenFlag === undefined || patch.hiddenFlag == null) {
223
+ patch.hiddenFlag = false
224
+ }
225
+
226
+ patch.cuFlag = __dirty__
227
+
228
+ return patch
229
+ })
230
+
231
+ let result = await MetaApi.updateMultiple('updateMultipleMenu', patches)
232
+ if (result) {
233
+ this.groupGrist.fetch()
234
+ }
235
+ }
236
+ }
237
+
238
+ /**
239
+ * 메뉴 그룹 Delete
240
+ * @returns
241
+ */
242
+ async deleteGroup() {
243
+ await MetaApi.deleteListByGristSelected(this.groupGrist, 'deleteMenus')
244
+ }
245
+
246
+ /**
247
+ * 메뉴 Create / Update
248
+ */
249
+ async saveMenu() {
250
+ var patches = this.detailGrist.dirtyRecords
251
+
252
+ if (ValueUtil.isNotEmpty(patches)) {
253
+ patches = patches.map(patch => {
254
+ const {
255
+ creator,
256
+ updater,
257
+ createdAt,
258
+ updatedAt,
259
+ __dirty__,
260
+ __dirtyfields__,
261
+ __origin__,
262
+ __seq__,
263
+ __selected__,
264
+ ...others
265
+ } = patch
266
+
267
+ patch = others
268
+ patch.menuType = patch.menuType || 'SCREEN'
269
+
270
+ if (!patch.parentId) {
271
+ patch.parent = { id: this.menuGroupId }
272
+ } else {
273
+ patch.parent = { id: patch.parentId }
274
+ }
275
+
276
+ delete patch.parentId
277
+
278
+ if (patch.hiddenFlag === undefined || patch.hiddenFlag == null) {
279
+ patch.hiddenFlag = false
280
+ }
281
+
282
+ patch.cuFlag = __dirty__
283
+
284
+ return patch
285
+ })
286
+
287
+ const response = await client.mutate({
288
+ mutation: gql`
289
+ mutation UpdateMultipleMenu($patches: [MenuPatch!]!) {
290
+ updateMultipleMenu(patches: $patches) {
291
+ id
292
+ }
293
+ }
294
+ `,
295
+ variables: {
296
+ patches
297
+ }
298
+ })
299
+
300
+ if (!response.errors) {
301
+ const result = response.data.updateMultipleMenu
302
+
303
+ if (result) {
304
+ this.detailGrist.fetch()
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ async exportMenu(record) {
311
+ let exportMenuElement = MetaApi.createCustomElement('export-menu-popup', 'export-menu-popup')
312
+
313
+ exportMenuElement.title = TermsUtil.tLabel('export')
314
+ ;(exportMenuElement as any).recordId = record.id
315
+ ;(exportMenuElement as any).recordName = record.name
316
+
317
+ await MetaApi.openPopupByElement(record.name, 'large', exportMenuElement, true)
318
+ }
319
+
320
+ /**
321
+ * 메뉴 Delete
322
+ * @returns
323
+ */
324
+ async deleteMenu() {
325
+ await MetaApi.deleteListByGristSelected(this.detailGrist, 'deleteMenus')
326
+ }
327
+
328
+ /**
329
+ * 메뉴 복사
330
+ */
331
+ async copyMenu() {
332
+ let selectMenus = this.detailGrist.selected
333
+
334
+ if (!selectMenus || selectMenus.length == 0) {
335
+ UiUtil.showAlertPopup('text.nothing_selected', 'text.there_is_no_selected_items', 'info', 'confirm')
336
+ return
337
+ }
338
+
339
+ let copyMenu = selectMenus[0]
340
+
341
+ if (!copyMenu.id) {
342
+ return
343
+ }
344
+
345
+ Object.keys(copyMenu).forEach(x => {
346
+ if (x.startsWith('__')) {
347
+ delete copyMenu[x]
348
+ }
349
+ })
350
+
351
+ let menu = await MetaApi.findOne('menu', copyMenu.id, 'template')
352
+ copyMenu.template = menu ? menu.template || '' : ''
353
+
354
+ copyMenu.rank = 99999
355
+ copyMenu.cuFlag = '+'
356
+
357
+ copyMenu.name = copyMenu.name + '-copy'
358
+ copyMenu.routing = copyMenu.routing + '-copy'
359
+ copyMenu.parent = { id: copyMenu.parentId }
360
+ delete copyMenu.id
361
+ delete copyMenu.parentId
362
+
363
+ let result = await MetaApi.updateMultiple('updateMultipleMenu', [copyMenu])
364
+ if (result) {
365
+ this.detailGrist.fetch()
366
+ }
367
+ }
368
+
369
+ groupMenuQuery(record) {
370
+ this.menuGroupId = record.id
371
+ this.detailGrist.fetch()
372
+ }
373
+
374
+ /**
375
+ * 메뉴 템플릿을 편집 할 수 있는 팝업을 오픈한다.
376
+ * @param {Object} record
377
+ */
378
+ async openMenuTemplatePopup(record) {
379
+ let menuTemplateElement = MetaApi.createCustomElement('dynamic-menu-template', 'dynamic-menu-template')
380
+
381
+ menuTemplateElement.title = TermsUtil.tLabel('template')
382
+ ;(menuTemplateElement as any).recordId = record.id
383
+
384
+ await MetaApi.openPopupByElement(record.name, 'large', menuTemplateElement, true)
385
+ }
386
+
387
+ /**
388
+ * 메뉴 템플릿을 생성 할 수 있는 화면으로 이동한다.
389
+ * @param {Object} record
390
+ */
391
+ navigateMetaGenerator(record) {
392
+ MetaApi.pageNavigate(`meta-generator?menuId=${record.id}`)
393
+ }
394
+
395
+ /**
396
+ * LifeCycle - 화면 레더링 설정
397
+ */
398
+ async pageInitialized(lifecycle) {
399
+ // 조회 필드
400
+ this.searchFields = [
401
+ // name, type, label, operator, optionValues
402
+ MetaApi.getGristSearchColumnConfig('name', 'string', 'name', 'i_like'),
403
+ // name, type, label, operator, codeName
404
+ await MetaApi.getGristSearchCodeColumnConfig('menuType', 'select', 'menu_type', 'eq', 'MENU_TYPE'),
405
+ // name, type, label, operator
406
+ MetaApi.getGristSearchColumnConfig('hiddenFlag', 'checkbox', 'hidden', 'eq'),
407
+ await MetaApi.getGristSearchCodeColumnConfig(
408
+ 'templateCode',
409
+ 'select',
410
+ 'menu_template_search_code',
411
+ 'eq',
412
+ 'MENU_TEXT_SEARCH_TYPE'
413
+ ),
414
+ MetaApi.getGristSearchColumnConfig('templateText', 'string', 'menu_template_search_text', 'i_like')
415
+ ]
416
+
417
+ // 메뉴 그룹 그리드 설정
418
+ this.groupConfig = {
419
+ rows: MetaApi.getGristSelectableConfig(false),
420
+ // 공간이 부족해서 페이지네이션 제거
421
+ pagination: { infinite: true },
422
+ appendable: true,
423
+ columns: [
424
+ ...MetaApi.getGristGuttersConfig(true, false),
425
+ {
426
+ type: 'gutter',
427
+ gutterName: 'button',
428
+ icon: 'menu_open',
429
+ handlers: {
430
+ click: (_columns, _data, _column, record, _rowIndex) => {
431
+ if (record.id) {
432
+ this.groupMenuQuery(record)
433
+ }
434
+ }
435
+ }
436
+ },
437
+ {
438
+ type: 'integer',
439
+ name: 'rank',
440
+ header: TermsUtil.tLabel('rank'),
441
+ record: {
442
+ align: 'left',
443
+ editable: true,
444
+ format: '#,###'
445
+ },
446
+ sortable: false,
447
+ width: 60
448
+ },
449
+ // type, name, align, editable, sortable, width
450
+ MetaApi.getGristColumnConfig('string', 'name', 'left', true, false, 200),
451
+ {
452
+ type: 'string',
453
+ name: 'title',
454
+ header: TermsUtil.tLabel('title'),
455
+ record: {
456
+ editable: false,
457
+ align: 'left',
458
+ renderer: (value, column, record, rowIndex, field) => {
459
+ return record.name ? TermsUtil.tMenu(record.name) : ''
460
+ }
461
+ },
462
+ sortable: false,
463
+ width: 200
464
+ },
465
+ // name, displayName, align, sortable, width, mandatory, codeName
466
+ await MetaApi.getGristCodeSelectorColumnConfig('menuType', 'menu_type', 'left', false, 90, true, 'MENU_TYPE'),
467
+ // type, name, displayName, align, editable, sortable, width
468
+ MetaApi.getGristColumnConfig2('string', 'iconPath', 'icon', 'left', true, false, 115),
469
+ MetaApi.getGristColumnConfig2('boolean', 'hiddenFlag', 'hidden', 'center', true, false, 55),
470
+ MetaApi.getGristColumnConfig2('string', 'routing', 'routing', 'left', true, false, 135),
471
+ MetaApi.getGristColumnConfig2('string', 'category', 'tag', 'left', true, false, 135),
472
+ MetaApi.getGristColumnConfig2('string', 'resourceUrl', 'page_location', 'left', true, false, 350),
473
+ {
474
+ type: 'resource-object',
475
+ name: 'role',
476
+ label: true,
477
+ header: i18next.t('field.required role'),
478
+ record: {
479
+ editable: true,
480
+ options: {
481
+ title: i18next.t('title.lookup role'),
482
+ queryName: 'roles'
483
+ }
484
+ },
485
+ width: 200
486
+ }
487
+ ]
488
+ }
489
+
490
+ // 메뉴 그리드 설정
491
+ this.detailConfig = {
492
+ rows: MetaApi.getGristSelectableConfig(false),
493
+ // 공간이 부족해서 페이지네이션 제거
494
+ pagination: { infinite: true },
495
+ appendable: true,
496
+ columns: [
497
+ ...MetaApi.getGristGuttersConfig(true, false),
498
+ {
499
+ type: 'gutter',
500
+ gutterName: 'button',
501
+ icon: 'download',
502
+ handlers: {
503
+ click: (_columns, _data, _column, record, _rowIndex) => {
504
+ if (record.id) {
505
+ this.exportMenu(record)
506
+ }
507
+ }
508
+ }
509
+ },
510
+ {
511
+ type: 'gutter',
512
+ gutterName: 'button',
513
+ icon: 'code',
514
+ handlers: {
515
+ click: (_columns, _data, _column, record, _rowIndex) => {
516
+ if (record.id) {
517
+ this.openMenuTemplatePopup(record)
518
+ }
519
+ }
520
+ }
521
+ },
522
+ {
523
+ type: 'gutter',
524
+ gutterName: 'button',
525
+ icon: 'construction',
526
+ handlers: {
527
+ click: (_columns, _data, _column, record, _rowIndex) => {
528
+ if (record.id) {
529
+ this.navigateMetaGenerator(record)
530
+ }
531
+ }
532
+ }
533
+ },
534
+ {
535
+ type: 'integer',
536
+ name: 'rank',
537
+ header: TermsUtil.tLabel('rank'),
538
+ record: {
539
+ align: 'left',
540
+ editable: true,
541
+ format: '#,###'
542
+ },
543
+ sortable: false,
544
+ width: 60
545
+ },
546
+ MetaApi.getGristColumnConfig('string', 'name', 'left', true, false, 175),
547
+ {
548
+ type: 'string',
549
+ name: 'title',
550
+ header: TermsUtil.tLabel('title'),
551
+ record: {
552
+ editable: false,
553
+ align: 'left',
554
+ renderer: (value, column, record, rowIndex, field) => {
555
+ return record.name ? TermsUtil.tMenu(record.name) : ''
556
+ }
557
+ },
558
+ sortable: false,
559
+ width: 175
560
+ },
561
+ // name, displayName, align, sortable, width, mandatory, codeName
562
+ await MetaApi.getGristCodeSelectorColumnConfig(
563
+ 'menuType',
564
+ 'page_type',
565
+ 'left',
566
+ false,
567
+ 90,
568
+ true,
569
+ 'MENU_PAGE_TYPE'
570
+ ),
571
+ await MetaApi.getGristCodeSelectorColumnConfig(
572
+ 'routingType',
573
+ 'routing_type',
574
+ 'left',
575
+ false,
576
+ 0,
577
+ false,
578
+ 'MENU_PAGE_ROUTING_TYPE'
579
+ ),
580
+ // type, name, displayName, align, editable, sortable, width
581
+ MetaApi.getGristColumnConfig2('string', 'routing', 'routing', 'left', true, false, 175),
582
+ MetaApi.getGristColumnConfig2('string', 'category', 'tag', 'left', true, false, 175),
583
+ MetaApi.getGristColumnConfig2('string', 'resourceUrl', 'page_location', 'left', true, false, 450),
584
+ MetaApi.getGristColumnConfig2('string', 'iconPath', 'icon', 'left', true, false, 100),
585
+ MetaApi.getGristColumnConfig2('boolean', 'hiddenFlag', 'hidden', 'center', true, false, 55),
586
+ {
587
+ type: 'resource-object',
588
+ name: 'parent',
589
+ header: TermsUtil.tLabel('parent-menu'),
590
+ record: {
591
+ renderer: (value, column, record, rowIndex, field) => {
592
+ return value ? value.name + ' (' + TermsUtil.tMenu(value.name) + ')' : ''
593
+ },
594
+ editable: true,
595
+ options: {
596
+ title: TermsUtil.tLabel('parent-menu'),
597
+ queryName: 'menus',
598
+ pagination: { pages: [1000] },
599
+ basicArgs: {
600
+ filters: [
601
+ {
602
+ name: 'parentId',
603
+ operator: 'is_null'
604
+ }
605
+ ],
606
+ sortings: [
607
+ {
608
+ name: 'rank',
609
+ desc: false
610
+ }
611
+ ]
612
+ },
613
+ list: { fields: ['id', 'name'] },
614
+ columns: [
615
+ { name: 'id', hidden: true },
616
+ {
617
+ name: 'rank',
618
+ header: TermsUtil.tLabel('rank'),
619
+ width: 75,
620
+ record: {
621
+ editable: false,
622
+ format: '#,###',
623
+ align: 'left'
624
+ },
625
+ sortable: true
626
+ },
627
+ {
628
+ name: 'name',
629
+ width: 300,
630
+ header: TermsUtil.tLabel('name'),
631
+ filter: 'search'
632
+ },
633
+ {
634
+ name: 'description',
635
+ width: 350,
636
+ header: TermsUtil.tLabel('title'),
637
+ record: {
638
+ editable: false,
639
+ renderer: function (value, column, record, rowIndex, field) {
640
+ return TermsUtil.tMenu(record.name)
641
+ }
642
+ }
643
+ },
644
+ {
645
+ type: 'code',
646
+ name: 'menuType',
647
+ width: 120,
648
+ header: TermsUtil.tLabel('menu_type'),
649
+ record: {
650
+ editable: false,
651
+ codeName: 'MENU_TYPE'
652
+ }
653
+ },
654
+ {
655
+ name: 'routing',
656
+ width: 150,
657
+ header: TermsUtil.tLabel('routing'),
658
+ record: {
659
+ editable: false
660
+ }
661
+ }
662
+ ],
663
+ valueField: 'id',
664
+ nameField: 'name',
665
+ descriptionField: 'routing'
666
+ }
667
+ },
668
+ width: 200
669
+ },
670
+ {
671
+ type: 'resource-object',
672
+ name: 'role',
673
+ label: true,
674
+ header: i18next.t('field.required role'),
675
+ record: {
676
+ editable: true,
677
+ options: {
678
+ title: i18next.t('title.lookup role'),
679
+ queryName: 'roles'
680
+ }
681
+ },
682
+ width: 200
683
+ }
684
+ /*{
685
+ type: 'meta-code-selector',
686
+ header: TermsUtil.tLabel('parent-menu'),
687
+ name: 'parentId',
688
+ record: {
689
+ editable: true,
690
+ align: 'left',
691
+ options: {
692
+ codes: await ServiceUtil.getCodeByEntity({queryName:'menus', codeField:'id', dispField:'name', filters:[{ name: 'parentId', operator: 'is_null', value: '' }]}),
693
+ queryName: 'menus',
694
+ codeField: 'id',
695
+ dispField: 'name',
696
+ filterFields: [{name: 'name', operator: 'like'}],
697
+ selectorName: TermsUtil.tLabel('parent-menu'),
698
+ columns: [
699
+ {
700
+ name: 'id',
701
+ hidden: true
702
+ },
703
+ //MetaApi.getGristColumnConfig('integer', 'rank', 'right', false, true, 65),
704
+ {
705
+ type: 'integer',
706
+ name: 'rank',
707
+ header: TermsUtil.tLabel('rank'),
708
+ record: {
709
+ align: 'left',
710
+ editable: false,
711
+ format: '#,###'
712
+ },
713
+ sortable: false,
714
+ width: 65
715
+ },
716
+ MetaApi.getGristColumnConfig2('boolean', 'hiddenFlag', 'hidden', 'center', true, false, 60),
717
+ {
718
+ type:'select',
719
+ name: 'menuType',
720
+ header: 'menu_type',
721
+ record: {
722
+ align:'left',
723
+ editable: false
724
+ },
725
+ options:{
726
+ type: 'code',
727
+ name: 'MENU_TYPE'
728
+ },
729
+ sortable: false,
730
+ width: 100
731
+ },
732
+ MetaApi.getGristColumnConfig('string', 'name', 'left', false, true, 450)
733
+ ],
734
+ filters: [{ name: 'parentId', operator: 'is_null', value: '' }],
735
+ sorters: [{ name: 'rank', desc: false }],
736
+ }
737
+ },
738
+ sortable: false,
739
+ width: 120
740
+ }*/
741
+ ]
742
+ }
743
+ }
744
+ }