@things-factory/worklist 7.0.0-alpha.4 → 7.0.0-alpha.5

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 (38) hide show
  1. package/client/components/activity-approval-timeline.ts +149 -0
  2. package/client/pages/activity-approval/activity-approval-page.ts +41 -141
  3. package/client/pages/activity-thread/activity-thread-page.ts +28 -24
  4. package/client/pages/activity-thread/activity-thread-view-page.ts +15 -8
  5. package/client/pages/activity-thread/activity-thread-view.ts +6 -114
  6. package/client/templates/activity-approval-context-template.ts +8 -13
  7. package/client/templates/activity-instance-context-template.ts +16 -18
  8. package/client/templates/activity-thread-context-template.ts +47 -157
  9. package/dist-client/components/activity-approval-timeline.d.ts +18 -0
  10. package/dist-client/components/activity-approval-timeline.js +145 -0
  11. package/dist-client/components/activity-approval-timeline.js.map +1 -0
  12. package/dist-client/pages/activity-approval/activity-approval-page.d.ts +1 -2
  13. package/dist-client/pages/activity-approval/activity-approval-page.js +40 -136
  14. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  15. package/dist-client/pages/activity-thread/activity-thread-page.js +26 -16
  16. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  17. package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +1 -0
  18. package/dist-client/pages/activity-thread/activity-thread-view-page.js +13 -4
  19. package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
  20. package/dist-client/pages/activity-thread/activity-thread-view.d.ts +0 -2
  21. package/dist-client/pages/activity-thread/activity-thread-view.js +6 -101
  22. package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
  23. package/dist-client/templates/activity-approval-context-template.d.ts +1 -0
  24. package/dist-client/templates/activity-approval-context-template.js +8 -13
  25. package/dist-client/templates/activity-approval-context-template.js.map +1 -1
  26. package/dist-client/templates/activity-instance-context-template.js +15 -16
  27. package/dist-client/templates/activity-instance-context-template.js.map +1 -1
  28. package/dist-client/templates/activity-thread-context-template.d.ts +1 -0
  29. package/dist-client/templates/activity-thread-context-template.js +46 -151
  30. package/dist-client/templates/activity-thread-context-template.js.map +1 -1
  31. package/dist-client/tsconfig.tsbuildinfo +1 -1
  32. package/dist-server/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +3 -3
  34. package/translations/en.json +1 -0
  35. package/translations/ja.json +7 -6
  36. package/translations/ko.json +1 -0
  37. package/translations/ms.json +1 -0
  38. package/translations/zh.json +5 -4
@@ -0,0 +1,149 @@
1
+ import '@material/mwc-icon'
2
+ import '@things-factory/organization/dist-client/component/approval-line-view.js'
3
+
4
+ import { html, css, LitElement, nothing } from 'lit'
5
+ import { customElement, property } from 'lit/decorators.js'
6
+
7
+ import { connect } from 'pwa-helpers/connect-mixin'
8
+
9
+ import { store } from '@operato/shell'
10
+ import { i18next } from '@operato/i18n'
11
+
12
+ import { ActivityApproval } from '../types/activity-approval'
13
+
14
+ const formatter = new Intl.DateTimeFormat(navigator.language, { dateStyle: 'full', timeStyle: 'short' })
15
+
16
+ @customElement('activity-approval-timeline')
17
+ export class ActivityApprovalTimeline extends connect(store)(LitElement) {
18
+ static styles = [
19
+ css`
20
+ :host {
21
+ display: block;
22
+ margin-bottom: var(--margin-default);
23
+ padding: var(--padding-default);
24
+ }
25
+
26
+ [subtitle] {
27
+ padding: var(--padding-narrow) var(--padding-default);
28
+ background-color: var(--theme-white-color);
29
+ border: 2px solid var(--secondary-text-color);
30
+ border-radius: 15px;
31
+ box-shadow: var(--box-shadow);
32
+ color: var(--secondary-text-color);
33
+ font-weight: bold;
34
+ }
35
+
36
+ ol {
37
+ list-style: none;
38
+ margin: var(--margin-default) 0 0 var(--margin-narrow);
39
+ padding: 0;
40
+ }
41
+
42
+ li {
43
+ display: flex;
44
+ border: none;
45
+ }
46
+
47
+ [info] {
48
+ flex: 1;
49
+ color: var(--secondary-color);
50
+
51
+ strong {
52
+ float: right;
53
+ }
54
+
55
+ mwc-icon {
56
+ position: relative;
57
+ top: 3px;
58
+ font-size: var(--fontsize-large);
59
+ }
60
+
61
+ p {
62
+ background-color: #f4f4f4;
63
+ margin: var(--margin-narrow) 0 var(--margin-default) 0;
64
+ padding: var(--padding-narrow) var(--padding-default);
65
+ font-size: var(--fontsize-small);
66
+ text-align: justify;
67
+ min-height: 20px;
68
+ }
69
+
70
+ p::before {
71
+ content: '';
72
+ float: right;
73
+ margin-top: -10px;
74
+ margin-right: 20px;
75
+ border: 7px solid transparent;
76
+ border-bottom-color: #f4f4f4;
77
+ border-top: 0;
78
+ }
79
+ }
80
+
81
+ [date] {
82
+ opacity: 0.7;
83
+ flex: initial;
84
+ width: 200px;
85
+ max-width: 30%;
86
+ font-size: var(--fontsize-small);
87
+ color: var(--primary-text-color);
88
+ }
89
+
90
+ [status] {
91
+ margin: 0 var(--margin-narrow);
92
+ display: block;
93
+ border-radius: 50%;
94
+ flex: initial;
95
+ width: 12px;
96
+ height: 12px;
97
+ position: relative;
98
+ top: 3px;
99
+ border: 2px solid #fff;
100
+ background-color: var(--worklist-status-color, tomato);
101
+ color: var(--primary-text-color);
102
+ }
103
+
104
+ [status]::before {
105
+ content: '';
106
+ height: 60px;
107
+ width: 2px;
108
+ display: block;
109
+ position: relative;
110
+ margin-left: 5px;
111
+ background-color: var(--worklist-status-color, tomato);
112
+ opacity: 0.2;
113
+ }
114
+ `
115
+ ]
116
+
117
+ @property({ type: Object }) private activityThread
118
+
119
+ render() {
120
+ const { activityApprovals = [] } = this.activityThread || {}
121
+
122
+ return html` ${activityApprovals.length > 0
123
+ ? html`
124
+ <span subtitle>${i18next.t('label.review-and-approval')}</span>
125
+
126
+ <ol>
127
+ ${activityApprovals.map(approval => this.renderActivityApproval(approval))}
128
+ </ol>
129
+ `
130
+ : nothing}`
131
+ }
132
+
133
+ renderActivityApproval(activityApproval: ActivityApproval) {
134
+ const { judgment, approver, comment, createdAt, terminatedAt } = activityApproval
135
+ const { name } = approver || {}
136
+
137
+ return html`
138
+ <li>
139
+ <span date>${formatter.format(new Date(terminatedAt || createdAt!))}</span>
140
+ <span status></span>
141
+ <span info>
142
+ ${i18next.t('label.activity-state-' + (judgment || 'started'))}
143
+ <strong><mwc-icon>account_circle</mwc-icon>${name}</strong>
144
+ <p>${comment}</p>
145
+ </span>
146
+ </li>
147
+ `
148
+ }
149
+ }
@@ -1,11 +1,12 @@
1
1
  import '@operato/property-editor/ox-properties-dynamic-view.js'
2
2
  import '@operato/board/ox-board-viewer.js'
3
3
  import '../../components/activity-approval-ribon.js'
4
+ import '../../components/activity-approval-timeline.js'
4
5
 
5
6
  import gql from 'graphql-tag'
6
- import { css, html } from 'lit'
7
+ import { css, html, nothing } from 'lit'
7
8
  import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'
8
- import { customElement, property, query, state } from 'lit/decorators.js'
9
+ import { customElement, query, state } from 'lit/decorators.js'
9
10
  import { keyed } from 'lit/directives/keyed.js'
10
11
  import { connect } from 'pwa-helpers/connect-mixin.js'
11
12
 
@@ -14,9 +15,6 @@ import { i18next, localize } from '@operato/i18n'
14
15
  import { PageView, store } from '@operato/shell'
15
16
  import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'
16
17
  import { provider } from '@things-factory/board-ui'
17
- import { ActivityApproval } from '../../types/activity-approval.js'
18
-
19
- const formatter = new Intl.DateTimeFormat(navigator.language, { dateStyle: 'short', timeStyle: 'short' })
20
18
 
21
19
  const ActivityApprovalFetchResult = `\
22
20
  {
@@ -30,6 +28,7 @@ const ActivityApprovalFetchResult = `\
30
28
  round
31
29
  order
32
30
  createdAt
31
+ terminatedAt
33
32
  activityThread {
34
33
  state
35
34
  dueAt
@@ -38,6 +37,8 @@ const ActivityApprovalFetchResult = `\
38
37
  id
39
38
  name
40
39
  }
40
+ updatedAt
41
+ terminatedAt
41
42
  output
42
43
  activityApprovals {
43
44
  round
@@ -120,106 +121,30 @@ export class ActivityApprovalPage extends connect(store)(localize(i18next)(PageV
120
121
  height: 100%;
121
122
  }
122
123
 
123
- #custom-content {
124
- overflow: auto;
125
- }
126
-
127
124
  div[comment] {
128
125
  display: flex;
129
- flex-direction: column;
130
- width: 100%;
131
- right: 0;
126
+ position: sticky;
132
127
  bottom: 0;
133
128
  margin: 0;
134
129
  padding: 0;
135
- opacity: 0.8;
136
- margin-top: auto;
130
+ width: 100%;
131
+ background-color: var(--main-section-background-color);
137
132
 
138
- max-height: 40%;
133
+ textarea {
134
+ flex: 1;
135
+ margin: var(--margin-default);
136
+ padding: var(--input-padding);
137
+ font: var(--input-font);
138
+ outline: none;
139
+ height: 80px;
140
+ border-radius: 10px;
141
+ border: var(--input-field-border);
142
+ resize: none;
143
+ }
139
144
  }
140
145
 
141
- div[timeline] {
142
- margin-bottom: var(--margin-default);
143
- padding: var(--padding-default);
144
- border-bottom: var(--border-dark-color);
145
- overflow: auto;
146
- }
147
- div[timeline] [subtitle] {
148
- padding: var(--padding-narrow) var(--padding-default);
149
- background-color: var(--theme-white-color);
150
- border: 2px solid var(--secondary-text-color);
151
- border-radius: 15px;
152
- box-shadow: var(--box-shadow);
153
- color: var(--secondary-text-color);
154
- font-weight: bold;
155
- }
156
- div[timeline] ol {
157
- list-style: none;
158
- margin: var(--margin-default) 0 0 var(--margin-narrow);
159
- padding: 0;
160
- }
161
- [timeline] li {
162
- display: flex;
163
- }
164
- [timeline] [info] {
165
- flex: 1;
166
- }
167
- [timeline] [date] {
168
- opacity: 0.7;
169
- width: 130px;
170
- font-size: var(--fontsize-small);
171
- }
172
- [timeline] [info] strong {
173
- float: right;
174
- }
175
- [timeline] [status] {
176
- margin: 0 var(--margin-narrow);
177
- display: block;
178
- border-radius: 50%;
179
- width: 12px;
180
- height: 12px;
181
- position: relative;
182
- top: 3px;
183
- border: 2px solid #fff;
184
- background-color: var(--worklist-status-color, tomato);
185
- }
186
- [timeline] [status]::before {
187
- content: '';
188
- height: 60px;
189
- width: 2px;
190
- display: block;
191
- position: relative;
192
- margin-left: 5px;
193
- background-color: var(--worklist-status-color, tomato);
194
- opacity: 0.2;
195
- }
196
- [timeline] [info] mwc-icon {
197
- position: relative;
198
- top: 3px;
199
- font-size: var(--fontsize-large);
200
- }
201
- [timeline] [info] p {
202
- background-color: var(--theme-white-color);
203
- margin: var(--margin-narrow) 0 var(--margin-default) 0;
204
- padding: var(--padding-narrow) var(--padding-default);
205
- font-size: var(--fontsize-small);
206
- text-align: justify;
207
- }
208
- [timeline] [info] p::before {
209
- content: '';
210
- float: right;
211
- margin-top: -10px;
212
- margin-right: 20px;
213
- border: 7px solid transparent;
214
- border-bottom-color: #f4f4f4;
215
- border-top: 0;
216
- }
217
- div[comment] textarea {
218
- margin: 0 var(--margin-default) var(--margin-default) var(--margin-default);
219
- padding: var(--input-padding);
220
- resize: none;
221
- font: var(--input-font);
222
- outline: none;
146
+ div[empty] {
147
+ align-self: center;
223
148
  }
224
149
  `
225
150
  ]
@@ -263,51 +188,29 @@ export class ActivityApprovalPage extends connect(store)(localize(i18next)(PageV
263
188
 
264
189
  render() {
265
190
  if (!this.activityThread) {
266
- return html`<div>no activity thread info.</div>`
191
+ return html`<div empty>no activity thread info.</div>`
267
192
  }
268
193
 
269
- const { activityApprovals = [] } = this.activityThread
270
- const approvals = activityApprovals
271
- .sort((a, b) => (a.round > b.round ? 1 : a.round < b.round ? -1 : a.order! > b.order! ? 1 : -1))
272
- .slice(0, -1)
194
+ const { terminatedAt } = this.activityApproval
195
+ const editable = !terminatedAt
273
196
 
274
197
  return html`
275
198
  <activity-approval-ribon .activityApproval=${this.activityApproval}></activity-approval-ribon>
276
199
  ${this.activityContent()}
277
- <div comment>
278
- <div timeline>
279
- <span subtitle>${i18next.t('label.review-and-approval')}</span>
280
-
281
- <ol>
282
- ${approvals.map(approval => this.renderActivityApproval(approval))}
283
- </ol>
284
- </div>
285
-
286
- <textarea
287
- placeholder="Jot down your comment here."
288
- .value=${this.activityApproval?.comment}
289
- @change=${(e: Event) => {
290
- this.activityApproval.comment = (e.target as HTMLTextAreaElement).value
291
- }}
292
- ></textarea>
293
- </div>
294
- `
295
- }
296
-
297
- renderActivityApproval(activityApproval: ActivityApproval) {
298
- const { judgment, approver, comment, round, order, createdAt, terminatedAt } = activityApproval
299
- const { name, email } = approver || {}
300
-
301
- return html`
302
- <li>
303
- <span date>${formatter.format(new Date(terminatedAt || createdAt!))}</span>
304
- <span status></span>
305
- <span info>
306
- ${i18next.t('label.activity-state-' + (judgment || 'started'))}
307
- <strong><mwc-icon>account_circle</mwc-icon>${name}</strong>
308
- <p>${comment}</p>
309
- </span>
310
- </li>
200
+ <activity-approval-timeline .activityThread=${this.activityThread}></activity-approval-timeline>
201
+ ${editable
202
+ ? html`
203
+ <div comment>
204
+ <textarea
205
+ placeholder=${String(i18next.t('text.explain the reason for approval/rejection'))}
206
+ .value=${this.activityApproval?.comment}
207
+ @change=${(e: Event) => {
208
+ this.activityApproval.comment = (e.target as HTMLTextAreaElement).value
209
+ }}
210
+ ></textarea>
211
+ </div>
212
+ `
213
+ : nothing}
311
214
  `
312
215
  }
313
216
 
@@ -393,11 +296,7 @@ export class ActivityApprovalPage extends connect(store)(localize(i18next)(PageV
393
296
  html`
394
297
  <fieldset>
395
298
  <legend>Input</legend>
396
- <ox-properties-dynamic-view
397
- data-name="input"
398
- .props=${inputSpec}
399
- .value=${input}
400
- ></ox-properties-dynamic-view>
299
+ <ox-properties-dynamic-view data-name="input" .props=${inputSpec} .value=${input}></ox-properties-dynamic-view>
401
300
  </fieldset>
402
301
 
403
302
  <fieldset>
@@ -455,6 +354,7 @@ export class ActivityApprovalPage extends connect(store)(localize(i18next)(PageV
455
354
  element.activityId = activityInstance.activity.id
456
355
  element.input = input
457
356
  element.output = output
357
+ element.activityApproval = this.activityApproval
458
358
 
459
359
  return element
460
360
  }
@@ -25,6 +25,7 @@ const ActivityThreadFetchResult = `\
25
25
  id
26
26
  name
27
27
  }
28
+ updatedAt
28
29
  output
29
30
  round
30
31
  activityApprovals {
@@ -111,8 +112,8 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
111
112
  height: 100%;
112
113
  }
113
114
 
114
- #custom-content {
115
- flex: 1;
115
+ div[empty] {
116
+ align-self: center;
116
117
  }
117
118
  `
118
119
  ]
@@ -126,8 +127,8 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
126
127
  const restartable = [ActivityThreadStatus.Rejected].includes(state)
127
128
  const savable = [ActivityThreadStatus.Assigned, ActivityThreadStatus.Started].includes(state)
128
129
  const submittable = savable
129
- const delegatable = savable
130
- const abortable = savable
130
+ // const delegatable = savable
131
+ // const abortable = savable
131
132
 
132
133
  return {
133
134
  title: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),
@@ -145,22 +146,22 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
145
146
  ...CommonButtonStyles.submit
146
147
  },
147
148
 
148
- delegatable && {
149
- title: i18next.t('button.delegate'),
150
- action: this._delegateActivityThread.bind(this),
151
- ...CommonButtonStyles.save
152
- },
149
+ // delegatable && {
150
+ // title: i18next.t('button.delegate'),
151
+ // action: this._delegateActivityThread.bind(this),
152
+ // ...CommonButtonStyles.save
153
+ // },
154
+
155
+ // abortable && {
156
+ // title: i18next.t('button.abort'),
157
+ // action: this._abortActivityThread.bind(this),
158
+ // ...CommonButtonStyles.cancel
159
+ // },
153
160
 
154
161
  restartable && {
155
162
  title: i18next.t('button.restart'),
156
163
  action: this._restartActivityThread.bind(this),
157
164
  ...CommonButtonStyles.save
158
- },
159
-
160
- abortable && {
161
- title: i18next.t('button.abort'),
162
- action: this._abortActivityThread.bind(this),
163
- ...CommonButtonStyles.cancel
164
165
  }
165
166
  ].filter(Boolean /* truthy only */)
166
167
  // activityThread: this.activityThread
@@ -170,10 +171,15 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
170
171
  render() {
171
172
  const activityThread = this.activityThread
172
173
 
173
- return html` ${activityThread
174
- ? html`<activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>`
175
- : html``}
176
- ${this.activityContent()}`
174
+ if (!activityThread) {
175
+ return html`<div empty>no activity thread info.</div> `
176
+ }
177
+
178
+ return html`
179
+ <activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>
180
+ ${this.activityContent()}
181
+ <activity-approval-timeline .activityThread=${activityThread}></activity-approval-timeline>
182
+ `
177
183
  }
178
184
 
179
185
  activityContent() {
@@ -258,11 +264,7 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
258
264
  html`
259
265
  <fieldset>
260
266
  <legend>Input</legend>
261
- <ox-properties-dynamic-view
262
- data-name="input"
263
- .props=${inputSpec}
264
- .value=${input}
265
- ></ox-properties-dynamic-view>
267
+ <ox-properties-dynamic-view data-name="input" .props=${inputSpec} .value=${input}></ox-properties-dynamic-view>
266
268
  </fieldset>
267
269
 
268
270
  <fieldset>
@@ -325,6 +327,8 @@ export class ActivityThreadPage extends connect(store)(localize(i18next)(PageVie
325
327
  element.activityId = activityInstance.activity.id
326
328
  element.input = input
327
329
  element.output = output
330
+ element.activityThread = this.activityThread
331
+
328
332
  element.addEventListener('change', (e: CustomEvent) => {
329
333
  this.activityThread.output = e.detail
330
334
  })
@@ -1,5 +1,6 @@
1
1
  import '@operato/board/ox-board-viewer.js'
2
2
  import '../../components/activity-thread-ribon.js'
3
+ import '../../components/activity-approval-timeline.js'
3
4
  import './activity-thread-view.js'
4
5
 
5
6
  import gql from 'graphql-tag'
@@ -118,6 +119,10 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
118
119
  #custom-content {
119
120
  flex: 1;
120
121
  }
122
+
123
+ div[empty] {
124
+ align-self: center;
125
+ }
121
126
  `
122
127
  ]
123
128
 
@@ -136,10 +141,15 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
136
141
  render() {
137
142
  const activityThread = this.activityThread
138
143
 
139
- return html` ${activityThread
140
- ? html`<activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>`
141
- : html``}
142
- ${this.activityContent()}`
144
+ if (!activityThread) {
145
+ return html`<div empty>no activity thread info.</div> `
146
+ }
147
+
148
+ return html`
149
+ <activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>
150
+ ${this.activityContent()}
151
+ <activity-approval-timeline .activityThread=${activityThread}></activity-approval-timeline>
152
+ `
143
153
  }
144
154
 
145
155
  activityContent() {
@@ -204,10 +214,7 @@ export class ActivityThreadViewPage extends connect(store)(localize(i18next)(Pag
204
214
  return html``
205
215
  }
206
216
 
207
- return keyed(
208
- this.activityThread.id,
209
- html` <activity-thread-view .activityThreadId=${this.activityThread.id}></activity-thread-view> `
210
- )
217
+ return keyed(this.activityThread.id, html` <activity-thread-view .activityThreadId=${this.activityThread.id}></activity-thread-view> `)
211
218
  }
212
219
 
213
220
  boardContent() {