@things-factory/i18n-base 7.0.1-alpha.9 → 7.0.1-alpha.92

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 (56) hide show
  1. package/client/bootstrap.ts +16 -0
  2. package/client/{index.js → index.ts} +0 -2
  3. package/client/page/terminology-page.ts +406 -0
  4. package/client/route.ts +7 -0
  5. package/config/config.development.js +29 -0
  6. package/config/config.production.js +29 -0
  7. package/dist-client/bootstrap.d.ts +6 -0
  8. package/dist-client/bootstrap.js +10 -0
  9. package/dist-client/bootstrap.js.map +1 -0
  10. package/dist-client/index.d.ts +5 -0
  11. package/dist-client/index.js +6 -0
  12. package/dist-client/index.js.map +1 -0
  13. package/dist-client/page/terminology-page.d.ts +79 -0
  14. package/dist-client/page/terminology-page.js +395 -0
  15. package/dist-client/page/terminology-page.js.map +1 -0
  16. package/dist-client/route.d.ts +1 -0
  17. package/dist-client/route.js +8 -0
  18. package/dist-client/route.js.map +1 -0
  19. package/dist-client/tsconfig.tsbuildinfo +1 -0
  20. package/dist-server/controllers/clear-cache-for-translation.js +18 -0
  21. package/dist-server/controllers/clear-cache-for-translation.js.map +1 -0
  22. package/dist-server/index.js +1 -0
  23. package/dist-server/index.js.map +1 -1
  24. package/dist-server/routes.js +66 -1
  25. package/dist-server/routes.js.map +1 -1
  26. package/dist-server/service/index.js +8 -3
  27. package/dist-server/service/index.js.map +1 -1
  28. package/dist-server/service/terminology/index.js +2 -1
  29. package/dist-server/service/terminology/index.js.map +1 -1
  30. package/dist-server/service/terminology/terminology-mutation.js +39 -2
  31. package/dist-server/service/terminology/terminology-mutation.js.map +1 -1
  32. package/dist-server/service/terminology/terminology-query.js +21 -0
  33. package/dist-server/service/terminology/terminology-query.js.map +1 -1
  34. package/dist-server/service/terminology/terminology-type.js +3 -3
  35. package/dist-server/service/terminology/terminology-type.js.map +1 -1
  36. package/dist-server/service/terminology/terminology.js +21 -4
  37. package/dist-server/service/terminology/terminology.js.map +1 -1
  38. package/dist-server/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +12 -8
  40. package/server/controllers/clear-cache-for-translation.ts +18 -0
  41. package/server/index.ts +1 -0
  42. package/server/routes.ts +85 -1
  43. package/server/service/index.ts +15 -6
  44. package/server/service/terminology/index.ts +1 -0
  45. package/server/service/terminology/terminology-mutation.ts +46 -2
  46. package/server/service/terminology/terminology-query.ts +11 -0
  47. package/server/service/terminology/terminology-type.ts +6 -6
  48. package/server/service/terminology/terminology.ts +31 -9
  49. package/things-factory.config.js +10 -2
  50. package/translations/en.json +8 -0
  51. package/translations/ja.json +8 -0
  52. package/translations/ko.json +8 -0
  53. package/translations/ms.json +8 -0
  54. package/translations/zh.json +8 -0
  55. package/client/bootstrap.js +0 -10
  56. package/client/components/i18n-msg.js +0 -9
@@ -0,0 +1,16 @@
1
+ import { PageView } from '@operato/shell'
2
+
3
+ declare module '@operato/shell' {
4
+ interface PageView {
5
+ languageUpdated(i18next: any): void
6
+ }
7
+ }
8
+
9
+ export default function bootstrap() {
10
+ /*
11
+ * PageView의 lifecycle에 languageUpdate를 추가한다.
12
+ */
13
+ PageView.prototype.languageUpdated = function (i18next) {
14
+ this.pageReset()
15
+ }
16
+ }
@@ -2,7 +2,5 @@
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
4
 
5
- import './components/i18n-msg'
6
-
7
5
  export { i18next } from '@operato/i18n/config.js'
8
6
  export * from '@operato/i18n/localize.js'
@@ -0,0 +1,406 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import '@operato/data-grist'
4
+ import '@operato/context/ox-context-page-toolbar.js'
5
+ import '@operato/input/ox-input-select-buttons.js'
6
+
7
+ import { css, html } from 'lit'
8
+ import { customElement, query, state } from 'lit/decorators.js'
9
+ import { connect } from 'pwa-helpers/connect-mixin.js'
10
+ import gql from 'graphql-tag'
11
+
12
+ import { store, CustomAlert, PageView } from '@operato/shell'
13
+ import { client } from '@operato/graphql'
14
+ import { DataGrist, FetchOption, GristRecord } from '@operato/data-grist'
15
+ import { i18next, localize } from '@operato/i18n'
16
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
17
+ import { isMobileDevice } from '@operato/utils'
18
+ import { getLanguages } from '@things-factory/auth-base/dist-client'
19
+
20
+ @customElement('terminology-page')
21
+ export class TerminologyPage extends connect(store)(localize(i18next)(PageView)) {
22
+ static styles = [
23
+ ScrollbarStyles,
24
+ CommonHeaderStyles,
25
+ css`
26
+ :host {
27
+ display: flex;
28
+ flex-direction: column;
29
+
30
+ overflow: hidden;
31
+
32
+ --grid-header-padding: 2px 0 2px 9px;
33
+ }
34
+
35
+ ox-grist {
36
+ overflow-y: auto;
37
+ flex: 1;
38
+ }
39
+ `
40
+ ]
41
+
42
+ @state() private gristConfig: any
43
+ @state() private mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
44
+ @state() private state?: string[]
45
+
46
+ @query('ox-grist') private grist!: DataGrist
47
+
48
+ get context() {
49
+ return {
50
+ title: i18next.t('title.terminology'),
51
+ search: {
52
+ handler: (search: string) => {
53
+ this.grist.searchText = search
54
+ },
55
+ value: this.grist?.searchText || ''
56
+ },
57
+ filter: {
58
+ handler: () => {
59
+ this.grist.toggleHeadroom()
60
+ }
61
+ },
62
+ help: 'mfg-warehouse/term-page',
63
+ actions: [
64
+ {
65
+ title: i18next.t('button.clear-cache'),
66
+ action: this.clearCache.bind(this),
67
+ icon: 'ink_eraser'
68
+ },
69
+ {
70
+ title: i18next.t('button.save'),
71
+ action: this.save.bind(this),
72
+ icon: 'save'
73
+ },
74
+ {
75
+ title: i18next.t('button.delete'),
76
+ action: this.delete.bind(this),
77
+ icon: 'delete',
78
+ emphasis: {
79
+ danger: true
80
+ }
81
+ }
82
+ ],
83
+ exportable: {
84
+ name: i18next.t('button.export'),
85
+ data: this.exportHandler.bind(this)
86
+ },
87
+ toolbar: false
88
+ }
89
+ }
90
+
91
+ async getFilterStatus() {
92
+ return (await getLanguages()).map(({ code, display }) => {
93
+ return { value: code, display }
94
+ })
95
+ }
96
+
97
+ render() {
98
+ const mode = this.mode || (isMobileDevice() ? 'LIST' : 'GRID')
99
+
100
+ return html`
101
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
102
+ <div slot="headroom" class="header">
103
+ <div class="title">${i18next.t('title.terminology')}</div>
104
+
105
+ <div class="filters">
106
+ <ox-filters-form autofocus without-search></ox-filters-form>
107
+ </div>
108
+
109
+ <ox-context-page-toolbar class="actions" .context=${this.context}></ox-context-page-toolbar>
110
+ </div>
111
+ </ox-grist>
112
+ `
113
+ }
114
+
115
+ async pageInitialized(lifecycle) {
116
+ this.gristConfig = {
117
+ list: {
118
+ fields: ['name', 'description'],
119
+ details: ['active', 'updatedAt']
120
+ },
121
+ columns: [
122
+ { type: 'gutter', gutterName: 'sequence' },
123
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
124
+ {
125
+ type: 'string',
126
+ name: 'id',
127
+ header: i18next.t('field.id'),
128
+ hidden: true,
129
+ width: 0
130
+ },
131
+ {
132
+ type: 'string',
133
+ name: 'name',
134
+ header: i18next.t('field.name'),
135
+ record: {
136
+ editable: true
137
+ },
138
+ filter: 'search',
139
+ sortable: true,
140
+ width: 250
141
+ },
142
+ {
143
+ type: 'select',
144
+ name: 'locale',
145
+ header: i18next.t('field.locale'),
146
+ record: {
147
+ editable: true,
148
+ options: [{ display: '', value: '' }, ...(await this.getFilterStatus())]
149
+ },
150
+ width: 90,
151
+ filter: {
152
+ type: 'select-buttons',
153
+ operator: 'in'
154
+ }
155
+ },
156
+ {
157
+ type: 'select',
158
+ name: 'category',
159
+ label: true,
160
+ header: i18next.t('field.category'),
161
+ record: {
162
+ editable: true,
163
+ options: ['', 'button', 'field', 'label', 'menu', 'text', 'title']
164
+ },
165
+ width: 90,
166
+ filter: 'in',
167
+ imex: true
168
+ },
169
+ {
170
+ type: 'string',
171
+ name: 'display',
172
+ label: true,
173
+ header: i18next.t('field.display'),
174
+ record: {
175
+ editable: true
176
+ },
177
+ filter: 'search',
178
+ sortable: true,
179
+ width: 380
180
+ },
181
+ {
182
+ type: 'resource-object',
183
+ name: 'updater',
184
+ header: i18next.t('field.updater'),
185
+ record: {
186
+ editable: false
187
+ },
188
+ sortable: true,
189
+ width: 120
190
+ },
191
+ {
192
+ type: 'datetime',
193
+ name: 'updatedAt',
194
+ header: i18next.t('field.updated_at'),
195
+ record: {
196
+ editable: false
197
+ },
198
+ sortable: true,
199
+ width: 180
200
+ }
201
+ ],
202
+ rows: {
203
+ appendable: true,
204
+ selectable: {
205
+ multiple: true
206
+ }
207
+ /*handlers: {
208
+ click: (columns, data, column, record, rowIndex) => {
209
+ // TODO Implement the desired sub-view(like item-view) and use it in the popup content after importing
210
+ const popup = openPopup(html`
211
+ <item-view item-id=${record.id} style="background-color: white;">
212
+ </item-view>
213
+ `, {
214
+ backdrop: true,
215
+ size: 'large',
216
+ title: i18next.t('text.item view')
217
+ })
218
+ popup.onclosed = () => {
219
+ this.grist.fetch()
220
+ }
221
+ }
222
+ }*/
223
+ },
224
+ sorters: [
225
+ {
226
+ name: 'name',
227
+ desc: true
228
+ }
229
+ ]
230
+ }
231
+ }
232
+
233
+ async pageUpdated(changes: any, lifecycle: any) {
234
+ if (this.active) {
235
+ // do something here when this page just became as active
236
+ }
237
+ }
238
+
239
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
240
+ const response = await client.query({
241
+ query: gql`
242
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
243
+ terminologies(filters: $filters, pagination: $pagination, sortings: $sortings) {
244
+ items {
245
+ id
246
+ name
247
+ locale
248
+ category
249
+ display
250
+ creator {
251
+ id
252
+ name
253
+ }
254
+ createdAt
255
+ updater {
256
+ id
257
+ name
258
+ }
259
+ updatedAt
260
+ }
261
+
262
+ total
263
+ }
264
+ }
265
+ `,
266
+ variables: {
267
+ filters,
268
+ pagination: { page, limit },
269
+ sortings
270
+ }
271
+ })
272
+
273
+ return {
274
+ total: response.data.terminologies.total || 0,
275
+ records: response.data.terminologies.items || []
276
+ }
277
+ }
278
+
279
+ exportHandler() {
280
+ let records = [] as GristRecord
281
+ if (this.grist.selected && this.grist.selected.length > 0) {
282
+ records = this.grist.selected
283
+ } else {
284
+ records = this.grist.data.records
285
+ }
286
+
287
+ var headerSetting = this.grist.compiledConfig.columns
288
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
289
+ .map(column => {
290
+ return column.imex === true
291
+ ? {
292
+ header: column.header.renderer(column),
293
+ key: column.name,
294
+ width: column.width,
295
+ type: column.type
296
+ }
297
+ : column.imex
298
+ })
299
+
300
+ var data = records.map(item => {
301
+ return {
302
+ id: item.id,
303
+ ...this.gristConfig.columns
304
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
305
+ .reduce((record, column) => {
306
+ const key = column.imex === true ? column.name : column.imex.key
307
+ record[key] = key
308
+ .split('.')
309
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
310
+ return record
311
+ }, {})
312
+ }
313
+ })
314
+
315
+ return { header: headerSetting, data: data }
316
+ }
317
+
318
+ async delete() {
319
+ const selectedRecords = this.grist.selected
320
+
321
+ if (!selectedRecords || selectedRecords.length == 0) {
322
+ this.showToast(i18next.t('text.NOTHING_SELECTED'))
323
+ } else {
324
+ const answer = await CustomAlert({
325
+ type: 'question',
326
+ title: i18next.t('button.delete'),
327
+ text: i18next.t('text.are_you_sure'),
328
+ confirmButton: { text: i18next.t('button.delete') },
329
+ cancelButton: { text: i18next.t('button.cancel') }
330
+ })
331
+
332
+ if (!answer) {
333
+ return
334
+ }
335
+
336
+ let ids = selectedRecords.map(record => record.id)
337
+
338
+ const response = await client.mutate({
339
+ mutation: gql`
340
+ mutation ($ids: [String!]!) {
341
+ deleteTerminologies(ids: $ids)
342
+ }
343
+ `,
344
+ variables: {
345
+ ids
346
+ }
347
+ })
348
+
349
+ this.grist.fetch()
350
+
351
+ return response.data.deleteTerminologies
352
+ }
353
+ }
354
+
355
+ async clearCache() {
356
+ const response = await client.mutate({
357
+ mutation: gql`
358
+ mutation {
359
+ clearTranslationsCache
360
+ }
361
+ `
362
+ })
363
+
364
+ if (!response.errors) {
365
+ this.showToast(i18next.t('text.info_x_successfully', { x: i18next.t('text.clearing-cache') }))
366
+ }
367
+ }
368
+
369
+ async save() {
370
+ let changedRecords = this.grist.dirtyRecords
371
+
372
+ if (!changedRecords || changedRecords.length == 0) {
373
+ this.showToast(i18next.t('text.nothing_changed'))
374
+ } else {
375
+ const patches = changedRecords.map(patch => {
376
+ const patchField: any = patch.id ? { id: patch.id } : {}
377
+ const dirtyFields = patch.__dirtyfields__
378
+ for (let key in dirtyFields) {
379
+ patchField[key] = dirtyFields[key].after
380
+ }
381
+ patchField.cuFlag = patch.__dirty__
382
+
383
+ return patchField
384
+ })
385
+
386
+ const response = await client.mutate({
387
+ mutation: gql`
388
+ mutation ($patches: [TerminologyPatch!]!) {
389
+ updateMultipleTerminologies(patches: $patches) {
390
+ id
391
+ }
392
+ }
393
+ `,
394
+ variables: {
395
+ patches
396
+ }
397
+ })
398
+
399
+ this.grist.fetch()
400
+ }
401
+ }
402
+
403
+ showToast(message: string) {
404
+ document.dispatchEvent(new CustomEvent('notify', { detail: { message } }))
405
+ }
406
+ }
@@ -0,0 +1,7 @@
1
+ export default function route(page) {
2
+ switch (page) {
3
+ case 'terminology-page':
4
+ import('./page/terminology-page.js')
5
+ return page
6
+ }
7
+ }
@@ -0,0 +1,29 @@
1
+ module.exports = {
2
+ i18n: {
3
+ languages: [
4
+ {
5
+ code: 'en-US',
6
+ display: 'English'
7
+ },
8
+ {
9
+ code: 'ko-KR',
10
+ display: '한국어'
11
+ },
12
+ {
13
+ code: 'zh-CN',
14
+ display: '中文'
15
+ },
16
+ {
17
+ code: 'ja-JP',
18
+ display: 'にほんご'
19
+ },
20
+ {
21
+ code: 'ms-MY',
22
+ display: 'Bahasa Malaysia'
23
+ }
24
+ ],
25
+ defaultLanguage: 'en-US',
26
+ disableUserFavoredLanguage: false,
27
+ disableCustomTerminologyFeature: false
28
+ }
29
+ }
@@ -0,0 +1,29 @@
1
+ module.exports = {
2
+ i18n: {
3
+ languages: [
4
+ {
5
+ code: 'en-US',
6
+ display: 'English'
7
+ },
8
+ {
9
+ code: 'ko-KR',
10
+ display: '한국어'
11
+ },
12
+ {
13
+ code: 'zh-CN',
14
+ display: '中文'
15
+ },
16
+ {
17
+ code: 'ja-JP',
18
+ display: 'にほんご'
19
+ },
20
+ {
21
+ code: 'ms-MY',
22
+ display: 'Bahasa Malaysia'
23
+ }
24
+ ],
25
+ defaultLanguage: 'en-US',
26
+ disableUserFavoredLanguage: false,
27
+ disableCustomTerminologyFeature: false
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ declare module '@operato/shell' {
2
+ interface PageView {
3
+ languageUpdated(i18next: any): void;
4
+ }
5
+ }
6
+ export default function bootstrap(): void;
@@ -0,0 +1,10 @@
1
+ import { PageView } from '@operato/shell';
2
+ export default function bootstrap() {
3
+ /*
4
+ * PageView의 lifecycle에 languageUpdate를 추가한다.
5
+ */
6
+ PageView.prototype.languageUpdated = function (i18next) {
7
+ this.pageReset();
8
+ };
9
+ }
10
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAQzC,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B;;OAEG;IACH,QAAQ,CAAC,SAAS,CAAC,eAAe,GAAG,UAAU,OAAO;QACpD,IAAI,CAAC,SAAS,EAAE,CAAA;IAClB,CAAC,CAAA;AACH,CAAC","sourcesContent":["import { PageView } from '@operato/shell'\n\ndeclare module '@operato/shell' {\n interface PageView {\n languageUpdated(i18next: any): void\n }\n}\n\nexport default function bootstrap() {\n /*\n * PageView의 lifecycle에 languageUpdate를 추가한다.\n */\n PageView.prototype.languageUpdated = function (i18next) {\n this.pageReset()\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ export { i18next } from '@operato/i18n/config.js';
5
+ export * from '@operato/i18n/localize.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ export { i18next } from '@operato/i18n/config.js';
5
+ export * from '@operato/i18n/localize.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,cAAc,2BAA2B,CAAA","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nexport { i18next } from '@operato/i18n/config.js'\nexport * from '@operato/i18n/localize.js'\n"]}
@@ -0,0 +1,79 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '@operato/data-grist';
3
+ import '@operato/context/ox-context-page-toolbar.js';
4
+ import '@operato/input/ox-input-select-buttons.js';
5
+ import { PageView } from '@operato/shell';
6
+ import { FetchOption } from '@operato/data-grist';
7
+ declare const TerminologyPage_base: (new (...args: any[]) => {
8
+ _storeUnsubscribe: import("redux").Unsubscribe;
9
+ connectedCallback(): void;
10
+ disconnectedCallback(): void;
11
+ stateChanged(_state: unknown): void;
12
+ readonly isConnected: boolean;
13
+ }) & (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
14
+ export declare class TerminologyPage extends TerminologyPage_base {
15
+ static styles: import("lit").CSSResult[];
16
+ private gristConfig;
17
+ private mode;
18
+ private state?;
19
+ private grist;
20
+ get context(): {
21
+ title: string;
22
+ search: {
23
+ handler: (search: string) => void;
24
+ value: string;
25
+ };
26
+ filter: {
27
+ handler: () => void;
28
+ };
29
+ help: string;
30
+ actions: ({
31
+ title: string;
32
+ action: () => Promise<void>;
33
+ icon: string;
34
+ emphasis?: undefined;
35
+ } | {
36
+ title: string;
37
+ action: () => Promise<any>;
38
+ icon: string;
39
+ emphasis: {
40
+ danger: boolean;
41
+ };
42
+ })[];
43
+ exportable: {
44
+ name: string;
45
+ data: () => {
46
+ header: (false | {
47
+ header: any;
48
+ key: string;
49
+ width: string | number | import("@operato/data-grist").ColumnWidthCallback | undefined;
50
+ type: string;
51
+ } | undefined)[];
52
+ data: any;
53
+ };
54
+ };
55
+ toolbar: boolean;
56
+ };
57
+ getFilterStatus(): Promise<any>;
58
+ render(): import("lit").TemplateResult<1>;
59
+ pageInitialized(lifecycle: any): Promise<void>;
60
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
61
+ fetchHandler({ page, limit, sortings, filters }: FetchOption): Promise<{
62
+ total: any;
63
+ records: any;
64
+ }>;
65
+ exportHandler(): {
66
+ header: (false | {
67
+ header: any;
68
+ key: string;
69
+ width: string | number | import("@operato/data-grist").ColumnWidthCallback | undefined;
70
+ type: string;
71
+ } | undefined)[];
72
+ data: any;
73
+ };
74
+ delete(): Promise<any>;
75
+ clearCache(): Promise<void>;
76
+ save(): Promise<void>;
77
+ showToast(message: string): void;
78
+ }
79
+ export {};