@things-factory/organization 6.2.73 → 6.2.79

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 (30) hide show
  1. package/client/pages/approval-line/common-approval-line-templates-page.ts +2 -2
  2. package/client/pages/approval-line/my-approval-line-templates-page.ts +2 -2
  3. package/client/pages/department/department-tree-page.ts +568 -0
  4. package/client/pages/employee/employee-list-page.ts +7 -2
  5. package/client/route.ts +4 -0
  6. package/dist-client/pages/approval-line/common-approval-line-templates-page.js +2 -2
  7. package/dist-client/pages/approval-line/common-approval-line-templates-page.js.map +1 -1
  8. package/dist-client/pages/approval-line/my-approval-line-templates-page.js +2 -2
  9. package/dist-client/pages/approval-line/my-approval-line-templates-page.js.map +1 -1
  10. package/dist-client/pages/department/department-tree-page.d.ts +53 -0
  11. package/dist-client/pages/department/department-tree-page.js +534 -0
  12. package/dist-client/pages/department/department-tree-page.js.map +1 -0
  13. package/dist-client/pages/employee/employee-list-page.js +7 -2
  14. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  15. package/dist-client/route.d.ts +1 -1
  16. package/dist-client/route.js +3 -0
  17. package/dist-client/route.js.map +1 -1
  18. package/dist-client/tsconfig.tsbuildinfo +1 -1
  19. package/dist-server/service/department/department-query.js +16 -6
  20. package/dist-server/service/department/department-query.js.map +1 -1
  21. package/dist-server/service/employee/employee-type.js +11 -2
  22. package/dist-server/service/employee/employee-type.js.map +1 -1
  23. package/dist-server/service/employee/employee.js +2 -1
  24. package/dist-server/service/employee/employee.js.map +1 -1
  25. package/dist-server/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +5 -5
  27. package/server/service/department/department-query.ts +19 -7
  28. package/server/service/employee/employee-type.ts +9 -2
  29. package/server/service/employee/employee.ts +2 -1
  30. package/things-factory.config.js +1 -0
@@ -28,8 +28,8 @@ export class CommonApprovalLineTemplatesPage extends connect(store)(localize(i18
28
28
 
29
29
  width: 100%;
30
30
 
31
- --grid-record-emphasized-background-color: red;
32
- --grid-record-emphasized-color: yellow;
31
+ --grid-record-emphasized-background-color: #8b0000;
32
+ --grid-record-emphasized-color: #ff6b6b;
33
33
  }
34
34
 
35
35
  ox-grist {
@@ -28,8 +28,8 @@ export class MyApprovalLineTemplatesPage extends connect(store)(localize(i18next
28
28
 
29
29
  width: 100%;
30
30
 
31
- --grid-record-emphasized-background-color: red;
32
- --grid-record-emphasized-color: yellow;
31
+ --grid-record-emphasized-background-color: #8b0000;
32
+ --grid-record-emphasized-color: #ff6b6b;
33
33
  }
34
34
 
35
35
  ox-grist {
@@ -0,0 +1,568 @@
1
+ import '@operato/data-tree'
2
+ import '@operato/context/ox-context-page-toolbar.js'
3
+
4
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
5
+ import { PageView, store } from '@operato/shell'
6
+ import { css, html } from 'lit'
7
+ import { customElement, property, query, state } from 'lit/decorators.js'
8
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements'
9
+ import { client } from '@operato/graphql'
10
+ import { i18next, localize } from '@operato/i18n'
11
+ import { isMobileDevice } from '@operato/utils'
12
+ import { DataGrist, FetchOption, GristRecord } from '@operato/data-grist'
13
+
14
+ import { connect } from 'pwa-helpers/connect-mixin'
15
+ import gql from 'graphql-tag'
16
+
17
+ import { DepartmentImporter } from './department-importer'
18
+ import { Department } from '../../types/department'
19
+
20
+ import { DepartmentView } from '../../component/department-view'
21
+
22
+ const departmentFragment = gql`
23
+ fragment Department_department on Department {
24
+ id
25
+ controlNo
26
+ name
27
+ description
28
+
29
+ manager {
30
+ id
31
+ name
32
+ controlNo
33
+ photo
34
+ email
35
+ }
36
+ active
37
+ state
38
+ picture
39
+
40
+ updater {
41
+ id
42
+ name
43
+ }
44
+ updatedAt
45
+ }
46
+ `
47
+
48
+ @customElement('department-tree-page')
49
+ export class DepartmentTreePage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
50
+ static styles = [
51
+ ScrollbarStyles,
52
+ CommonHeaderStyles,
53
+ css`
54
+ :host {
55
+ display: flex;
56
+
57
+ width: 100%;
58
+
59
+ --grid-record-emphasized-background-color: #8b0000;
60
+ --grid-record-emphasized-color: #ff6b6b;
61
+ }
62
+
63
+ ox-grist {
64
+ overflow-y: auto;
65
+ flex: 1;
66
+ }
67
+ `
68
+ ]
69
+
70
+ static get scopedElements() {
71
+ return {
72
+ 'department-importer': DepartmentImporter
73
+ }
74
+ }
75
+
76
+ @state() root?: Department
77
+ @state() selected?: Department
78
+
79
+ @query('ox-grist') private grist!: DataGrist
80
+
81
+ get context() {
82
+ return {
83
+ title: i18next.t('title.department list'),
84
+ help: 'organization/department',
85
+ actions: [
86
+ {
87
+ icon: 'add',
88
+ title: i18next.t('button.add'),
89
+ action: this.create.bind(this)
90
+ },
91
+ {
92
+ icon: 'save',
93
+ title: i18next.t('button.save'),
94
+ action: this.save.bind(this)
95
+ },
96
+ {
97
+ icon: 'delete',
98
+ title: i18next.t('button.delete'),
99
+ action: this.delete.bind(this)
100
+ }
101
+ ].filter(Boolean),
102
+ exportable: {
103
+ name: i18next.t('title.department list'),
104
+ data: this.exportHandler.bind(this)
105
+ },
106
+ importable: {
107
+ handler: this.importHandler.bind(this)
108
+ },
109
+ toolbar: false
110
+ }
111
+ }
112
+
113
+ @property({ type: Object }) gristConfig: any
114
+
115
+ render() {
116
+ const mode = isMobileDevice() ? 'CARD' : 'GRID'
117
+
118
+ return html`
119
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
120
+ <div slot="headroom" class="header">
121
+ <div class="title">
122
+ <mwc-icon>summarize</mwc-icon>
123
+ ${i18next.t('title.employee list')}
124
+ </div>
125
+
126
+ <div class="filters">
127
+ <ox-filters-form class="filter" autofocus without-search></ox-filters-form>
128
+ </div>
129
+
130
+ <ox-context-page-toolbar class="actions" .context=${this.context}></ox-context-page-toolbar>
131
+ </div>
132
+ </ox-grist>
133
+ `
134
+ }
135
+
136
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
137
+ const response = await client.query({
138
+ query: gql`
139
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
140
+ responses: departmentRoot {
141
+ ...Department_department
142
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
143
+ ...Department_department
144
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
145
+ ...Department_department
146
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
147
+ ...Department_department
148
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
149
+ ...Department_department
150
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
151
+ ...Department_department
152
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
153
+ ...Department_department
154
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
155
+ ...Department_department
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ ${departmentFragment}
167
+ `,
168
+ variables: {
169
+ filters,
170
+ pagination: { page, limit },
171
+ sortings
172
+ }
173
+ })
174
+
175
+ const root = response.data.responses
176
+
177
+ return {
178
+ total: 1, //response.data.responses.total || 0,
179
+ records: [root]
180
+ }
181
+ }
182
+
183
+ async delete() {
184
+ if (!this.selected) {
185
+ alert('select department first.')
186
+ }
187
+
188
+ const children = this.selected?.children
189
+ if (children && children.length > 0) {
190
+ alert('Department having children cannot be deleted.')
191
+ }
192
+
193
+ if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
194
+ const { id } = this.selected || {}
195
+
196
+ const response = await client.mutate({
197
+ mutation: gql`
198
+ mutation ($id: String!) {
199
+ deleteDepartment(id: $id)
200
+ }
201
+ `,
202
+ variables: {
203
+ id
204
+ }
205
+ })
206
+
207
+ this.selected = {}
208
+ this.updateContext()
209
+
210
+ await this.grist.fetch()
211
+ }
212
+ }
213
+
214
+ async pageInitialized(lifecycle: any) {
215
+ this.gristConfig = {
216
+ pagination: { pages: [50, 100, 200] },
217
+ list: {
218
+ thumbnail: 'profile',
219
+ fields: ['controlNo', 'name'],
220
+ details: ['email', 'manager', 'updatedAt']
221
+ },
222
+ columns: [
223
+ {
224
+ type: 'gutter',
225
+ gutterName: 'dirty',
226
+ fixed: true
227
+ },
228
+ {
229
+ type: 'tree',
230
+ name: 'name',
231
+ label: true,
232
+ header: i18next.t('label.name'),
233
+ record: {
234
+ editable: false,
235
+ options: {
236
+ childrenProperty: 'children',
237
+ selectable: true
238
+ }
239
+ },
240
+ filter: 'search',
241
+ sortable: true,
242
+ width: 200,
243
+ fixed: true
244
+ },
245
+ { name: 'id', hidden: true },
246
+ {
247
+ type: 'string',
248
+ name: 'controlNo',
249
+ header: i18next.t('label.control-no'),
250
+ record: {
251
+ editable: true
252
+ },
253
+ filter: 'search',
254
+ sortable: true,
255
+ width: 110
256
+ },
257
+ {
258
+ type: 'string',
259
+ name: 'description',
260
+ header: i18next.t('label.description'),
261
+ record: {
262
+ editable: true
263
+ },
264
+ filter: 'search',
265
+ sortable: true,
266
+ width: 110
267
+ },
268
+ {
269
+ type: 'string',
270
+ name: 'state',
271
+ header: i18next.t('label.state'),
272
+ record: {
273
+ editable: true
274
+ },
275
+ sortable: true,
276
+ width: 110
277
+ },
278
+ {
279
+ type: 'resource-object',
280
+ name: 'manager',
281
+ header: i18next.t('label.manager'),
282
+ record: {
283
+ editable: true,
284
+ options: {
285
+ title: i18next.t('title.employee list'),
286
+ queryName: 'employees',
287
+ pagination: { pages: [50, 100, 200] },
288
+ basicArgs: {
289
+ filters: [
290
+ {
291
+ name: 'active',
292
+ operator: 'eq',
293
+ value: true
294
+ }
295
+ ]
296
+ },
297
+ list: { fields: ['controlNo', 'name', 'email'] },
298
+ columns: [
299
+ { name: 'id', hidden: true },
300
+ {
301
+ name: 'controlNo',
302
+ width: 120,
303
+ header: { renderer: () => i18next.t('field.control-no') },
304
+ filter: 'search',
305
+ sortable: true
306
+ },
307
+ {
308
+ name: 'name',
309
+ width: 120,
310
+ header: { renderer: () => i18next.t('field.name') },
311
+ filter: 'search',
312
+ sortable: true
313
+ },
314
+ {
315
+ name: 'email',
316
+ width: 150,
317
+ header: { renderer: () => i18next.t('label.email') },
318
+ filter: 'search',
319
+ sortable: true
320
+ }
321
+ ],
322
+ valueField: 'id',
323
+ nameField: 'name',
324
+ descriptionField: 'controlNo'
325
+ }
326
+ },
327
+ sortable: true,
328
+ width: 120
329
+ },
330
+ {
331
+ type: 'checkbox',
332
+ name: 'active',
333
+ label: true,
334
+ header: i18next.t('field.active'),
335
+ width: 70,
336
+ record: {
337
+ align: 'center',
338
+ editable: true
339
+ },
340
+ filter: true,
341
+ sortable: true
342
+ },
343
+ {
344
+ type: 'resource-object',
345
+ name: 'updater',
346
+ header: i18next.t('field.updater'),
347
+ width: 90,
348
+ sortable: false
349
+ },
350
+ {
351
+ type: 'datetime',
352
+ name: 'updatedAt',
353
+ header: i18next.t('field.updated_at'),
354
+ width: 180,
355
+ sortable: true
356
+ },
357
+ {
358
+ type: 'image',
359
+ name: 'picture',
360
+ record: {
361
+ renderer: function (value, column, record, rowIndex, field) {
362
+ return html`<ox-pfp-view
363
+ style="height:90%; width: unset; aspect-ratio: 1 / 1;"
364
+ .profile=${record.picture}
365
+ .name=${record.name}
366
+ ></ox-pfp-view>`
367
+ }
368
+ },
369
+ hidden: true
370
+ }
371
+ ],
372
+ rows: {
373
+ appendable: false,
374
+ selectable: {
375
+ multiple: true
376
+ }
377
+ },
378
+ sorters: [
379
+ {
380
+ name: 'controlNo'
381
+ }
382
+ ]
383
+ }
384
+ }
385
+
386
+ async pageUpdated(changes: any, lifecycle: any) {
387
+ if (this.active) {
388
+ // do something here when this page just became as active
389
+ }
390
+ }
391
+
392
+ async create() {
393
+ // const { id: parentId } = this.selected || {}
394
+ // const { controlNo, name, description, state, picture, active, manager } = this.grist.department
395
+
396
+ // var department = {
397
+ // controlNo,
398
+ // name,
399
+ // description,
400
+ // state,
401
+ // manager,
402
+ // active
403
+ // } as any
404
+
405
+ // if (picture instanceof File) {
406
+ // department.picture = picture
407
+ // }
408
+
409
+ // if (parentId) {
410
+ // department.parent = { id: parentId }
411
+ // }
412
+
413
+ // const response = await client.mutate({
414
+ // mutation: gql`
415
+ // mutation ($department: NewDepartment!) {
416
+ // createDepartment(department: $department) {
417
+ // ...Department_department
418
+ // }
419
+ // }
420
+
421
+ // ${departmentFragment}
422
+ // `,
423
+ // variables: {
424
+ // department
425
+ // },
426
+ // context: {
427
+ // hasUpload: true
428
+ // }
429
+ // })
430
+
431
+ // this.selected = response.data.createDepartment
432
+ // this.updateContext()
433
+
434
+ await this.grist.fetch()
435
+ }
436
+
437
+ // async _deleteDataSet() {
438
+ // if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
439
+ // const ids = this.grist.selected.map(record => record.id)
440
+ // if (ids && ids.length > 0) {
441
+ // const response = await client.mutate({
442
+ // mutation: gql`
443
+ // mutation ($ids: [String!]!) {
444
+ // deleteDataSets(ids: $ids)
445
+ // }
446
+ // `,
447
+ // variables: {
448
+ // ids
449
+ // }
450
+ // })
451
+
452
+ // if (!response.errors) {
453
+ // this.grist.fetch()
454
+ // notify({
455
+ // message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
456
+ // })
457
+ // }
458
+ // }
459
+ // }
460
+ // }
461
+
462
+ // async _copyDataSet() {
463
+ // var selected = this.grist.selected
464
+ // if (selected.length == 0) return
465
+
466
+ // if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.copy') }))) return
467
+ // var response = await client.mutate({
468
+ // mutation: gql`
469
+ // mutation ($ids: [String!]!) {
470
+ // copyDataSets(ids: $ids) {
471
+ // id
472
+ // }
473
+ // }
474
+ // `,
475
+ // variables: {
476
+ // ids: selected.map(r => r.id)
477
+ // }
478
+ // })
479
+
480
+ // if (!response.errors) {
481
+ // this.grist.fetch()
482
+ // }
483
+ // }
484
+
485
+ // async save() {
486
+ // const { id, controlNo, name, description, state, picture, active, manager } = this.departmentView.department
487
+
488
+ // if (!id) {
489
+ // alert('Please select department first.')
490
+ // }
491
+
492
+ // var patch = {
493
+ // controlNo,
494
+ // name,
495
+ // description,
496
+ // state,
497
+ // active,
498
+ // manager
499
+ // } as any
500
+
501
+ // if (picture instanceof File) {
502
+ // patch.picture = picture
503
+ // }
504
+
505
+ // const response = await client.mutate({
506
+ // mutation: gql`
507
+ // mutation ($id: String!, $patch: DepartmentPatch!) {
508
+ // updateDepartment(id: $id, patch: $patch) {
509
+ // ...Department_department
510
+ // }
511
+ // }
512
+
513
+ // ${departmentFragment}
514
+ // `,
515
+ // variables: {
516
+ // id,
517
+ // patch
518
+ // },
519
+ // context: {
520
+ // hasUpload: true
521
+ // }
522
+ // })
523
+
524
+ // this.selected = response.data.updateDepartment
525
+
526
+ // this.fetch()
527
+ // }
528
+
529
+ async save() {
530
+ let patches = this.grist.dirtyRecords
531
+ if (patches && patches.length) {
532
+ patches = patches.map(patch => {
533
+ let patchField: any = patch.id ? { id: patch.id } : {}
534
+ const dirtyFields = patch.__dirtyfields__
535
+ for (let key in dirtyFields) {
536
+ patchField[key] = dirtyFields[key].after
537
+ }
538
+ patchField.cuFlag = patch.__dirty__
539
+
540
+ return patchField
541
+ })
542
+
543
+ const response = await client.mutate({
544
+ mutation: gql`
545
+ mutation ($patches: [DepartmentPatch!]!) {
546
+ updateMultipleDepartment(patches: $patches) {
547
+ name
548
+ }
549
+ }
550
+ `,
551
+ variables: {
552
+ patches
553
+ },
554
+ context: {
555
+ hasUpload: true
556
+ }
557
+ })
558
+
559
+ if (!response.errors) {
560
+ this.grist.fetch()
561
+ }
562
+ }
563
+ }
564
+
565
+ async exportHandler() {}
566
+
567
+ async importHandler(records) {}
568
+ }
@@ -30,8 +30,13 @@ export class EmployeeListPage extends connect(store)(localize(i18next)(ScopedEle
30
30
 
31
31
  width: 100%;
32
32
 
33
- --grid-record-emphasized-background-color: red;
34
- --grid-record-emphasized-color: yellow;
33
+ --grid-record-emphasized-background-color: #8b0000;
34
+ --grid-record-emphasized-color: #ff6b6b;
35
+ }
36
+
37
+ ox-grist {
38
+ overflow-y: auto;
39
+ flex: 1;
35
40
  }
36
41
  `
37
42
  ]
package/client/route.ts CHANGED
@@ -8,6 +8,10 @@ export default function route(page: string) {
8
8
  import('./pages/department/department-list-page')
9
9
  return page
10
10
 
11
+ case 'department-tree':
12
+ import('./pages/department/department-tree-page')
13
+ return page
14
+
11
15
  case 'employees-by-department':
12
16
  import('./pages/employee/employees-by-department')
13
17
  return page
@@ -339,8 +339,8 @@ CommonApprovalLineTemplatesPage.styles = [
339
339
 
340
340
  width: 100%;
341
341
 
342
- --grid-record-emphasized-background-color: red;
343
- --grid-record-emphasized-color: yellow;
342
+ --grid-record-emphasized-background-color: #8b0000;
343
+ --grid-record-emphasized-color: #ff6b6b;
344
344
  }
345
345
 
346
346
  ox-grist {