@live-change/task-frontend 0.8.27 → 0.8.29

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.
@@ -1,13 +1,57 @@
1
1
  <template>
2
- <div>
3
- <h1>Hello world!</h1>
4
- <p>{{ currentTime }}</p>
5
- <Clock :time="currentTime" />
2
+ <div class="flex flex-row w-full justify-content-evenly">
3
+ <div class="surface-card shadow-1 border-round px-3 py-1">
4
+ <h2>Built shelters</h2>
5
+
6
+ <div>
7
+
8
+ </div>
9
+
10
+ <command-form service="testTasks" action="buildShelter" reset-on-done v-slot="{ data, definition }">
11
+ <pre>{{ definition.properties }}</pre>
12
+ <pre>{{data}}</pre>
13
+
14
+ <div class="text text-xl">
15
+ Size:
16
+ </div>
17
+ <div class="pl-2">
18
+ <div class="flex flex-row align-items-center">
19
+ <label for="role" class="mr-2 w-5rem text-right">Width:</label>
20
+ <InputNumber v-model="data.size.width" mode="decimal"
21
+ showButtons :min="3" :max="9" />
22
+ </div>
23
+ <div class="flex flex-row align-items-center">
24
+ <label for="role" class="mr-2 w-5rem text-right">Height:</label>
25
+ <InputNumber v-model="data.size.height" mode="decimal" showButtons :min="3" :max="9" />
26
+ </div>
27
+ <div class="flex flex-row align-items-center">
28
+ <label for="role" class="mr-2 w-5rem text-right">Length:</label>
29
+ <InputNumber v-model="data.size.length" mode="decimal" showButtons :min="3" :max="9" />
30
+ </div>
31
+
32
+ <div class="flex flex-row align-items-center">
33
+ <label for="role" class="mr-2 w-5rem">Wood type:</label>
34
+ <Dropdown id="role" class="w-14rem" v-model="data.woodType" placeholder="Select a Wood type"
35
+ :options="definition.properties.woodType.options" />
36
+ </div>
37
+
38
+ <div class="text-right">
39
+ <Button type="submit" icon="pi pi-play" label="Build" class="mt-2" />
40
+ </div>
41
+ </div>
42
+
43
+ </command-form>
44
+ </div>
45
+ <div class="surface-card shadow-1 border-round px-3 py-1">
46
+ <h2>Tasks</h2>
47
+
48
+ </div>
6
49
  </div>
7
50
  </template>
8
51
 
9
52
  <script setup>
10
- import { currentTime } from "@live-change/frontend-base";
53
+
54
+
11
55
 
12
56
  </script>
13
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/task-frontend",
3
- "version": "0.8.27",
3
+ "version": "0.8.29",
4
4
  "scripts": {
5
5
  "memDev": "node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "rm tmp.db; node server/start.js localDev --enableSessions --initScript ./init.js",
@@ -35,41 +35,41 @@
35
35
  "@codemirror/language": "6.10.1",
36
36
  "@dotenvx/dotenvx": "0.27.0",
37
37
  "@fortawesome/fontawesome-free": "^6.4.2",
38
- "@live-change/access-control-frontend": "^0.8.27",
39
- "@live-change/access-control-service": "^0.8.27",
40
- "@live-change/backup-service": "^0.8.27",
41
- "@live-change/blog-frontend": "^0.8.27",
42
- "@live-change/blog-service": "^0.8.27",
43
- "@live-change/cli": "^0.8.27",
44
- "@live-change/content-frontend": "^0.8.27",
45
- "@live-change/content-service": "^0.8.27",
46
- "@live-change/dao": "^0.8.27",
47
- "@live-change/dao-vue3": "^0.8.27",
48
- "@live-change/dao-websocket": "^0.8.27",
49
- "@live-change/db-client": "^0.8.27",
50
- "@live-change/email-service": "^0.8.27",
51
- "@live-change/framework": "^0.8.27",
52
- "@live-change/frontend-auto-form": "^0.8.27",
53
- "@live-change/frontend-base": "^0.8.27",
54
- "@live-change/geoip-service": "^0.8.27",
55
- "@live-change/image-frontend": "^0.8.27",
56
- "@live-change/locale-settings-service": "^0.8.27",
57
- "@live-change/password-authentication-service": "^0.8.27",
58
- "@live-change/prosemirror-service": "^0.8.27",
59
- "@live-change/secret-code-service": "^0.8.27",
60
- "@live-change/secret-link-service": "^0.8.27",
61
- "@live-change/session-service": "^0.8.27",
62
- "@live-change/task-service": "^0.8.27",
63
- "@live-change/upload-frontend": "^0.8.27",
64
- "@live-change/url-frontend": "^0.8.27",
65
- "@live-change/url-service": "^0.8.27",
66
- "@live-change/user-frontend": "^0.8.27",
67
- "@live-change/user-identification-service": "^0.8.27",
68
- "@live-change/user-service": "^0.8.27",
69
- "@live-change/vote-service": "^0.8.27",
70
- "@live-change/vue3-components": "^0.8.27",
71
- "@live-change/vue3-ssr": "^0.8.27",
72
- "@live-change/wysiwyg-frontend": "^0.8.27",
38
+ "@live-change/access-control-frontend": "^0.8.29",
39
+ "@live-change/access-control-service": "^0.8.29",
40
+ "@live-change/backup-service": "^0.8.29",
41
+ "@live-change/blog-frontend": "^0.8.29",
42
+ "@live-change/blog-service": "^0.8.29",
43
+ "@live-change/cli": "^0.8.29",
44
+ "@live-change/content-frontend": "^0.8.29",
45
+ "@live-change/content-service": "^0.8.29",
46
+ "@live-change/dao": "^0.8.29",
47
+ "@live-change/dao-vue3": "^0.8.29",
48
+ "@live-change/dao-websocket": "^0.8.29",
49
+ "@live-change/db-client": "^0.8.29",
50
+ "@live-change/email-service": "^0.8.29",
51
+ "@live-change/framework": "^0.8.29",
52
+ "@live-change/frontend-auto-form": "^0.8.29",
53
+ "@live-change/frontend-base": "^0.8.29",
54
+ "@live-change/geoip-service": "^0.8.29",
55
+ "@live-change/image-frontend": "^0.8.29",
56
+ "@live-change/locale-settings-service": "^0.8.29",
57
+ "@live-change/password-authentication-service": "^0.8.29",
58
+ "@live-change/prosemirror-service": "^0.8.29",
59
+ "@live-change/secret-code-service": "^0.8.29",
60
+ "@live-change/secret-link-service": "^0.8.29",
61
+ "@live-change/session-service": "^0.8.29",
62
+ "@live-change/task-service": "^0.8.29",
63
+ "@live-change/upload-frontend": "^0.8.29",
64
+ "@live-change/url-frontend": "^0.8.29",
65
+ "@live-change/url-service": "^0.8.29",
66
+ "@live-change/user-frontend": "^0.8.29",
67
+ "@live-change/user-identification-service": "^0.8.29",
68
+ "@live-change/user-service": "^0.8.29",
69
+ "@live-change/vote-service": "^0.8.29",
70
+ "@live-change/vue3-components": "^0.8.29",
71
+ "@live-change/vue3-ssr": "^0.8.29",
72
+ "@live-change/wysiwyg-frontend": "^0.8.29",
73
73
  "@vueuse/core": "^10.9.0",
74
74
  "codeceptjs-assert": "^0.0.5",
75
75
  "compression": "^1.7.4",
@@ -91,7 +91,7 @@
91
91
  "vue3-scroll-border": "0.1.6"
92
92
  },
93
93
  "devDependencies": {
94
- "@live-change/codeceptjs-helper": "^0.8.27",
94
+ "@live-change/codeceptjs-helper": "^0.8.29",
95
95
  "codeceptjs": "^3.5.12",
96
96
  "generate-password": "1.7.1",
97
97
  "playwright": "^1.41.2",
@@ -102,5 +102,5 @@
102
102
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
103
103
  "license": "ISC",
104
104
  "description": "",
105
- "gitHead": "9a84f91121fb5fc2c9fd2acb9a7e5a0a952d611e"
105
+ "gitHead": "9bc23973964b33f2e837db9fbf8dfb51916752a8"
106
106
  }
@@ -94,6 +94,9 @@ app.config = {
94
94
  name: 'backup',
95
95
  port: 8007
96
96
  },
97
+ {
98
+ name: 'testTasks'
99
+ }
97
100
  ]
98
101
  }
99
102
 
@@ -47,3 +47,8 @@ export {
47
47
  task,
48
48
  init
49
49
  }
50
+
51
+ import testTasks from './testTasks.js'
52
+ export {
53
+ testTasks
54
+ }
@@ -0,0 +1,287 @@
1
+ import App from '@live-change/framework'
2
+ const app = App.app()
3
+
4
+ import relationsPlugin from '@live-change/relations-plugin'
5
+ import accessControlService from '@live-change/access-control-service'
6
+
7
+ const definition = app.createServiceDefinition({
8
+ name: "testTasks",
9
+ use: [ relationsPlugin, accessControlService ]
10
+ })
11
+
12
+ import { task } from '@live-change/task-service'
13
+
14
+ import PQueue from 'p-queue'
15
+
16
+ const workersCount = 2
17
+ const workDuration = 1000
18
+ const pauseDuration = 500
19
+
20
+
21
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
22
+
23
+ const workerQueue = new PQueue({ concurrency: workersCount })
24
+
25
+ const getWood = task({
26
+ name: 'getWood',
27
+ properties: {
28
+ woodType: {
29
+ type: String,
30
+ validation: ['nonEmpty']
31
+ },
32
+ },
33
+ returns: {
34
+ type: 'Wood',
35
+ properties: {
36
+ type: {
37
+ type: String
38
+ }
39
+ }
40
+ },
41
+ async execute({ woodType }, { service, task }, emit) {
42
+ await sleep(workDuration)
43
+ return {
44
+ type: 'Wood',
45
+ woodType
46
+ }
47
+ }
48
+ })
49
+
50
+ const cutWood = task({
51
+ name: 'cutWood',
52
+ properties: {
53
+ wood: {
54
+ type: 'Wood',
55
+ properties: {
56
+ woodType: {
57
+ type: String
58
+ }
59
+ }
60
+ },
61
+ },
62
+ returns: {
63
+ type: Array,
64
+ of: {
65
+ type: 'Plank',
66
+ properties: {
67
+ type: {
68
+ type: String
69
+ }
70
+ }
71
+ }
72
+ },
73
+ async execute({ wood }, { service, task }, emit) {
74
+ await sleep(workDuration)
75
+ return Array(4).fill(0).map(() => ({
76
+ type: 'Plank',
77
+ woodType: wood.woodType
78
+ }))
79
+ }
80
+ })
81
+
82
+ const makePlanks = task({
83
+ name: 'makePlanks',
84
+ properties: {
85
+ woodType: {
86
+ type: String,
87
+ validation: ['nonEmpty']
88
+ },
89
+ },
90
+ returns: {
91
+ type: Array,
92
+ of: {
93
+ type: 'Plank',
94
+ properties: {
95
+ type: {
96
+ type: String
97
+ }
98
+ }
99
+ }
100
+ },
101
+ async execute({ type }, { service, task }, emit) {
102
+ const wood = await workerQueue.add(task.run(getWood, { type }))
103
+ await sleep(pauseDuration)
104
+ const planks = await workerQueue.add(task.run(cutWood, { wood }))
105
+ await sleep(pauseDuration)
106
+ return planks
107
+ }
108
+ })
109
+
110
+ const buildShelter = task({
111
+ name: "buildShelter",
112
+ properties: {
113
+ size: {
114
+ type: Object,
115
+ properties: {
116
+ width: { type: Number },
117
+ height: { type: Number },
118
+ length: { type: Number }
119
+ },
120
+ validation: ['nonEmpty']
121
+ },
122
+ woodType: {
123
+ type: String,
124
+ options: ['acacia', 'oak', 'birch', 'spruce'],
125
+ validation: ['nonEmpty']
126
+ },
127
+ },
128
+ returns: {
129
+ type: 'Shelter',
130
+ properties: {
131
+ walls: {
132
+ type: Array,
133
+ of: {
134
+ type: 'Wall'
135
+ }
136
+ },
137
+ roof: {
138
+ type: 'Roof'
139
+ }
140
+ }
141
+ },
142
+ async execute({ size: { width, height, length }, woodType }, { service, task }, emit) {
143
+ //// Probably useless
144
+ // compute wall sizes
145
+ const wall1Size = width * height
146
+ const wall2Size = length * height
147
+ // compute roof size
148
+ const roofSize = width * length
149
+ // compute total plank blocks amount
150
+ const howManyPlanks = wall1Size * 2 + wall2Size * 2 + roof
151
+
152
+ let planksCounter = 0
153
+ task.progress(planksCounter, howManyPlanks)
154
+ // gather planks
155
+ const planks = await Promise.all( // do planks in parallel
156
+ Array(howManyPlanks / 4)
157
+ .fill(0)
158
+ .map(
159
+ () => workerQueue.add(async () => {
160
+ const planks = await task.run(makePlanks, { woodType })
161
+ planksCounter += 4
162
+ task.progress(planksCounter, howManyPlanks)
163
+ return planks
164
+ })
165
+ )
166
+ )
167
+
168
+ await sleep(pauseDuration)
169
+
170
+ let placedPlanks = 0
171
+ // build walls
172
+ const walls = await Promise.all( // do walls in parallel
173
+ [wall1, wall2, wall1, wall2].map(
174
+ async (wallSize) => {
175
+ const wall = await workerQueue.add(task.run(buildWall, { planks, wallSize }))
176
+ placedPlanks += wallSize
177
+ task.progress(planksCounter, howManyPlanks)
178
+ return wall
179
+ }
180
+ )
181
+ )
182
+
183
+ await sleep(pauseDuration)
184
+
185
+ // build roof
186
+ const roof = await workerQueue.add(
187
+ async () => {
188
+ const roof = await task.run(buildRoof, { planks })
189
+ placedPlanks += roofSize
190
+ return roof
191
+ }
192
+ )
193
+
194
+ await sleep(pauseDuration)
195
+
196
+ return {
197
+ type: 'Shelter',
198
+ walls,
199
+ roof
200
+ }
201
+ }
202
+ })
203
+
204
+ definition.action({
205
+ name: "buildShelter",
206
+ properties: {
207
+ size: {
208
+ type: Object,
209
+ properties: {
210
+ width: {
211
+ type: Number,
212
+ default: 4
213
+ },
214
+ height: {
215
+ type: Number,
216
+ default: 3
217
+ },
218
+ length: {
219
+ type: Number,
220
+ default: 4
221
+ }
222
+ },
223
+ validation: ['nonEmpty']
224
+ },
225
+ woodType: {
226
+ type: String,
227
+ validation: ['nonEmpty'],
228
+ options: ['acacia', 'oak', 'birch', 'spruce'],
229
+ default: 'oak'
230
+ },
231
+ place: {
232
+ type: String,
233
+ validation: ['nonEmpty'],
234
+ default: 'forest'
235
+ }
236
+ },
237
+ async execute({ size, woodType, place }, { service, client, command }, emit) {
238
+ await buildShelter.start({ size, woodType, place }, 'userAction', command.id)
239
+
240
+ }
241
+ })
242
+
243
+ const Shelter = definition.model({
244
+ name: "Shelter",
245
+ properties: {
246
+ size: {
247
+ type: Object,
248
+ properties: {
249
+ width: { type: Number },
250
+ height: { type: Number },
251
+ length: { type: Number }
252
+ },
253
+ validation: ['nonEmpty']
254
+ },
255
+ woodType: {
256
+ type: String,
257
+ options: ['acacia', 'oak', 'birch', 'spruce'],
258
+ validation: ['nonEmpty']
259
+ },
260
+ walls: {
261
+ type: Array,
262
+ of: {
263
+ type: 'Wall'
264
+ }
265
+ },
266
+ roof: {
267
+ type: 'Roof'
268
+ }
269
+ }
270
+ })
271
+
272
+ definition.trigger({
273
+ name: 'taskBuildShelterDone',
274
+ properties: {
275
+ shelter: {
276
+ type: 'Shelter'
277
+ }
278
+ },
279
+ async execute(props, { service, client }, emit) {
280
+ console.log("Task done", props)
281
+ const { result } = props
282
+ console.log("Shelter built", result)
283
+ }
284
+ })
285
+
286
+
287
+ export default definition
@@ -1,22 +0,0 @@
1
-
2
- <template>
3
- <div class="surface-card p-3 shadow-2 border-round">
4
- {{ d(new Date(), 'long') }}
5
- </div>
6
- </template>
7
-
8
- <script setup lang="ts">
9
- import { defineProps, toRefs } from 'vue'
10
- import { useI18n } from 'vue-i18n'
11
- const { t, d, n } = useI18n()
12
-
13
- const props = defineProps<{
14
- time: number
15
- }>()
16
-
17
- const { time } = toRefs(props)
18
- </script>
19
-
20
- <style scoped>
21
-
22
- </style>