@things-factory/worklist 6.1.63 → 6.1.64

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/activity-approval/activity-approval-page.ts +2 -1
  2. package/client/pages/activity-instance/activity-instance-view.ts +6 -5
  3. package/client/pages/activity-thread/activity-thread-page.ts +2 -1
  4. package/client/pages/activity-thread/activity-thread-view-page.ts +18 -41
  5. package/client/pages/activity-thread/activity-thread-view.ts +401 -0
  6. package/client/pages/todo/done-list-calendar-page.ts +1 -1
  7. package/client/pages/todo/done-list-page.ts +1 -1
  8. package/dist-client/pages/activity-approval/activity-approval-page.js +2 -1
  9. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  10. package/dist-client/pages/activity-instance/activity-instance-view.js +6 -5
  11. package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
  12. package/dist-client/pages/activity-thread/activity-thread-page.js +2 -1
  13. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  14. package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +5 -5
  15. package/dist-client/pages/activity-thread/activity-thread-view-page.js +17 -38
  16. package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
  17. package/dist-client/pages/activity-thread/activity-thread-view.d.ts +17 -0
  18. package/dist-client/pages/activity-thread/activity-thread-view.js +380 -0
  19. package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -0
  20. package/dist-client/pages/todo/done-list-calendar-page.js +1 -1
  21. package/dist-client/pages/todo/done-list-calendar-page.js.map +1 -1
  22. package/dist-client/pages/todo/done-list-page.js +1 -1
  23. package/dist-client/pages/todo/done-list-page.js.map +1 -1
  24. package/dist-client/route.d.ts +1 -1
  25. package/dist-client/tsconfig.tsbuildinfo +1 -1
  26. package/dist-server/controllers/activity-instance/issue.js +1 -1
  27. package/dist-server/controllers/activity-instance/issue.js.map +1 -1
  28. package/dist-server/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +3 -3
  30. package/server/controllers/activity-instance/issue.ts +1 -1
@@ -197,8 +197,9 @@ export class ActivityApprovalPage extends connect(store)(localize(i18next)(PageV
197
197
  return this.customElementContent()
198
198
  case 'page':
199
199
  case 'external':
200
- default:
201
200
  return html``
201
+ default:
202
+ return this.generatedContent()
202
203
  }
203
204
  }
204
205
 
@@ -192,13 +192,13 @@ export class ActivityInstanceView extends localize(i18next)(LitElement) {
192
192
  border-bottom-color: #f4f4f4;
193
193
  border-top: 0;
194
194
  }
195
- [etc] div {
195
+ [thread] div {
196
196
  border-bottom: var(--border-dark-color);
197
197
  padding: var(--padding-narrow);
198
198
  text-align: right;
199
199
  overflow: hidden;
200
200
  }
201
- [etc] div label {
201
+ [thread] div label {
202
202
  float: left;
203
203
  width: 25%;
204
204
  text-align: left;
@@ -233,7 +233,6 @@ export class ActivityInstanceView extends localize(i18next)(LitElement) {
233
233
  terminatedAt,
234
234
  updatedAt
235
235
  } = this.activityInstance
236
- const instance = this.activityInstance
237
236
 
238
237
  return html`
239
238
  <div instance-container>
@@ -242,7 +241,9 @@ export class ActivityInstanceView extends localize(i18next)(LitElement) {
242
241
  <strong>${name}</strong>
243
242
  ${description}
244
243
  </div>
245
- ${approvalLine ? html`<approval-line-view .model=${approvalLine}></approval-line-view>` : html``}
244
+ <div>
245
+ ${approvalLine ? html`<approval-line-view .model=${approvalLine}></approval-line-view>` : html``}
246
+ </div>
246
247
 
247
248
  <div>
248
249
  <label>${i18next.t('label.status')}</label>
@@ -282,7 +283,7 @@ export class ActivityInstanceView extends localize(i18next)(LitElement) {
282
283
  <strong>${name}</strong>
283
284
  </div>
284
285
 
285
- <div etc>
286
+ <div thread>
286
287
  <span subtitle>${i18next.t('label.information')}</span>
287
288
  <div>
288
289
  <label>${i18next.t('label.status')}</label>
@@ -172,8 +172,9 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
172
172
  return this.customElementContent()
173
173
  case 'page':
174
174
  case 'external':
175
- default:
176
175
  return html``
176
+ default:
177
+ return this.generatedContent()
177
178
  }
178
179
  }
179
180
 
@@ -1,5 +1,6 @@
1
- import '@operato/property-editor/ox-properties-dynamic-view.js'
2
1
  import '@operato/board/ox-board-viewer.js'
2
+ import '../../components/activity-thread-ribon.js'
3
+ import './activity-thread-view.js'
3
4
 
4
5
  import gql from 'graphql-tag'
5
6
  import { css, html } from 'lit'
@@ -32,6 +33,7 @@ const ActivityThreadFetchResult = `\
32
33
  description
33
34
  state
34
35
  activity {
36
+ id
35
37
  model {
36
38
  name
37
39
  description
@@ -85,7 +87,6 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
85
87
  flex-direction: column;
86
88
 
87
89
  width: 100%;
88
- padding: 5px;
89
90
  overflow: auto;
90
91
  }
91
92
 
@@ -94,6 +95,10 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
94
95
  height: 100%;
95
96
  }
96
97
 
98
+ activity-thread-view {
99
+ padding: var(--padding-default);
100
+ }
101
+
97
102
  #custom-content {
98
103
  flex: 1;
99
104
  }
@@ -107,13 +112,18 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
107
112
  return {
108
113
  title: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),
109
114
  help: 'worklist/activity',
110
- actions: [],
111
- activityThread: this.activityThread
115
+ actions: []
116
+ // activityThread: this.activityThread
112
117
  }
113
118
  }
114
119
 
115
120
  render() {
116
- return html` ${this.activityContent()}`
121
+ const activityThread = this.activityThread
122
+
123
+ return html` ${activityThread
124
+ ? html`<activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>`
125
+ : html``}
126
+ ${this.activityContent()}`
117
127
  }
118
128
 
119
129
  activityContent() {
@@ -128,8 +138,9 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
128
138
  return this.customElementContent()
129
139
  case 'page':
130
140
  case 'external':
131
- default:
132
141
  return html``
142
+ default:
143
+ return this.generatedContent()
133
144
  }
134
145
  }
135
146
 
@@ -169,43 +180,9 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
169
180
  }
170
181
 
171
182
  generatedContent() {
172
- var { output, activityInstance } = this.activityThread || {}
173
- var { input } = activityInstance || {}
174
-
175
- const inputSpec = this.getInputSpec()
176
- const outputSpec = this.getOutputSpec()
177
-
178
- if (!output) {
179
- output = inputSpec
180
- .filter(item => item.inout === 'inout')
181
- .reduce((inout, item) => {
182
- inout[item.name] = input[item.name]
183
- return inout
184
- }, {})
185
- }
186
-
187
183
  return keyed(
188
184
  this.activityThread.id,
189
- html`
190
- <fieldset>
191
- <legend>Input</legend>
192
- <ox-properties-dynamic-view
193
- data-name="input"
194
- .props=${inputSpec}
195
- .value=${input}
196
- ></ox-properties-dynamic-view>
197
- </fieldset>
198
-
199
- <fieldset>
200
- <legend>Output</legend>
201
- <ox-properties-dynamic-view
202
- data-name="output"
203
- .props=${outputSpec}
204
- .value=${output}
205
- @property-change=${e => (this.activityThread.output = e.currentTarget.value)}
206
- ></ox-properties-dynamic-view>
207
- </fieldset>
208
- `
185
+ html` <activity-thread-view .activityThreadId=${this.activityThread.id}></activity-thread-view> `
209
186
  )
210
187
  }
211
188
 
@@ -0,0 +1,401 @@
1
+ import '@things-factory/organization/dist-client/component/approval-line-view.js'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement, property, query, state } from 'lit/decorators.js'
6
+
7
+ import { client } from '@operato/graphql'
8
+ import { i18next, localize } from '@operato/i18n'
9
+ import { ScrollbarStyles } from '@operato/styles'
10
+
11
+ import { ActivityThread } from '../../types/activity-thread'
12
+ import { ActivityApproval } from '../../types/activity-approval'
13
+
14
+ const formatter = new Intl.DateTimeFormat(navigator.language, { dateStyle: 'short', timeStyle: 'short' })
15
+
16
+ @customElement('activity-thread-view')
17
+ export class ActivityThreadView extends localize(i18next)(LitElement) {
18
+ static styles = [
19
+ ScrollbarStyles,
20
+ css`
21
+ :host {
22
+ display: flex;
23
+ flex-direction: column;
24
+ overflow: auto;
25
+ font-size: var(--fontsize-default);
26
+ }
27
+
28
+ :host([state='assigned']) {
29
+ --worklist-status-color: #5f7184;
30
+ }
31
+
32
+ :host([state='started']) {
33
+ --worklist-status-color: #56af45;
34
+ }
35
+
36
+ :host([state='delegated']) {
37
+ --worklist-status-color: #8654b0;
38
+ }
39
+
40
+ :host([state='submitted']) {
41
+ --worklist-status-color: #428df3;
42
+ }
43
+
44
+ :host([state='escalated']) {
45
+ --worklist-status-color: #595de5;
46
+ }
47
+
48
+ :host([state='rejected']) {
49
+ --worklist-status-color: #f27429;
50
+ }
51
+
52
+ :host([state='ended']) {
53
+ --worklist-status-color: #02acae;
54
+ }
55
+
56
+ :host([state='aborted']) {
57
+ --worklist-status-color: #cb3a33;
58
+ }
59
+
60
+ [instance-container] {
61
+ flex: 1;
62
+ background-color: var(--main-section-background-color);
63
+ border-right: var(--border-dark-color);
64
+ padding: var(--padding-wide);
65
+ color: var(--primary-text-color);
66
+ }
67
+ [thread-container] {
68
+ flex: 2;
69
+ padding: var(--padding-wide);
70
+ }
71
+ [instance-container] div {
72
+ margin-bottom: var(--margin-default);
73
+ padding-bottom: var(--padding-default);
74
+ border-bottom: var(--border-dark-color);
75
+ }
76
+ [instance-container] div label {
77
+ display: inline-block;
78
+ margin-right: var(--margin-default);
79
+ }
80
+ span[status] {
81
+ width: 15px;
82
+ height: 15px;
83
+ background-color: var(--worklist-status-color, tomato);
84
+ display: inline-block;
85
+ margin-right: var(--margin-narrow);
86
+ border-radius: 50%;
87
+ }
88
+ table {
89
+ width: 100%;
90
+ border-collapse: collapse;
91
+ }
92
+ th {
93
+ background-color: rgba(var(--primary-color-rgb), 0.05);
94
+ border-top: var(--grid-header-top-border);
95
+ border-bottom: var(--grid-header-bottom-border);
96
+ padding: var(--grid-header-padding);
97
+ text-overflow: ellipsis;
98
+ font: var(--grid-header-font);
99
+ color: var(--grid-header-color);
100
+ }
101
+ td {
102
+ padding: var(--padding-narrow);
103
+ border-bottom: var(--grid-record-border-bottom);
104
+ }
105
+ [assignee] * {
106
+ vertical-align: middle;
107
+ }
108
+ [assignee] mwc-icon {
109
+ opacity: 0.5;
110
+ }
111
+ [subtitle] {
112
+ display: block;
113
+ margin: var(--margin-wide) 0 var(--margin-narrow) 0;
114
+ font: bold 16px var(--theme-font);
115
+ color: var(--secondary-text-color);
116
+ }
117
+ [timeline] ol {
118
+ list-style: none;
119
+ margin: 0;
120
+ padding: 0;
121
+ }
122
+ [timeline] li {
123
+ display: flex;
124
+ }
125
+ [timeline] [info] {
126
+ flex: 1;
127
+ }
128
+ [timeline] [date] {
129
+ opacity: 0.7;
130
+ width: 120px;
131
+ font-size: var(--fontsize-small);
132
+ }
133
+ [timeline] [info] strong {
134
+ float: right;
135
+ }
136
+ [timeline] [status] {
137
+ margin: 0 var(--margin-narrow);
138
+ display: block;
139
+ border-radius: 50%;
140
+ width: 12px;
141
+ height: 12px;
142
+ position: relative;
143
+ top: 3px;
144
+ border: 2px solid #fff;
145
+ background-color: var(--worklist-status-color, tomato);
146
+ }
147
+ [timeline] [status]::before {
148
+ content: '';
149
+ height: 60px;
150
+ width: 2px;
151
+ display: block;
152
+ position: relative;
153
+ margin-left: 5px;
154
+ background-color: var(--worklist-status-color, tomato);
155
+ opacity: 0.2;
156
+ }
157
+ [timeline] [info] mwc-icon {
158
+ position: relative;
159
+ top: 3px;
160
+ font-size: var(--fontsize-large);
161
+ }
162
+ [timeline] [info] p {
163
+ background-color: #f4f4f4;
164
+ margin: var(--margin-narrow) 0 var(--margin-default) 0;
165
+ padding: var(--padding-narrow) var(--padding-default);
166
+ border-radius: var(--border-radius);
167
+ font-size: var(--fontsize-small);
168
+ text-align: justify;
169
+ }
170
+ [timeline] [info] p::before {
171
+ content: '';
172
+ float: right;
173
+ margin-top: -10px;
174
+ margin-right: 20px;
175
+ border: 7px solid transparent;
176
+ border-bottom-color: #f4f4f4;
177
+ border-top: 0;
178
+ }
179
+ [thread] div {
180
+ border-bottom: var(--border-dark-color);
181
+ padding: var(--padding-narrow);
182
+ text-align: right;
183
+ overflow: hidden;
184
+ }
185
+ [thread] div label {
186
+ float: left;
187
+ width: 25%;
188
+ text-align: left;
189
+ }
190
+ `
191
+ ]
192
+
193
+ @property({
194
+ type: String,
195
+ attribute: 'activity-thread-id'
196
+ })
197
+ activityThreadId?: string
198
+
199
+ @state() activityThread?: ActivityThread
200
+
201
+ render() {
202
+ if (!this.activityThread) {
203
+ return html`<div>no activity thread info.</div>`
204
+ }
205
+
206
+ const {
207
+ state,
208
+ assignee,
209
+ output,
210
+ round,
211
+ activityApprovals = [],
212
+ assignedAt,
213
+ startedAt,
214
+ terminatedAt,
215
+ activityInstance
216
+ } = this.activityThread
217
+ const { input } = activityInstance!
218
+ const { name, email } = assignee || {}
219
+
220
+ return html`
221
+ <div assignee>
222
+ <mwc-icon>account_circle</mwc-icon>
223
+ <strong>${name}</strong>
224
+ </div>
225
+
226
+ <div thread>
227
+ <span subtitle>${i18next.t('label.information')}</span>
228
+ <div>
229
+ <label>${i18next.t('label.status')}</label>
230
+ <span status></span>
231
+ <strong>${i18next.t('label.activity-state-' + state)}</strong>
232
+ </div>
233
+ <div>
234
+ <label>${i18next.t('field.assigned-at')}</label> ${assignedAt && formatter.format(new Date(assignedAt))}
235
+ </div>
236
+ <div><label>${i18next.t('field.started-at')}</label> ${startedAt && formatter.format(new Date(startedAt))}</div>
237
+ <div>
238
+ <label>${i18next.t('field.terminated-at')}</label> ${terminatedAt && formatter.format(new Date(terminatedAt))}
239
+ </div>
240
+ <div><label>${i18next.t('field.round')}</label> ${round}</div>
241
+ </div>
242
+
243
+ <div>
244
+ <span subtitle>${i18next.t('field.output')}</span>
245
+ ${this.renderInOut({ ...input, ...output })}
246
+ </div>
247
+ <div timeline>
248
+ <span subtitle>승인 검토 이력</span>
249
+ <ol>
250
+ ${activityApprovals
251
+ .sort((a, b) => (a.round < b.round ? 1 : a.round > b.round ? -1 : a.order! < b.order! ? 1 : -1))
252
+ .map(approval => this.renderActivityApproval(approval))}
253
+ </ol>
254
+ </div>
255
+ `
256
+ }
257
+
258
+ renderActivityThread(activityThread: ActivityThread) {}
259
+
260
+ renderActivityApproval(activityApproval: ActivityApproval) {
261
+ const { judgment, approver, comment, round, order, createdAt, terminatedAt } = activityApproval
262
+ const { name, email } = approver || {}
263
+
264
+ return html`
265
+ <li>
266
+ <span date>${formatter.format(new Date(terminatedAt || createdAt!))}</span>
267
+ <span status></span>
268
+ <span info>
269
+ ${i18next.t('label.activity-state-' + (judgment || 'started'))}
270
+ <strong><mwc-icon>account_circle</mwc-icon>${name}</strong>
271
+ <p>${comment}</p>
272
+ </span>
273
+ </li>
274
+ `
275
+ }
276
+
277
+ renderInOut(data) {
278
+ const { activity } = this.activityThread!.activityInstance!
279
+ const { model } = activity || {}
280
+
281
+ return html`
282
+ <table>
283
+ <tr>
284
+ <th>${i18next.t('label.name')}</th>
285
+ <th>${i18next.t('label.value')}</th>
286
+ </tr>
287
+ ${model?.map(
288
+ item => html`
289
+ <tr>
290
+ <td>${item.name}</td>
291
+ <td>${item.tag ? data[item.tag] : ''}</td>
292
+ </tr>
293
+ `
294
+ )}
295
+ </table>
296
+ `
297
+ }
298
+
299
+ updated(changes) {
300
+ if (changes.has('activityThreadId')) {
301
+ this.fetchActivityThread()
302
+ }
303
+ }
304
+
305
+ async fetchActivityThread() {
306
+ const id = this.activityThreadId
307
+
308
+ const response = await client.query({
309
+ query: gql`
310
+ query ($id: String!) {
311
+ activityThread(id: $id) {
312
+ state
313
+ transaction
314
+ output
315
+ assignee {
316
+ id
317
+ name
318
+ email
319
+ }
320
+ round
321
+ activityApprovals {
322
+ round
323
+ order
324
+ approver {
325
+ name
326
+ email
327
+ }
328
+ judgment
329
+ comment
330
+ createdAt
331
+ terminatedAt
332
+ }
333
+ assignedAt
334
+ startedAt
335
+ terminatedAt
336
+ updater {
337
+ id
338
+ name
339
+ }
340
+ activityInstance {
341
+ id
342
+ name
343
+ description
344
+ state
345
+ key01
346
+ key02
347
+ key03
348
+ key04
349
+ key05
350
+ input
351
+ output
352
+ activity {
353
+ id
354
+ name
355
+ description
356
+ searchKeys {
357
+ name
358
+ description
359
+ inputKey
360
+ tKey
361
+ }
362
+ model {
363
+ name
364
+ description
365
+ active
366
+ tag
367
+ inout
368
+ type
369
+ unit
370
+ options
371
+ quantifier
372
+ spec
373
+ }
374
+ }
375
+ approvalLine {
376
+ type
377
+ value
378
+ approver {
379
+ id
380
+ name
381
+ description
382
+ controlNo
383
+ }
384
+ }
385
+ assignedAt
386
+ startedAt
387
+ terminatedAt
388
+ updatedAt
389
+ }
390
+ }
391
+ }
392
+ `,
393
+ variables: {
394
+ id
395
+ }
396
+ })
397
+
398
+ this.activityThread = response.data.activityThread
399
+ this.setAttribute('state', this.activityThread?.state || '')
400
+ }
401
+ }
@@ -80,7 +80,7 @@ export class DoneListCalendarPage extends connect(store)(PageView) {
80
80
  const color = ['black', 'darkgray', 'orange', 'red'][priority || 0]
81
81
  const href =
82
82
  type == 'activity-thread'
83
- ? `activity-thread/${id}?title=${name}`
83
+ ? `activity-thread-view/${id}?title=${name}`
84
84
  : `activity-approval/${id}?title=${name}`
85
85
  const at = new Date(date).toLocaleTimeString([], {
86
86
  hourCycle: 'h23',
@@ -354,6 +354,6 @@ export class DoneListPage extends connect(store)(localize(i18next)(PageView)) {
354
354
  }
355
355
 
356
356
  openActivityThreadViewPage(activityThread) {
357
- navigate(`activity-thread/${activityThread.id}?title=${activityThread.name}`)
357
+ navigate(`activity-thread-view/${activityThread.id}?title=${activityThread.name}`)
358
358
  }
359
359
  }
@@ -127,8 +127,9 @@ let ActivityApprovalPage = class ActivityApprovalPage extends connect(store)(loc
127
127
  return this.customElementContent();
128
128
  case 'page':
129
129
  case 'external':
130
- default:
131
130
  return html ``;
131
+ default:
132
+ return this.generatedContent();
132
133
  }
133
134
  }
134
135
  templateContent() {