@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
@@ -0,0 +1,297 @@
1
+ import gql from 'graphql-tag'
2
+ import { client } from '@operato/graphql'
3
+ import { adjustFilters } from '@operato/utils'
4
+
5
+ import { MetaUtilMixin } from './meta-util-mixin'
6
+
7
+
8
+ /**
9
+ * GraphQL 호출
10
+ ******************************************************
11
+ * @param {Object} baseElement
12
+ * @returns
13
+ */
14
+ export const HandlerGraphqlMixin = (baseElement) => class extends MetaUtilMixin(baseElement) {
15
+
16
+ /**
17
+ * GraphQL Query 호출
18
+ ****************************************
19
+ * @returns {object}
20
+ */
21
+ async gqlQuery(page, limit, sorters, sortings, filters) {
22
+ // 조회 함수
23
+ let gqlQueryFunc = this.getParams(this.gqlInfo, 'query', 'list_func');
24
+
25
+ // element 의 경우 상위 데이터 parent_id 가 있다.
26
+ if (this.isElement) {
27
+ let gqlParentId = this.getParams(this.gqlInfo, 'query', 'parent_id');
28
+
29
+ if (this.isNotEmpty(gqlParentId)) {
30
+ if (this.isEmpty(this.parent_id)) {
31
+ // 상위 객체 아이디가 지정되지 않았으면 return
32
+ return;
33
+ }
34
+
35
+ filters = adjustFilters(filters, [
36
+ {
37
+ name: gqlParentId,
38
+ operator: "eq",
39
+ value: this.parent_id
40
+ }
41
+ ]);
42
+ }
43
+ }
44
+
45
+ // GraphQL 쿼리
46
+ let gqlQuery = `
47
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
48
+ ${gqlQueryFunc}(filters: $filters, pagination: $pagination, sortings: $sortings) {
49
+ items {
50
+ ${this.getViewElementColsToGql()}
51
+ }
52
+ total
53
+ }
54
+ }
55
+ `
56
+
57
+
58
+ // 페이지 처리
59
+ if (this.infinity_page === true) {
60
+ page = 0;
61
+ limit = 0;
62
+ }
63
+
64
+
65
+ // 요청 Object
66
+ let reqObject = {
67
+ query: gql`${gqlQuery}`,
68
+ variables: {
69
+ filters,
70
+ pagination: { page, limit },
71
+ sortings
72
+ }
73
+ }
74
+
75
+
76
+ // 요청
77
+ let response = await client.query(reqObject);
78
+
79
+ // 결과
80
+ return {
81
+ total: response.data[gqlQueryFunc].total || 0,
82
+ records: response.data[gqlQueryFunc].items || []
83
+ }
84
+ }
85
+
86
+ /**
87
+ * 레코드의 ID 를 이용해 데이터를 호출 한다.
88
+ * @param {String} id
89
+ */
90
+ async gqlFindOne(id) {
91
+ let gqlFindOneFunc = this.getParams(this.gqlInfo, 'query', 'find_one_func')
92
+
93
+ let gqlQuery = `
94
+ query ($id: String!) {
95
+ ${gqlFindOneFunc}(id: $id) {
96
+ ${this.getViewElementColsToGql()}
97
+ }
98
+ }`;
99
+
100
+ // 요청 Object
101
+ let reqObject = {
102
+ query: gql`${gqlQuery}`,
103
+ variables: { id: id }
104
+ }
105
+
106
+ // 요청
107
+ let response = await client.query(reqObject);
108
+
109
+ if (!response.errors) {
110
+ return response.data[gqlFindOneFunc] || [];
111
+ }
112
+ }
113
+
114
+
115
+ /**
116
+ * 화면에 그리스트 또는 폼 에서 GraphQl 조회 대상 컬럼을 추출한다.
117
+ * @returns {String}
118
+ */
119
+ getViewElementColsToGql() {
120
+ if (this.isNotEmpty(this.gqlFetchField)) {
121
+ return this.gqlFetchField;
122
+ }
123
+
124
+ // 그리스트가 있으면 그리드 설정셋에서 추출
125
+ if (this.grist) {
126
+ return this.getConfigsetToGql(this.gristConfigSet);
127
+ } else {
128
+ // 없으면 폼뷰 설정셋에서 추출
129
+ return this.getConfigsetToGql({ columns: this.formConfigSet });
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Grist 또는 Form 설정 셋 에서 컬럼을 추출 한다.
135
+ * @param {Array} configSet
136
+ * @returns
137
+ */
138
+ getConfigsetToGql(configSet) {
139
+ let gqlString = '';
140
+
141
+ configSet.columns.filter(x => x.type != 'gutter').forEach(x => {
142
+ gqlString += "\n"
143
+ gqlString += (x.type === 'object') == false ? x.name : `${x.name}\n{${this.getObjctColumnToGql(x)}}`;
144
+ })
145
+
146
+ this.gqlFetchField = gqlString;
147
+ return gqlString;
148
+ }
149
+
150
+ /**
151
+ * Object 타입의 컬럼은 별도의 컬럼 처리가 필요함.
152
+ ****************************************
153
+ * @param {Object} column
154
+ * @param {String} gqlString
155
+ * @returns
156
+ */
157
+ getObjctColumnToGql(column, gqlString) {
158
+ if (this.isEmpty(gqlString)) {
159
+ gqlString = '';
160
+ }
161
+
162
+ // 설정에 정의가 되어 있지 않으면 기본 id, name, description 필드
163
+ if (this.isEmpty(column.record.options) || this.isEmpty(column.record.options.select)) {
164
+ gqlString += "\nid\nname\ndescription";
165
+ } else {
166
+ // 설정에 정의가 되어 있으면
167
+ column.record.options.select.forEach(x => {
168
+ if (x.type !== 'object') {
169
+ gqlString += `\n${x.name}`;
170
+ }
171
+ })
172
+ }
173
+
174
+ return gqlString;
175
+ }
176
+
177
+
178
+ /**
179
+ * List 데이터 CU 호출
180
+ ********************************************
181
+ * @param {Array} patches
182
+ * @returns
183
+ */
184
+ async gqlCuMultiple(patches) {
185
+ let gqlMultipleFunc = this.getParams(this.gqlInfo, 'mutation', 'multiple', 'func')
186
+ let gqlMultipleType = this.getParams(this.gqlInfo, 'mutation', 'multiple', 'type')
187
+
188
+ // element 의 경우 상위 데이터 parent_id 가 있다.
189
+ if (this.isElement) {
190
+ let gqlParentId = this.getParams(this.gqlInfo, 'mutation', 'multiple', 'parent_id');
191
+ if (this.isNotEmpty(gqlParentId)) {
192
+ if (this.isEmpty(this.parent_id)) {
193
+ // 상위 객체 아이디가 지정되지 않았으면 return
194
+ return;
195
+ }
196
+
197
+ patches.forEach(x => {
198
+ patches.gqlParentId = this.parent_id;
199
+ })
200
+ }
201
+ }
202
+
203
+ const response = await client.query({
204
+ query: gql`
205
+ mutation ($patches: [${gqlMultipleType}!]!) {
206
+ ${gqlMultipleFunc}(patches: $patches) {
207
+ id
208
+ }
209
+ }
210
+ `,
211
+ variables: {
212
+ patches
213
+ },
214
+ context: {
215
+ hasUpload: true
216
+ }
217
+ });
218
+
219
+ return response;
220
+ }
221
+
222
+ /**
223
+ * String List ids 에 대하여 삭제 요청
224
+ *********************************************
225
+ * @param {Array} ids
226
+ */
227
+ async gqlDeletes(ids) {
228
+ let gqlDeleteFunc = this.getParams(this.gqlInfo, 'mutation', 'delete', 'func')
229
+
230
+ // delete 요청
231
+ const response = await client.query({
232
+ query: gql`
233
+ mutation ($ids: [String!]!) {
234
+ ${gqlDeleteFunc}(ids: $ids)
235
+ }
236
+ `,
237
+ variables: {
238
+ ids
239
+ }
240
+ })
241
+
242
+ return response;
243
+ }
244
+
245
+ /**
246
+ * 시나리오를 호출 한다.
247
+ *************************************************
248
+ * @param {String} scenarioName
249
+ * @param {Object} variables
250
+ */
251
+ async gqlCallScenario(scenarioName, variables) {
252
+
253
+ // scenario 호출
254
+ const response = await client.query({
255
+ query: gql`
256
+ mutation ($scenarioName: String!, $variables: Object) {
257
+ runScenario(scenarioName: $scenarioName, variables: $variables){
258
+ state
259
+ message
260
+ data
261
+ __typename
262
+ }
263
+ }
264
+ `,
265
+ variables: {
266
+ scenarioName: scenarioName,
267
+ variables: variables
268
+ }
269
+ })
270
+
271
+ return response;
272
+ }
273
+
274
+
275
+ /**********************************
276
+ * LifeCycle
277
+ ***********************************/
278
+
279
+ async connectedCallback() {
280
+ if (super.connectedCallback) {
281
+ await super.connectedCallback();
282
+ }
283
+ }
284
+
285
+ async firstUpdated() {
286
+ if (super.firstUpdated) {
287
+ await super.firstUpdated();
288
+ }
289
+ }
290
+
291
+ async pageInitialized() {
292
+ if (super.pageInitialized) {
293
+ await super.pageInitialized();
294
+ }
295
+ }
296
+
297
+ }
@@ -0,0 +1,119 @@
1
+ import { HandlerCustomButtonMixin } from "./handler-custom-button-mixin";
2
+
3
+ /**
4
+ * 그리드의 버튼을 핸들링
5
+ ******************************************************
6
+ * @param {Object} baseElement
7
+ * @returns
8
+ */
9
+ export const HandlerGristButtonMixin = (baseElement) => class extends HandlerCustomButtonMixin(baseElement) {
10
+
11
+
12
+ /**
13
+ * 그리스트 버튼에 대한 커스텀 액션 분기
14
+ *******************************************
15
+ * @param {Object} actionInfo
16
+ * @param {Object} record
17
+ */
18
+ async gristButtonHandler(actionInfo, record) {
19
+ let action = this.getParams(actionInfo, "logic");
20
+ let eventType = this.getParams(action, "type");
21
+
22
+ if (eventType === 'form') {
23
+ // 상세 폼뷰는 기본 정의된 로직으로 셋팅
24
+ action.tagname = "operation-master-form-view";
25
+ action.module = "chef";
26
+ action.location = "pages/master/operation/operation-master-form-view.js";
27
+ action.parent_field = "id";
28
+
29
+ await this.commonButtonOpenPopup(action, record);
30
+ } else if (eventType === 'pass_param') {
31
+ // 다른 객체로 파라미터 전달
32
+ this.gristButtonPassParam(action, record);
33
+ } else if (eventType === 'page') {
34
+ // page 이동
35
+ this.commonButtonPageNavigate(action, record);
36
+ } else if (eventType === 'popup') {
37
+ // popup 오픈
38
+ await this.commonButtonOpenPopup(action, record);
39
+ } else if (eventType === 'scenario') {
40
+ // scenario 호출
41
+ await this.commonButtonCallScenario(action, record);
42
+ } else if (eventType === 'value_reference') {
43
+ // 설정된 조건에 따라 커스텀 로직 처리
44
+ await this.gristButtonValueReference(action, record);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 설정된 조건과 record 의 값을 비교. 로직 처리
50
+ ************************************************
51
+ * @param {Object} config
52
+ * @param {Object} record
53
+ * @param {Object} params
54
+ */
55
+ async gristButtonValueReference(config, record) {
56
+ // 지정된 조건 Loop
57
+ for (let idx = 0; idx < config.relation.length; idx++) {
58
+ let relation = config.relation[idx];
59
+ let useRelation = this.compareObjectValues(relation, record, Object.keys(relation).filter(key => key != 'logic'));
60
+ if (useRelation === true) {
61
+ // 조건 체크 후 버튼 핸들러 호출
62
+ await this.gristButtonHandler(relation, record);
63
+ return;
64
+ }
65
+ }
66
+ }
67
+
68
+ /**
69
+ * 파라미터 전달 버튼 처리
70
+ ************************************************
71
+ * @param {Object} action
72
+ * @param {Object} record
73
+ */
74
+ gristButtonPassParam(action, record) {
75
+ // 파라미터 전달 정보
76
+ let passInfo = action.pass_field;
77
+
78
+ // Object Key 로 Element 를 검색.
79
+ Object.keys(passInfo).forEach(elementId => {
80
+ let tElement = this.shadowRoot.querySelector(`#${elementId}`);
81
+
82
+ // 대상 엘리먼트에 매치할 필드 정보
83
+ let matchInfo = passInfo[elementId];
84
+
85
+ // 필드 정보 Loop tField : target , sField : source
86
+ Object.keys(matchInfo).forEach(tField => {
87
+ let sField = matchInfo[tField];
88
+ // param 값이 * 이면 record 전체
89
+ let param = sField === "*" ? record : record[sField];
90
+
91
+ // tElement.tField 에 파라미터 set
92
+ tElement[tField] = param;
93
+ })
94
+ })
95
+ }
96
+
97
+ /**********************************
98
+ * LifeCycle
99
+ ***********************************/
100
+
101
+ async connectedCallback() {
102
+ if (super.connectedCallback) {
103
+ await super.connectedCallback();
104
+ }
105
+ }
106
+
107
+ async firstUpdated() {
108
+ if (super.firstUpdated) {
109
+ await super.firstUpdated();
110
+ }
111
+ }
112
+
113
+ async pageInitialized() {
114
+ if (super.pageInitialized) {
115
+ await super.pageInitialized();
116
+ }
117
+ }
118
+
119
+ }
@@ -0,0 +1,69 @@
1
+ import { store } from '@operato/shell'
2
+
3
+ import { HandlerGraphqlMixin } from './handler-graphql-mixin';
4
+
5
+ /**
6
+ * 메타 정보를 로드..
7
+ ******************************************************
8
+ * @param {Object} baseElement
9
+ * @returns
10
+ */
11
+ export const MetaSetMixin = (baseElement) => class extends HandlerGraphqlMixin(baseElement) {
12
+
13
+ /**
14
+ * 메뉴 메타 정보 가져오기
15
+ ************************************
16
+ * @description /meta/{domain} 의 디렉토리 먼저 검색
17
+ * @description /meta/default 도메인별 메타에 없으면 기본 설정 불러오기
18
+ * @param {String} subMenu
19
+ * @param {String} menu
20
+ */
21
+ getMetaInfo(subMenu, menu) {
22
+ console.log(store.getState())
23
+
24
+ let domainPath = store.getState().app.contextPath.replace("/domain/", "");
25
+ let menuMeta = {};
26
+
27
+ try {
28
+ // menuMeta = require(`./../meta/${domainPath}/${subMenu}/${menu}.json`); // 도메인내 우선 검색
29
+ menuMeta = require(`@operato/chef/client/meta/${domainPath}/${subMenu}/${menu}.json`); // 도메인내 우선 검색
30
+ } catch {
31
+ // menuMeta = require(`./../meta/default/${subMenu}/${menu}.json`); // 없으면 공통
32
+ menuMeta = require(`@operato/chef/client/meta/default/${subMenu}/${menu}.json`); // 없으면 공통
33
+ }
34
+
35
+ this.menuInfo = menuMeta.menu;
36
+ this.gridColumnConfig = menuMeta.grid_column;
37
+ this.gridConfig = menuMeta.grid;
38
+ this.buttonConfig = menuMeta.button;
39
+ this.searchConfig = menuMeta.search;
40
+ this.formColumnConfig = menuMeta.form_column;
41
+
42
+ this.gqlInfo = this.getParams(this.menuInfo, "gql");
43
+ }
44
+
45
+
46
+
47
+ /**********************************
48
+ * LifeCycle
49
+ ***********************************/
50
+
51
+ async connectedCallback() {
52
+ if (super.connectedCallback) {
53
+ await super.connectedCallback();
54
+ }
55
+ }
56
+
57
+ async firstUpdated() {
58
+ if (super.firstUpdated) {
59
+ await super.firstUpdated();
60
+ }
61
+ }
62
+
63
+ async pageInitialized() {
64
+ if (super.pageInitialized) {
65
+ await super.pageInitialized();
66
+ }
67
+ }
68
+
69
+ }