@things-factory/worklist 10.1.42 → 10.1.46
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.
- package/dist-client/components/activity-thread-timeline.d.ts +2 -2
- package/dist-client/components/decision-slots.d.ts +14 -1
- package/dist-client/components/decision-slots.js +33 -1
- package/dist-client/components/decision-slots.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-page.js +3 -3
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-approval/approval-gate.d.ts +14 -6
- package/dist-client/pages/activity-approval/approval-gate.js +17 -5
- package/dist-client/pages/activity-approval/approval-gate.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.js +6 -3
- package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/activity-instance/approval-line-input.d.ts +29 -0
- package/dist-server/controllers/activity-instance/approval-line-input.js +44 -0
- package/dist-server/controllers/activity-instance/approval-line-input.js.map +1 -0
- package/dist-server/controllers/activity-instance/assign.js +12 -2
- package/dist-server/controllers/activity-instance/assign.js.map +1 -1
- package/dist-server/controllers/activity-instance/claim-draft.d.ts +17 -0
- package/dist-server/controllers/activity-instance/claim-draft.js +30 -0
- package/dist-server/controllers/activity-instance/claim-draft.js.map +1 -0
- package/dist-server/controllers/activity-instance/discard-draft.d.ts +5 -5
- package/dist-server/controllers/activity-instance/discard-draft.js +5 -5
- package/dist-server/controllers/activity-instance/discard-draft.js.map +1 -1
- package/dist-server/controllers/activity-instance/draft.js +11 -0
- package/dist-server/controllers/activity-instance/draft.js.map +1 -1
- package/dist-server/controllers/activity-instance/issue.js +20 -0
- package/dist-server/controllers/activity-instance/issue.js.map +1 -1
- package/dist-server/controllers/activity-instance/pick.js +16 -0
- package/dist-server/controllers/activity-instance/pick.js.map +1 -1
- package/dist-server/controllers/common.js +4 -3
- package/dist-server/controllers/common.js.map +1 -1
- package/dist-server/service/activity-summary/activity-summary-query.js +6 -53
- package/dist-server/service/activity-summary/activity-summary-query.js.map +1 -1
- package/dist-server/service/activity-summary/index.d.ts +2 -1
- package/dist-server/service/activity-summary/index.js +2 -1
- package/dist-server/service/activity-summary/index.js.map +1 -1
- package/dist-server/service/activity-summary/open-work.d.ts +5 -0
- package/dist-server/service/activity-summary/open-work.js +63 -0
- package/dist-server/service/activity-summary/open-work.js.map +1 -0
- package/dist-server/service/activity-summary/person-open-work.d.ts +17 -0
- package/dist-server/service/activity-summary/person-open-work.js +68 -0
- package/dist-server/service/activity-summary/person-open-work.js.map +1 -0
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/tests/approval-line-input.test.ts +112 -0
- package/tests/delegate-thread.test.ts +101 -0
- package/tests/discard-draft.test.ts +53 -15
- package/tests/discard-versus-issue.pg.test.ts +127 -0
- package/tests/org-member-domain.test.ts +87 -0
- package/tests/person-open-work.test.ts +91 -0
- package/tests/pick-race.pg.test.ts +128 -0
- package/translations/en.json +3 -0
- package/translations/ja.json +3 -0
- package/translations/ko.json +3 -0
- package/translations/ms.json +3 -0
- package/translations/zh.json +3 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { join } from 'path'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Picking the same case at the same moment, on postgres.
|
|
5
|
+
*
|
|
6
|
+
* pick read the instance, checked it was issued or unassigned, then made a thread - holding nothing in
|
|
7
|
+
* between. Runs only when WORKLIST_PG_URL names a postgres server (see discard-versus-issue.pg.test.ts).
|
|
8
|
+
*
|
|
9
|
+
* A case waiting for one person must end with one thread, whoever wins; and one person pressing twice
|
|
10
|
+
* must not hold it twice.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const url = process.env.WORKLIST_PG_URL
|
|
14
|
+
const maybe = url ? describe : describe.skip
|
|
15
|
+
|
|
16
|
+
maybe('picking at once, on postgres', () => {
|
|
17
|
+
const { DataSource } = require('typeorm')
|
|
18
|
+
const { entityClosure } = require(join(__dirname, '..', '..', 'ops-master', 'test', 'support', 'database.cjs'))
|
|
19
|
+
const { NamingStrategy } = require('@things-factory/shell/dist-server/initializers/naming-strategy.js')
|
|
20
|
+
const DIST = join(__dirname, '..', 'dist-server')
|
|
21
|
+
const { Activity } = require(join(DIST, 'service', 'activity', 'activity.js'))
|
|
22
|
+
const { ActivityInstance } = require(join(DIST, 'service', 'activity-instance', 'activity-instance.js'))
|
|
23
|
+
const { ActivityThread } = require(join(DIST, 'service', 'activity-thread', 'activity-thread.js'))
|
|
24
|
+
const { ActivityApproval } = require(join(DIST, 'service', 'activity-approval', 'activity-approval.js'))
|
|
25
|
+
const { pick } = require(join(DIST, 'controllers', 'activity-instance', 'pick.js'))
|
|
26
|
+
const { Domain } = require('@things-factory/shell')
|
|
27
|
+
const { Role, User } = require('@things-factory/auth-base')
|
|
28
|
+
|
|
29
|
+
let db: any
|
|
30
|
+
let domain: any
|
|
31
|
+
let role: any
|
|
32
|
+
let first: any
|
|
33
|
+
let second: any
|
|
34
|
+
let activity: any
|
|
35
|
+
|
|
36
|
+
beforeAll(async () => {
|
|
37
|
+
db = new DataSource({
|
|
38
|
+
type: 'postgres',
|
|
39
|
+
url,
|
|
40
|
+
synchronize: true,
|
|
41
|
+
dropSchema: true,
|
|
42
|
+
entities: entityClosure([Activity, ActivityInstance, ActivityThread, ActivityApproval]),
|
|
43
|
+
namingStrategy: new NamingStrategy()
|
|
44
|
+
})
|
|
45
|
+
await db.initialize()
|
|
46
|
+
|
|
47
|
+
domain = await db.getRepository(Domain).save({ name: 'd', subdomain: 'd' })
|
|
48
|
+
const person = (name: string) =>
|
|
49
|
+
db.getRepository(User).save({ name, email: `${name}@example.com`, password: 'x', status: 'activated', domains: [domain] })
|
|
50
|
+
first = await person('first')
|
|
51
|
+
second = await person('second')
|
|
52
|
+
role = await db.getRepository(Role).save({ domain, name: 'pickers', users: [first, second] })
|
|
53
|
+
activity = await db.getRepository(Activity).save({ domain, name: 'pick', activityType: 'standard', startingType: 'issue' })
|
|
54
|
+
}, 60000)
|
|
55
|
+
|
|
56
|
+
afterAll(async () => db?.destroy())
|
|
57
|
+
|
|
58
|
+
const as = (user: any) => (tx: any) => ({ state: { domain, user, tx }, t: (key: string) => key }) as any
|
|
59
|
+
|
|
60
|
+
const aCase = (round: number) =>
|
|
61
|
+
db.getRepository(ActivityInstance).save({
|
|
62
|
+
domain,
|
|
63
|
+
name: `p${round}`,
|
|
64
|
+
state: 'issued',
|
|
65
|
+
activity,
|
|
66
|
+
assigneeRole: role,
|
|
67
|
+
threadsMin: 1,
|
|
68
|
+
threadsMax: 1
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const threadsOf = (instance: any) => db.getRepository(ActivityThread).count({ where: { activityInstance: { id: instance.id } } })
|
|
72
|
+
|
|
73
|
+
it('two people picking a case that waits for one: one thread, the other refused', async () => {
|
|
74
|
+
const endings: string[] = []
|
|
75
|
+
|
|
76
|
+
for (let round = 0; round < 20; round++) {
|
|
77
|
+
const instance = await aCase(round)
|
|
78
|
+
|
|
79
|
+
const results = await Promise.allSettled([
|
|
80
|
+
db.transaction((tx: any) => pick(instance.id, as(first)(tx))),
|
|
81
|
+
db.transaction((tx: any) => pick(instance.id, as(second)(tx)))
|
|
82
|
+
])
|
|
83
|
+
|
|
84
|
+
const won = results.filter(one => one.status === 'fulfilled').length
|
|
85
|
+
endings.push(`${won} won, ${await threadsOf(instance)} threads`)
|
|
86
|
+
|
|
87
|
+
expect(await threadsOf(instance)).toBe(1)
|
|
88
|
+
expect(won).toBe(1)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log('endings', [...new Set(endings)].join(' · '))
|
|
92
|
+
}, 120000)
|
|
93
|
+
|
|
94
|
+
it('one person pressing twice holds the case once', async () => {
|
|
95
|
+
for (let round = 0; round < 20; round++) {
|
|
96
|
+
const instance = await aCase(100 + round)
|
|
97
|
+
|
|
98
|
+
await Promise.allSettled([
|
|
99
|
+
db.transaction((tx: any) => pick(instance.id, as(first)(tx))),
|
|
100
|
+
db.transaction((tx: any) => pick(instance.id, as(first)(tx)))
|
|
101
|
+
])
|
|
102
|
+
|
|
103
|
+
expect(await threadsOf(instance)).toBe(1)
|
|
104
|
+
}
|
|
105
|
+
}, 120000)
|
|
106
|
+
|
|
107
|
+
it('a case waiting for two lets two people in at once', async () => {
|
|
108
|
+
for (let round = 0; round < 10; round++) {
|
|
109
|
+
const instance = await db.getRepository(ActivityInstance).save({
|
|
110
|
+
domain,
|
|
111
|
+
name: `two${round}`,
|
|
112
|
+
state: 'issued',
|
|
113
|
+
activity,
|
|
114
|
+
assigneeRole: role,
|
|
115
|
+
threadsMin: 2,
|
|
116
|
+
threadsMax: 2
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const results = await Promise.allSettled([
|
|
120
|
+
db.transaction((tx: any) => pick(instance.id, as(first)(tx))),
|
|
121
|
+
db.transaction((tx: any) => pick(instance.id, as(second)(tx)))
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
expect(results.map(one => one.status)).toEqual(['fulfilled', 'fulfilled'])
|
|
125
|
+
expect(await threadsOf(instance)).toBe(2)
|
|
126
|
+
}
|
|
127
|
+
}, 120000)
|
|
128
|
+
})
|
package/translations/en.json
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"error.activity-instance is addressed to another role": "{id} is assigned to another role. only someone with that role can pick it.",
|
|
39
39
|
"error.activity-instance is already issued": "this task ({id}) has already been issued with the {state} status.",
|
|
40
40
|
"error.activity-instance is already terminated": "this task ({id}) has already been terminated with the {state} status.",
|
|
41
|
+
"error.activity-instance approval line is set": "this task already has its approval line; it is set on the task's detail screen.",
|
|
42
|
+
"error.activity-instance assignee not in this domain": "these are not people of this site: {emails}",
|
|
43
|
+
"error.activity-instance draft is gone": "this draft went out or was thrown away in the meantime. please read the list again.",
|
|
41
44
|
"error.activity-instance not found": "this task ({activityInstance}) cannot be found.",
|
|
42
45
|
"error.activity-instance not a draft any more": "this draft has already gone out, so it cannot be thrown away.",
|
|
43
46
|
"error.activity-instance should not be assigned": "this task ({id}) is already in {actual} status and cannot be assigned.",
|
package/translations/ja.json
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"error.activity-instance is addressed to another role": "{id} は別の役割に割り当てられた業務です。その役割を持つ人だけが選択できます。",
|
|
39
39
|
"error.activity-instance is already issued": "このタスク({id})はすでに{state}状態で発行されています。",
|
|
40
40
|
"error.activity-instance is already terminated": "このタスク({id})はすでに{state}状態で終了しています。",
|
|
41
|
+
"error.activity-instance approval line is set": "この業務は決裁ラインが決まっています。決裁ラインは業務詳細で変更します。",
|
|
42
|
+
"error.activity-instance assignee not in this domain": "このサイトの人ではありません: {emails}",
|
|
43
|
+
"error.activity-instance draft is gone": "この下書きはその間に発行されたか破棄されました。一覧を読み直してください。",
|
|
41
44
|
"error.activity-instance not found": "このタスク({activityInstance})が見つかりません。",
|
|
42
45
|
"error.activity-instance not a draft any more": "この下書きはすでに発行されたため、破棄できません。",
|
|
43
46
|
"error.activity-instance should not be assigned": "このタスク({id})はすでに{actual}状態のため、割り当てできません。",
|
package/translations/ko.json
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"error.activity-instance is addressed to another role": "{id} 는 다른 역할에 할당된 업무입니다. 그 역할을 가진 사람만 선택할 수 있습니다.",
|
|
39
39
|
"error.activity-instance is already issued": "이 작업({id})은 이미 {state} 상태로 제기되었습니다.",
|
|
40
40
|
"error.activity-instance is already terminated": "이 작업({id})는 이미 {state} 상태로 종료되었습니다.",
|
|
41
|
+
"error.activity-instance approval line is set": "이 업무는 결재선이 정해져 있습니다. 결재선은 업무 상세에서 바꿉니다.",
|
|
42
|
+
"error.activity-instance assignee not in this domain": "이 사업장 사람이 아닙니다: {emails}",
|
|
43
|
+
"error.activity-instance draft is gone": "이 초안은 그사이 발행되었거나 버려졌습니다. 목록을 새로 읽어 주십시오.",
|
|
41
44
|
"error.activity-instance not found": "이 작업({activityInstance})을 찾을 수 없습니다.",
|
|
42
45
|
"error.activity-instance not a draft any more": "이 초안은 이미 발행되어 버릴 수 없습니다.",
|
|
43
46
|
"error.activity-instance should not be assigned": "이 작업({id})은 이미 {actual} 상태로 할당할 수 없습니다.",
|
package/translations/ms.json
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"error.activity-instance is addressed to another role": "{id} ditugaskan kepada peranan lain. hanya orang yang memegang peranan itu boleh memilihnya.",
|
|
39
39
|
"error.activity-instance is already issued": "Tugas ini ({id}) telah dikeluarkan dengan status {state}.",
|
|
40
40
|
"error.activity-instance is already terminated": "Tugas ini ({id}) telah tamat dengan status {state}.",
|
|
41
|
+
"error.activity-instance approval line is set": "tugas ini sudah mempunyai laluan kelulusan; ia ditetapkan pada skrin butiran tugas.",
|
|
42
|
+
"error.activity-instance assignee not in this domain": "ini bukan orang dalam domain ini: {emails}",
|
|
43
|
+
"error.activity-instance draft is gone": "draf ini telah dikeluarkan atau dibuang sementara itu. sila baca senarai semula.",
|
|
41
44
|
"error.activity-instance not found": "Tugas ini ({activityInstance}) tidak dijumpai.",
|
|
42
45
|
"error.activity-instance not a draft any more": "draf ini sudah dikeluarkan, jadi ia tidak boleh dibuang.",
|
|
43
46
|
"error.activity-instance should not be assigned": "Tugas ini ({id}) sudah berada dalam status {actual} dan tidak boleh diberikan.",
|
package/translations/zh.json
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"error.activity-instance is addressed to another role": "{id} 已分配给其他角色。只有拥有该角色的人员才能选择。",
|
|
39
39
|
"error.activity-instance is already issued": "此任务({id})已被以{state}状态提出。",
|
|
40
40
|
"error.activity-instance is already terminated": "此任务({id})已以{state}状态终止。",
|
|
41
|
+
"error.activity-instance approval line is set": "此业务已设定审批线,请在业务详情中修改。",
|
|
42
|
+
"error.activity-instance assignee not in this domain": "以下不是本站点的人员:{emails}",
|
|
43
|
+
"error.activity-instance draft is gone": "此草稿在此期间已发布或已丢弃,请重新读取列表。",
|
|
41
44
|
"error.activity-instance not found": "未找到此任务({activityInstance})。",
|
|
42
45
|
"error.activity-instance not a draft any more": "此草稿已发布,无法丢弃。",
|
|
43
46
|
"error.activity-instance should not be assigned": "此任务({id})已处于{actual}状态,无法分配。",
|