@things-factory/meta-ui 5.0.0-zeta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE.md +21 -0
  3. package/client/actions/main.js +1 -0
  4. package/client/bootstrap.js +8 -0
  5. package/client/index.js +23 -0
  6. package/client/mixin/handler-basic-button-mixin.js +202 -0
  7. package/client/mixin/handler-common-button-mixin.js +90 -0
  8. package/client/mixin/handler-custom-button-mixin.js +127 -0
  9. package/client/mixin/handler-graphql-mixin.js +297 -0
  10. package/client/mixin/handler-grist-button-mixin.js +119 -0
  11. package/client/mixin/meta-set-mixin.js +69 -0
  12. package/client/mixin/meta-util-mixin.js +577 -0
  13. package/client/mixin/render-basic-form-mixin.js +264 -0
  14. package/client/mixin/render-basic-grist-mixin.js +85 -0
  15. package/client/mixin/render-button-mixin.js +163 -0
  16. package/client/mixin/render-grist-mixin.js +478 -0
  17. package/client/mixin/render-search-mixin.js +37 -0
  18. package/client/pages/basic-form-element.js +9 -0
  19. package/client/pages/basic-grist-element.js +11 -0
  20. package/client/pages/basic-grist-page.js +12 -0
  21. package/client/pages/main.js +27 -0
  22. package/client/reducers/main.js +17 -0
  23. package/client/route.js +7 -0
  24. package/dist-server/controllers/index.js +1 -0
  25. package/dist-server/controllers/index.js.map +1 -0
  26. package/dist-server/index.js +20 -0
  27. package/dist-server/index.js.map +1 -0
  28. package/dist-server/middlewares/index.js +8 -0
  29. package/dist-server/middlewares/index.js.map +1 -0
  30. package/dist-server/migrations/index.js +12 -0
  31. package/dist-server/migrations/index.js.map +1 -0
  32. package/dist-server/routes.js +25 -0
  33. package/dist-server/routes.js.map +1 -0
  34. package/package.json +30 -0
  35. package/server/controllers/index.ts +0 -0
  36. package/server/index.ts +4 -0
  37. package/server/middlewares/index.ts +3 -0
  38. package/server/migrations/index.ts +9 -0
  39. package/server/routes.ts +28 -0
  40. package/things-factory.config.js +13 -0
  41. package/translations/en.json +1 -0
  42. package/translations/ko.json +1 -0
  43. package/translations/ms.json +1 -0
  44. package/translations/zh.json +1 -0
  45. package/tsconfig.json +9 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
+ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
+
8
+ <!-- ## [Unreleased] -->
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hatiolab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ export const UPDATE_META_UI = 'UPDATE_META_UI'
@@ -0,0 +1,8 @@
1
+ import { store } from '@things-factory/shell'
2
+ import metaUi from './reducers/main'
3
+
4
+ export default function bootstrap() {
5
+ store.addReducers({
6
+ metaUi
7
+ })
8
+ }
@@ -0,0 +1,23 @@
1
+ export * from './actions/main'
2
+
3
+
4
+ /** Mix In **/
5
+ export * from './mixin/handler-basic-button-mixin'
6
+ export * from './mixin/handler-common-button-mixin'
7
+ export * from './mixin/handler-custom-button-mixin'
8
+ export * from './mixin/handler-graphql-mixin'
9
+ export * from './mixin/handler-grist-button-mixin'
10
+
11
+ export * from './mixin/meta-set-mixin'
12
+ export * from './mixin/meta-util-mixin'
13
+ export * from './mixin/render-basic-form-mixin'
14
+ export * from './mixin/render-basic-grist-mixin'
15
+ export * from './mixin/render-button-mixin'
16
+ export * from './mixin/render-grist-mixin'
17
+ export * from './mixin/render-search-mixin'
18
+
19
+ /** Page **/
20
+ export * from './pages/basic-grist-page'
21
+
22
+ export * from './pages/basic-grist-element'
23
+ export * from './pages/basic-form-element'
@@ -0,0 +1,202 @@
1
+ import { HandlerCommonButtonMixin } from "./handler-common-button-mixin";
2
+ import { EXPORT } from '@things-factory/export-base'
3
+ import { store } from '@operato/shell'
4
+
5
+ /**
6
+ * 기본 Button 에 대한 이벤트 처리 ( import, export, save, delete, add )
7
+ ******************************************************
8
+ * @param {Object} baseElement
9
+ * @returns
10
+ */
11
+ export const HandlerBasicButtonMixin = (baseElement) => class extends HandlerCommonButtonMixin(baseElement) {
12
+
13
+
14
+
15
+ /****************************************
16
+ * 조회
17
+ *****************************************/
18
+
19
+ /**
20
+ * 리스트 조회
21
+ *******************************
22
+ * @param {Object} fetchParam
23
+ * @returns {Object}
24
+ */
25
+ async fetchHandler({ page = 0, limit = 0, sorters = [], sortings = [], filters = [] }) {
26
+ let formFilters = await this.filterForm?.getQueryFilters() || [];
27
+ return await this.gqlQuery(page, limit, sorters, sortings, formFilters);
28
+ }
29
+
30
+
31
+
32
+
33
+ /****************************************
34
+ * CUD
35
+ *****************************************/
36
+
37
+ /**
38
+ * 저장 버튼 처리
39
+ */
40
+ async save() {
41
+ const patches = this.getPatches();
42
+
43
+ // 변경된 내용이 없음
44
+ if (!patches || patches.length == 0) {
45
+ this.showCustomAlert('title.info', 'text.NOTHING_CHANGED');
46
+ return;
47
+ }
48
+
49
+ await this.requestCUMultiple(patches);
50
+ }
51
+
52
+ /**
53
+ * 저장 버튼, 생성 GraphQL Request
54
+ *****************************
55
+ * @param {Array} patches
56
+ */
57
+ async requestCUMultiple(patches) {
58
+ // CuMultiple 요청
59
+ let response = await this.gqlCuMultiple(patches);
60
+ if (!response.errors) {
61
+ this.showToast('text.Success to Process');
62
+
63
+ await this.fetch();
64
+ }
65
+ }
66
+
67
+
68
+ /**
69
+ * 엘리먼트 로드시 엑셀 import
70
+ */
71
+ async import() {
72
+ //TODO
73
+ }
74
+
75
+ /**
76
+ * 엘리먼트 로드시 엑셀 export
77
+ */
78
+ async export() {
79
+ await this._exportableData(this.grist);
80
+ }
81
+
82
+
83
+ /**
84
+ * 삭제 버튼 처리
85
+ */
86
+ async delete() {
87
+ const records = this.grist.selected;
88
+
89
+ // 삭제할 대상이 없어요.
90
+ if (!records || records.length == 0) {
91
+ this.showCustomAlert('title.info', 'text.there_is_nothing_to_delete');
92
+ return;
93
+ }
94
+
95
+ // 삭제 하시겠어요
96
+ const answer = await this.showCustomAlert('text.confirm', 'are_you_sure', 'warning', 'button.delete', 'button.cancel');
97
+ if (!answer.value) return
98
+
99
+ let ids = this.grist.selected.map(x => x.id);
100
+
101
+ // 삭제 요청
102
+ let response = await this.gqlDeletes(ids);
103
+
104
+ if (!response.errors) {
105
+ this.showToast('text.data_deleted_successfully');
106
+ this.grist.fetch();
107
+ }
108
+ }
109
+
110
+
111
+ /**
112
+ * 팝업으로 한건 생성
113
+ ***********************************************
114
+ * @param {Object} patches
115
+ * @returns {Boolean}
116
+ */
117
+ async recordCreationCallback(patches) {
118
+ patches = [{ ...patches, cuFlag: '+' }]
119
+ await this.requestCUMultiple(patches);
120
+ return true;
121
+ }
122
+
123
+
124
+
125
+
126
+ /**************************
127
+ * 기타
128
+ **************************/
129
+
130
+ /**
131
+ * 내보내기
132
+ **************************************
133
+ @ @param {Grist}
134
+ * @returns {Object} { header: headerSetting, data: data } or Not
135
+ */
136
+ async _exportableData(grist) {
137
+ if (this.isEmpty(grist)) {
138
+ grist = this.grist;
139
+ }
140
+
141
+ var headerSetting = grist._config.columns
142
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined && column.hidden !== true)
143
+ .map(column => {
144
+ return column.imex
145
+ })
146
+
147
+ let records = grist.data.records;
148
+
149
+ var data = records.map(item => {
150
+ return {
151
+ // id: item.id,
152
+ ...grist._config.columns
153
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined && column.hidden !== true)
154
+ .reduce((record, column) => {
155
+ record[column.imex.key] = column.imex.key
156
+ .split('.')
157
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
158
+ return record
159
+ }, {})
160
+ }
161
+ })
162
+
163
+ // element 로 호출된 경우 리턴 없이 바로 xlsx 내보내기
164
+ if (this.isElement) {
165
+ let extension = 'xlsx';
166
+
167
+ store.dispatch({
168
+ type: EXPORT,
169
+ exportable: {
170
+ extension,
171
+ name: this.convertMsgCode(this.getParams(this.menuInfo, 'title')),
172
+ data: { header: headerSetting, data: data }
173
+ }
174
+ })
175
+ } else {
176
+ return { header: headerSetting, data: data }
177
+ }
178
+ }
179
+
180
+
181
+ /**********************************
182
+ * LifeCycle
183
+ ***********************************/
184
+
185
+ async connectedCallback() {
186
+ if (super.connectedCallback) {
187
+ await super.connectedCallback();
188
+ }
189
+ }
190
+
191
+ async firstUpdated() {
192
+ if (super.firstUpdated) {
193
+ await super.firstUpdated();
194
+ }
195
+ }
196
+
197
+ async pageInitialized() {
198
+ if (super.pageInitialized) {
199
+ await super.pageInitialized();
200
+ }
201
+ }
202
+ }
@@ -0,0 +1,90 @@
1
+ import { MetaSetMixin } from "./meta-set-mixin";
2
+
3
+ /**
4
+ * 기본 Button 에 대한 이벤트 처리 ( import, export, save, delete, add )
5
+ ******************************************************
6
+ * @param {Object} baseElement
7
+ * @returns
8
+ */
9
+ export const HandlerCommonButtonMixin = (baseElement) => class extends MetaSetMixin(baseElement) {
10
+
11
+
12
+ /**
13
+ * 패이지 이동 버튼 처리
14
+ ***************************************
15
+ * @param {Object} action
16
+ * @param {Object} record
17
+ */
18
+ commonButtonPageNavigate(action, record) {
19
+ this.pageNavite(action.url, record);
20
+ }
21
+
22
+ /**
23
+ * 팝업 오픈 버튼 처리
24
+ *********************************************
25
+ * @param {Object} action
26
+ * @param {Object} record
27
+ */
28
+ async commonButtonOpenPopup(action, record) {
29
+ // 타이틀 변환
30
+ let title = this.convertMsgCode(action.title);
31
+
32
+ // 타이틀 상세 필드 정의 확인
33
+ if (this.isNotEmpty(action.title_detail)) {
34
+ title = `${title}(${record[action.title_detail]})`
35
+ }
36
+ // 팝업 오픈
37
+ this.openDynamicPopup(title, action, record)
38
+ }
39
+
40
+ /**
41
+ * 시나리오 호출 버튼 처리
42
+ ******************************************
43
+ * @param {Object} action
44
+ * @param {Object or Array} params
45
+ */
46
+ async commonButtonCallScenario(action, params) {
47
+
48
+ // 시나리오 호출
49
+ let response = await this.gqlCallScenario(action.name, params);
50
+
51
+ // 처리중 에러가 발생했으면
52
+ if (response.errors) {
53
+ return;
54
+ }
55
+
56
+ // 시나리오 호출 후처리가 없으면 return
57
+ if (this.isEmpty(action.after)) {
58
+ return;
59
+ }
60
+
61
+ // 후처리가 fetch 이면 그리스트 조회
62
+ if (action === 'fetch') {
63
+ this.grist.fetch();
64
+ }
65
+ }
66
+
67
+
68
+
69
+ /**********************************
70
+ * LifeCycle
71
+ ***********************************/
72
+
73
+ async connectedCallback() {
74
+ if (super.connectedCallback) {
75
+ await super.connectedCallback();
76
+ }
77
+ }
78
+
79
+ async firstUpdated() {
80
+ if (super.firstUpdated) {
81
+ await super.firstUpdated();
82
+ }
83
+ }
84
+
85
+ async pageInitialized() {
86
+ if (super.pageInitialized) {
87
+ await super.pageInitialized();
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,127 @@
1
+ import { HandlerBasicButtonMixin, HandlerBasicEventMixin } from "./handler-basic-button-mixin";
2
+
3
+ /**
4
+ * Custom Button 에 대한 이벤트 처리 ( import, export, save, delete, add ) 제외
5
+ ******************************************************
6
+ * @param {Object} baseElement
7
+ * @returns
8
+ */
9
+ export const HandlerCustomButtonMixin = (baseElement) => class extends HandlerBasicButtonMixin(baseElement) {
10
+ /**
11
+ * 커스텀 버튼에 대한 액션 분기
12
+ *******************************************
13
+ * @param {Object} logic
14
+ */
15
+ async customButtonHandler(logic) {
16
+ // logic 이 설정되지 않았으면 return
17
+ if (this.isEmpty(logic)) {
18
+ return;
19
+ }
20
+
21
+ let eventType = this.getParams(logic, 'type');
22
+ let paramInfo = this.getParams(logic, 'param');
23
+
24
+ let includeGristParams = paramInfo.filter(x => x.startsWith('grist'));
25
+
26
+ // 오류 메시지 처리
27
+ if (this.isNotEmpty(includeGristParams)) {
28
+ // 그리스트 존재 여부
29
+ if (!this.grist) {
30
+ // TODO
31
+ this.showCustomAlert('title.info', '그리드가 없습니다.')
32
+ return;
33
+ }
34
+
35
+ // 그리스트 데이터 존재 여부
36
+ if (((this.grist && this.grist.data) ? this.grist.data.records : []).length == 0) {
37
+ // 비어있는 그리드 입니다.
38
+ this.showCustomAlert('title.info', 'text.emptyGridMessage')
39
+ return;
40
+ }
41
+
42
+ if (paramInfo.includes('grist_one') || paramInfo.includes('grist_selected')) {
43
+ // 선택된 행이 있는지 확인
44
+ let selectedRows = this.grist ? this.grist.selected : [];
45
+
46
+ if (this.isEmpty(selectedRows)) {
47
+ // 선택된 항목이 없습니다.
48
+ this.showCustomAlert('title.info', 'text.there_is_no_selected_items')
49
+ return;
50
+ }
51
+
52
+ if (paramInfo.includes('grist_one')) {
53
+ // 하나의 행만 선택 되었는지 확인
54
+ if (selectedRows.length > 1) {
55
+ // TODO 하나의 항목만 선택해주세요.
56
+ this.showCustomAlert('title.info', '하나의 항목만 선택해주세요.')
57
+ return;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ let params = {};
64
+
65
+ if (paramInfo.includes("filter")) {
66
+ if (!this.filterForm) {
67
+ // TODO
68
+ this.showCustomAlert('title.info', '서치폼이 없습니다.')
69
+ return;
70
+ }
71
+ let filterValues = this.filterForm ? await this.filterForm.getQueryFilters() : [];
72
+ params['filter'] = filterValues;
73
+ }
74
+
75
+ if (paramInfo.includes('grist_all')) {
76
+ params['grist'] = this.grist.data.records;
77
+ } else if (paramInfo.includes('grist_one')) {
78
+ params['grist'] = this.grist.selected[0];
79
+ } else if (paramInfo.includes('grist_selected')) {
80
+ params['grist'] = this.grist.selected;
81
+ }
82
+
83
+ if (eventType === 'page') {
84
+ let convParam = {
85
+ ...(params['grist'] ? params['grist'] : {}),
86
+ ...(params['filter'] ? params['filter'] : {})
87
+ };
88
+
89
+ // page 이동
90
+ this.commonButtonPageNavigate(logic, convParam);
91
+ } else if (eventType === 'popup') {
92
+ let convParam = {
93
+ ...(params['grist'] ? params['grist'] : {}),
94
+ ...(params['filter'] ? params['filter'] : {})
95
+ };
96
+
97
+ // popup 오픈
98
+ await this.commonButtonOpenPopup(logic, convParam);
99
+ } else if (eventType === 'scenario') {
100
+ // scenario 호출
101
+ await this.commonButtonCallScenario(logic, params);
102
+ }
103
+ }
104
+
105
+ /**********************************
106
+ * LifeCycle
107
+ ***********************************/
108
+
109
+ async connectedCallback() {
110
+ if (super.connectedCallback) {
111
+ await super.connectedCallback();
112
+ }
113
+ }
114
+
115
+ async firstUpdated() {
116
+ if (super.firstUpdated) {
117
+ await super.firstUpdated();
118
+ }
119
+ }
120
+
121
+ async pageInitialized() {
122
+ if (super.pageInitialized) {
123
+ await super.pageInitialized();
124
+ }
125
+ }
126
+
127
+ }