@live-change/task-frontend 0.8.32 → 0.8.33

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.
@@ -4,42 +4,42 @@
4
4
  "deps": {
5
5
  "@codemirror/language": "6.10.1",
6
6
  "@dotenvx/dotenvx": "0.27.0",
7
- "@fortawesome/fontawesome-free": "^6.4.2",
8
- "@live-change/access-control-frontend": "0.8.23",
9
- "@live-change/access-control-service": "0.8.23",
10
- "@live-change/backup-service": "0.8.23",
11
- "@live-change/blog-frontend": "0.8.23",
12
- "@live-change/blog-service": "0.8.23",
13
- "@live-change/cli": "0.8.23",
14
- "@live-change/content-frontend": "0.8.23",
15
- "@live-change/content-service": "0.8.23",
16
- "@live-change/dao": "0.8.23",
17
- "@live-change/dao-vue3": "0.8.23",
18
- "@live-change/dao-websocket": "0.8.23",
19
- "@live-change/db-client": "0.8.23",
20
- "@live-change/email-service": "0.8.23",
21
- "@live-change/framework": "0.8.23",
22
- "@live-change/frontend-auto-form": "0.8.23",
23
- "@live-change/frontend-base": "0.8.23",
24
- "@live-change/geoip-service": "0.8.23",
25
- "@live-change/image-frontend": "0.8.23",
26
- "@live-change/locale-settings-service": "0.8.23",
27
- "@live-change/password-authentication-service": "0.8.23",
28
- "@live-change/prosemirror-service": "0.8.23",
29
- "@live-change/secret-code-service": "0.8.23",
30
- "@live-change/secret-link-service": "0.8.23",
31
- "@live-change/session-service": "0.8.23",
32
- "@live-change/upload-frontend": "0.8.23",
33
- "@live-change/url-frontend": "0.8.23",
34
- "@live-change/url-service": "0.8.23",
35
- "@live-change/vote-service": "0.8.23",
36
- "@live-change/task-service": "0.8.23",
37
- "@live-change/user-frontend": "0.8.23",
38
- "@live-change/user-identification-service": "0.8.23",
39
- "@live-change/user-service": "0.8.23",
40
- "@live-change/vue3-components": "0.8.23",
41
- "@live-change/vue3-ssr": "0.8.23",
42
- "@live-change/wysiwyg-frontend": "0.8.23",
7
+ "@fortawesome/fontawesome-free": "^6.5.2",
8
+ "@live-change/access-control-frontend": "0.8.32",
9
+ "@live-change/access-control-service": "0.8.32",
10
+ "@live-change/backup-service": "0.8.32",
11
+ "@live-change/blog-frontend": "0.8.32",
12
+ "@live-change/blog-service": "0.8.32",
13
+ "@live-change/cli": "0.8.32",
14
+ "@live-change/content-frontend": "0.8.32",
15
+ "@live-change/content-service": "0.8.32",
16
+ "@live-change/dao": "0.8.32",
17
+ "@live-change/dao-vue3": "0.8.32",
18
+ "@live-change/dao-websocket": "0.8.32",
19
+ "@live-change/db-client": "0.8.32",
20
+ "@live-change/email-service": "0.8.32",
21
+ "@live-change/framework": "0.8.32",
22
+ "@live-change/frontend-auto-form": "0.8.32",
23
+ "@live-change/frontend-base": "0.8.32",
24
+ "@live-change/geoip-service": "0.8.32",
25
+ "@live-change/image-frontend": "0.8.32",
26
+ "@live-change/locale-settings-service": "0.8.32",
27
+ "@live-change/password-authentication-service": "0.8.32",
28
+ "@live-change/prosemirror-service": "0.8.32",
29
+ "@live-change/secret-code-service": "0.8.32",
30
+ "@live-change/secret-link-service": "0.8.32",
31
+ "@live-change/session-service": "0.8.32",
32
+ "@live-change/task-service": "0.8.32",
33
+ "@live-change/upload-frontend": "0.8.32",
34
+ "@live-change/url-frontend": "0.8.32",
35
+ "@live-change/url-service": "0.8.32",
36
+ "@live-change/user-frontend": "0.8.32",
37
+ "@live-change/user-identification-service": "0.8.32",
38
+ "@live-change/user-service": "0.8.32",
39
+ "@live-change/vote-service": "0.8.32",
40
+ "@live-change/vue3-components": "0.8.32",
41
+ "@live-change/vue3-ssr": "0.8.32",
42
+ "@live-change/wysiwyg-frontend": "0.8.32",
43
43
  "@vueuse/core": "^10.9.0",
44
44
  "codeceptjs-assert": "^0.0.5",
45
45
  "compression": "^1.7.4",
@@ -59,7 +59,7 @@
59
59
  "vue-i18n": "^9.10.1",
60
60
  "vue-router": "^4.2.5",
61
61
  "vue3-scroll-border": "0.1.6",
62
- "@live-change/codeceptjs-helper": "0.8.23",
62
+ "@live-change/codeceptjs-helper": "0.8.32",
63
63
  "codeceptjs": "^3.5.12",
64
64
  "generate-password": "1.7.1",
65
65
  "playwright": "^1.41.2",
@@ -82,7 +82,7 @@
82
82
  },
83
83
  {
84
84
  "file": "LICENSE",
85
- "hash": "11061867800085944532"
85
+ "hash": "10221119794387200971"
86
86
  },
87
87
  {
88
88
  "file": "data/GeoLite2-Country.mmdb",
@@ -174,15 +174,27 @@
174
174
  },
175
175
  {
176
176
  "file": "front/src/Index.vue",
177
- "hash": "6141752239478277683"
177
+ "hash": "15104691593361452519"
178
+ },
179
+ {
180
+ "file": "front/src/ShelterProgress.vue",
181
+ "hash": "10500323481502622407"
178
182
  },
179
183
  {
180
184
  "file": "front/src/analytics/index.js",
181
185
  "hash": "492811393913301668"
182
186
  },
183
187
  {
184
- "file": "front/src/components/Clock.vue",
185
- "hash": "6241258097645393918"
188
+ "file": "front/src/components/BuildShelterResult.vue",
189
+ "hash": "12307738355148781708"
190
+ },
191
+ {
192
+ "file": "front/src/components/MakePlanksResult.vue",
193
+ "hash": "15891030442450754519"
194
+ },
195
+ {
196
+ "file": "front/src/components/Task.vue",
197
+ "hash": "690040641751569935"
186
198
  },
187
199
  {
188
200
  "file": "front/src/config.js",
@@ -198,7 +210,7 @@
198
210
  },
199
211
  {
200
212
  "file": "front/src/router.js",
201
- "hash": "16714073484061964064"
213
+ "hash": "15530460209801505227"
202
214
  },
203
215
  {
204
216
  "file": "front/tsconfig.json",
@@ -212,17 +224,21 @@
212
224
  "file": "front/vite.config.ts",
213
225
  "hash": "4804285485121244435"
214
226
  },
227
+ {
228
+ "file": "front/vite.config.ts.timestamp-1717571300028-addad6453ee85.mjs",
229
+ "hash": "17152765440974688639"
230
+ },
215
231
  {
216
232
  "file": "index.js",
217
- "hash": "11269213519712721017"
233
+ "hash": "15558335606886518311"
218
234
  },
219
235
  {
220
236
  "file": "package.json",
221
- "hash": "11328295818425146716"
237
+ "hash": "17822390086587439626"
222
238
  },
223
239
  {
224
240
  "file": "server/app.config.js",
225
- "hash": "11753059881031204026"
241
+ "hash": "3863281573320850472"
226
242
  },
227
243
  {
228
244
  "file": "server/init.js",
@@ -238,7 +254,7 @@
238
254
  },
239
255
  {
240
256
  "file": "server/services.list.js",
241
- "hash": "7926432475169575282"
257
+ "hash": "4032859481033847252"
242
258
  },
243
259
  {
244
260
  "file": "server/start.js",
@@ -246,7 +262,7 @@
246
262
  },
247
263
  {
248
264
  "file": "server/testTasks.js",
249
- "hash": "3244421341483603138"
265
+ "hash": "14976257887791558210"
250
266
  },
251
267
  {
252
268
  "file": "start-dev-docker.sh",
Binary file
@@ -1,15 +1,16 @@
1
1
  <template>
2
2
  <div class="flex flex-row w-full justify-content-evenly">
3
3
  <div class="surface-card shadow-1 border-round px-3 py-1">
4
- <h2>Built shelters</h2>
5
4
 
6
5
  <div>
7
-
6
+ <h2>Built shelters</h2>
7
+ <pre>{{ shelters }}</pre>
8
8
  </div>
9
9
 
10
- <command-form service="testTasks" action="buildShelter" reset-on-done v-slot="{ data, definition }">
11
- <pre>{{ definition.properties }}</pre>
12
- <pre>{{data}}</pre>
10
+ <command-form service="testTasks" action="buildShelter" reset-on-done v-slot="{ data, definition }"
11
+ @done="handleStarted">
12
+ <!-- <pre>{{ definition.properties }}</pre>
13
+ <pre>{{ data }}</pre>-->
13
14
 
14
15
  <div class="text text-xl">
15
16
  Size:
@@ -42,16 +43,32 @@
42
43
 
43
44
  </command-form>
44
45
  </div>
45
- <div class="surface-card shadow-1 border-round px-3 py-1">
46
+ <!-- <div class="surface-card shadow-1 border-round px-3 py-1">
47
+ <h2>Root</h2>
48
+ <pre>{{ tasksRoot }}</pre>
46
49
  <h2>Tasks</h2>
47
-
48
- </div>
50
+ <Task v-for="task in rootTasks" :key="task.id" :task="task" :tasks="tasks" :task-types="taskTypes" />
51
+ </div>-->
49
52
  </div>
50
53
  </template>
51
54
 
52
55
  <script setup>
56
+ import { ref, computed } from 'vue'
57
+ import { usePath, live } from '@live-change/vue3-ssr'
58
+ import { useRouter } from 'vue-router'
59
+
60
+ const path = usePath()
61
+
62
+ const router = useRouter()
53
63
 
64
+ const [ shelters ] = await Promise.all([
65
+ live(path.testTasks.shelters({})),
66
+ ])
54
67
 
68
+ function handleStarted({ parameters, result }) {
69
+ console.log("Started", parameters, result)
70
+ router.push({ name: 'progress', params: { action: result.cause }})
71
+ }
55
72
 
56
73
  </script>
57
74
 
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <div class="flex flex-row w-full justify-content-evenly">
3
+ <div class="surface-card shadow-1 border-round px-3 py-1 w-full">
4
+ <h2>Tasks</h2>
5
+ <Task v-for="task in rootTasks" :key="task.id" :task="task" :tasks="tasks" :task-types="taskTypes" />
6
+ <!-- <pre>{{ rootTasks }}</pre>-->
7
+ </div>
8
+ </div>
9
+ <!-- <pre>{{ tasks }}</pre>-->
10
+ </template>
11
+
12
+ <script setup>
13
+ import { ref, computed, defineProps } from 'vue'
14
+ import { usePath, live } from '@live-change/vue3-ssr'
15
+ import BuildShelterResult from './components/BuildShelterResult.vue'
16
+ import MakePlanksResult from './components/MakePlanksResult.vue'
17
+
18
+ const props = defineProps({
19
+ action: {
20
+ type: Object,
21
+ required: true
22
+ }
23
+ })
24
+
25
+ const taskTypes = {
26
+ buildShelter: {
27
+ label(task) {
28
+ return `Building shelter`
29
+ +` ${task.properties.size.width}x${task.properties.size.height}x${task.properties.size.length}`
30
+ +` at ${task.properties.place}`
31
+ +` with ${task.properties.woodType} wood`
32
+ },
33
+ resultComponent: BuildShelterResult
34
+ },
35
+ makePlanks: {
36
+ label(task) {
37
+ return `Making planks from ${task.properties.woodType} wood`
38
+ },
39
+ resultComponent: MakePlanksResult
40
+ },
41
+ getWood: {
42
+ label(task) {
43
+ return `Getting ${task.properties.woodType} wood`
44
+ }
45
+ },
46
+ cutWood: {
47
+ label(task) {
48
+ return `Cutting ${task.properties.wood.woodType} wood`
49
+ }
50
+ },
51
+ buildWall: {
52
+ label(task) {
53
+ return `Building wall with ${task.properties.wallSize} planks`
54
+ }
55
+ },
56
+ buildRoof: {
57
+ label(task) {
58
+ return `Building roof with ${task.properties.roofSize} planks`
59
+ }
60
+ },
61
+ placePlank: {
62
+ label(task) {
63
+ return `Placing plank`
64
+ }
65
+ }
66
+ }
67
+
68
+ const tasksRoot = computed(() => ({
69
+ rootType: 'userAction',
70
+ root: props.action
71
+ }))
72
+
73
+ const path = usePath()
74
+
75
+ const tasksPath = computed(
76
+ () => tasksRoot.value ? path.task.tasksByRoot(tasksRoot.value) : null
77
+ )
78
+
79
+ const [ tasks ] = await Promise.all([
80
+ live(tasksPath)
81
+ ])
82
+
83
+ const rootTasks = computed(() => tasks.value ? tasks.value.filter(t => t.causeType !== 'task_Task') : [])
84
+
85
+ </script>
86
+
87
+ <style scoped>
88
+
89
+ </style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <div class="flex flex-row justify-content-between flex-wrap">
3
+ <div class="font-semibold">
4
+ Built shelter with:
5
+ </div>
6
+ <div v-for="part in result.walls"
7
+ :class="`bg-gray-200 px-1 mx-2 border-round`">
8
+ <span>Wall</span>
9
+ <span class="ml-1">({{ part.size }})</span>
10
+ </div>
11
+ <div v-for="part in [result.roof]"
12
+ :class="`bg-gray-200 px-1 mx-2 border-round`">
13
+ <span>Roof</span>
14
+ <span class="ml-1">({{ part.size }})</span>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup>
20
+ import { defineProps, toRefs } from 'vue'
21
+
22
+ const props = defineProps({
23
+ result: {
24
+ type: Object,
25
+ required: true
26
+ },
27
+ task: {
28
+ type: Object,
29
+ default: () => ({})
30
+ },
31
+ taskType: {
32
+ type: Object,
33
+ default: () => ({})
34
+ }
35
+ })
36
+
37
+ const { result } = toRefs(props)
38
+ </script>
39
+
40
+ <style scoped>
41
+
42
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <div class="flex flex-row">
3
+ <div class="font-semibold">
4
+ Made:
5
+ </div>
6
+ <div v-for="part in result"
7
+ :class="`bg-yellow-200 px-1 mx-2 border-round`">
8
+ <span>{{ part.woodType }}</span>
9
+ <span class="ml-1">plank</span>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { defineProps, toRefs } from 'vue'
16
+
17
+ const props = defineProps({
18
+ result: {
19
+ type: Object,
20
+ required: true
21
+ },
22
+ task: {
23
+ type: Object,
24
+ default: () => ({})
25
+ },
26
+ taskType: {
27
+ type: Object,
28
+ default: () => ({})
29
+ }
30
+ })
31
+
32
+ const { result } = toRefs(props)
33
+ </script>
34
+
35
+ <style scoped>
36
+
37
+ </style>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <div>
3
+ <div class="text-lg flex flex-row justify-content-between flex-wrap" :class="taskColor">
4
+ <div class="flex flex-row align-items-center mr-3">
5
+ <i :class="['pi', icon, taskColor]" style="font-size: 1rem" />
6
+ <div :class="['ml-2']">{{ label }}</div>
7
+ </div>
8
+ <div v-if="task?.progress && task?.state !== 'done'" class="w-8rem mr-3 flex-grow-1" style="max-width: 50vw">
9
+ <ProgressBar :value="(100 * task.progress.current / task.progress.total).toFixed()" />
10
+ </div>
11
+ <div v-if="task?.retries?.length" class="mr-3">
12
+ <i class="pi pi-replay" />
13
+ {{ task.retries.length }} / {{ task.maxRetries }}
14
+ </div>
15
+ <div>{{ task?.state !== 'done' ? (task?.progress?.action || task?.state) : 'done' }}</div>
16
+ </div>
17
+ <div v-for="retry in task?.retries" class="ml-4 flex flex-row justify-content-between text-red-800">
18
+ {{ retry.error }} at {{ d(retry.failedAt, 'shortestTime')}}
19
+ </div>
20
+ <!-- <pre>{{ task.progress }}</pre>-->
21
+ <div v-if="taskResultComponent && task.result" class="m-2">
22
+ <component :is="taskResultComponent" :task="task" :result="task.result" :taskType="taskType" />
23
+ </div>
24
+ <div class="ml-4">
25
+ <Task v-for="task in childTasks" :key="task.id" :task="task" :tasks="tasks" :taskTypes="taskTypes" />
26
+ </div>
27
+ </div>
28
+ </template>
29
+
30
+
31
+ <script setup>
32
+
33
+ import { ref, onMounted, defineProps, toRefs, computed } from "vue"
34
+
35
+ import { useToast } from 'primevue/usetoast'
36
+ const toast = useToast()
37
+ import { useConfirm } from 'primevue/useconfirm'
38
+ const confirm = useConfirm()
39
+
40
+ import { useActions, usePath, live } from '@live-change/vue3-ssr'
41
+ const actions = useActions()
42
+
43
+ import { useI18n } from 'vue-i18n'
44
+ const { t, tm, rt, n, d } = useI18n()
45
+
46
+ const props = defineProps({
47
+ task: {
48
+ type: Object,
49
+ required: true
50
+ },
51
+ tasks: {
52
+ type: Array,
53
+ required: true
54
+ },
55
+ taskTypes: {
56
+ type: Object,
57
+ default: () => ({})
58
+ }
59
+ })
60
+ const { task, tasks, taskTypes } = toRefs(props)
61
+
62
+ const taskId = computed(() => task.value.to || task.value.id)
63
+ const taskType = computed(() => taskTypes.value[task.value.type || task.value.name] || {})
64
+
65
+ const taskResultComponent = computed(() => taskType.value.resultComponent)
66
+
67
+ const label = computed(() => {
68
+ if(taskType.value.label) {
69
+ if(typeof taskType.value.label == 'function') return taskType.value.label(task.value)
70
+ return taskType.value.label
71
+ }
72
+ return task.value.name || task.value.type
73
+ })
74
+
75
+ const childTasks = computed(
76
+ () => tasks.value.filter(m => m.causeType === "task_Task" && m.cause === taskId.value)
77
+ )
78
+
79
+ const icon = computed(() => {
80
+ switch(task.value.state) {
81
+ case 'created': return 'pi-sparkles'
82
+ case 'waiting': return 'pi-hourglass pi-spin'
83
+ case 'running': return 'pi-play'
84
+ case 'working': return 'pi-spin pi-spinner'
85
+ case 'done': return 'pi-check'
86
+ case 'failed': return 'pi-exclamation-triangle'
87
+ case 'retrying': return 'pi-replay'
88
+ default: return 'pi-question'
89
+ }
90
+ })
91
+
92
+ const taskColor = computed(() => {
93
+ switch(task.value.state) {
94
+ case 'failed': return 'text-red-600'
95
+ default: {}
96
+ }
97
+ })
98
+
99
+ </script>
100
+
101
+
102
+ <style scoped>
103
+
104
+ </style>
@@ -24,6 +24,11 @@ export function routes(config = {}) {
24
24
  component: () => import("./Index.vue")
25
25
  }),
26
26
 
27
+ route({
28
+ name: 'progress', path: prefix+'progress/:action', meta: { }, props:true,
29
+ component: () => import("./ShelterProgress.vue")
30
+ }),
31
+
27
32
  ...pagesRoutes,
28
33
 
29
34
  ...contentEditRoutes({ ...config }),
@@ -66,7 +71,7 @@ export function createRouter(app, config) {
66
71
  return { name: 'user:settings' }
67
72
  }
68
73
  }
69
- if(to && to.name == 'user:signIn' && from?.matched.find(m => m?.meta.saveForSignIn)) {
74
+ if(to && to.name === 'user:signIn' && from?.matched.find(m => m?.meta.saveForSignIn)) {
70
75
  console.log("SAVE FOR LOGIN", from.fullPath)
71
76
  localStorage.redirectAfterLogin = from.fullPath
72
77
  }
@@ -0,0 +1,39 @@
1
+ // front/vite.config.ts
2
+ import { defineConfig } from "file:///home/m8/IdeaProjects/live-change/node_modules/vite/dist/node/index.js";
3
+ import Pages from "file:///home/m8/IdeaProjects/live-change/node_modules/vite-plugin-pages/dist/index.mjs";
4
+ import baseViteConfig from "file:///home/m8/IdeaProjects/live-change/live-change-stack/frontend/frontend-base/vite-config.js";
5
+ var version = process.env.VERSION ?? "unknown";
6
+ var vite_config_default = defineConfig(async ({ command, mode }) => {
7
+ const baseConfig = await baseViteConfig({ command, mode });
8
+ return {
9
+ ...baseConfig,
10
+ define: {
11
+ ...baseConfig.define,
12
+ ENV_VERSION: JSON.stringify(version),
13
+ ENV_BRAND_NAME: JSON.stringify("Example"),
14
+ ENV_BRAND_DOMAIN: JSON.stringify("example.com")
15
+ },
16
+ plugins: [
17
+ ...baseConfig.plugins,
18
+ Pages({
19
+ dirs: [
20
+ // basic
21
+ { dir: "src/pages", baseRoute: "" }
22
+ // blog
23
+ // { dir: 'src/blog', baseRoute: 'blog' },
24
+ ],
25
+ extensions: ["vue", "md"]
26
+ })
27
+ ],
28
+ resolve: {
29
+ ...baseConfig.resolve,
30
+ alias: [
31
+ ...baseConfig.resolve.alias
32
+ ]
33
+ }
34
+ };
35
+ });
36
+ export {
37
+ vite_config_default as default
38
+ };
39
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZnJvbnQvdml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9tOC9JZGVhUHJvamVjdHMvbGl2ZS1jaGFuZ2UvbGl2ZS1jaGFuZ2Utc3RhY2svZnJvbnRlbmQvdGFzay1mcm9udGVuZC9mcm9udFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvbTgvSWRlYVByb2plY3RzL2xpdmUtY2hhbmdlL2xpdmUtY2hhbmdlLXN0YWNrL2Zyb250ZW5kL3Rhc2stZnJvbnRlbmQvZnJvbnQvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvbTgvSWRlYVByb2plY3RzL2xpdmUtY2hhbmdlL2xpdmUtY2hhbmdlLXN0YWNrL2Zyb250ZW5kL3Rhc2stZnJvbnRlbmQvZnJvbnQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xuaW1wb3J0IFBhZ2VzIGZyb20gJ3ZpdGUtcGx1Z2luLXBhZ2VzJ1xuXG5sZXQgdmVyc2lvbiA9IHByb2Nlc3MuZW52LlZFUlNJT04gPz8gJ3Vua25vd24nXG5cbi8vIEB0cy1pZ25vcmVcbmltcG9ydCBiYXNlVml0ZUNvbmZpZyBmcm9tICdAbGl2ZS1jaGFuZ2UvZnJvbnRlbmQtYmFzZS92aXRlLWNvbmZpZy5qcydcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKGFzeW5jICh7IGNvbW1hbmQsIG1vZGUgfSkgPT4ge1xuICBjb25zdCBiYXNlQ29uZmlnID0gKGF3YWl0IGJhc2VWaXRlQ29uZmlnKHsgY29tbWFuZCwgbW9kZSB9KSlcbiAgcmV0dXJuIHtcbiAgICAuLi5iYXNlQ29uZmlnLFxuXG4gICAgZGVmaW5lOiB7XG4gICAgICAuLi5iYXNlQ29uZmlnLmRlZmluZSxcbiAgICAgIEVOVl9WRVJTSU9OOiBKU09OLnN0cmluZ2lmeSh2ZXJzaW9uKSxcbiAgICAgIEVOVl9CUkFORF9OQU1FOiBKU09OLnN0cmluZ2lmeShcIkV4YW1wbGVcIiksXG4gICAgICBFTlZfQlJBTkRfRE9NQUlOOiBKU09OLnN0cmluZ2lmeShcImV4YW1wbGUuY29tXCIpLFxuICAgIH0sXG5cbiAgICBwbHVnaW5zOiBbXG4gICAgICAuLi5iYXNlQ29uZmlnLnBsdWdpbnMsXG4gICAgICBQYWdlcyh7XG4gICAgICAgIGRpcnM6IFtcbiAgICAgICAgICAvLyBiYXNpY1xuICAgICAgICAgIHsgZGlyOiAnc3JjL3BhZ2VzJywgYmFzZVJvdXRlOiAnJyB9LFxuICAgICAgICAgIC8vIGJsb2dcbiAgICAgICAgICAvLyB7IGRpcjogJ3NyYy9ibG9nJywgYmFzZVJvdXRlOiAnYmxvZycgfSxcbiAgICAgICAgXSxcbiAgICAgICAgZXh0ZW5zaW9uczogWyd2dWUnLCAnbWQnXSxcbiAgICAgIH0pLFxuICAgIF0sXG5cbiAgICByZXNvbHZlOiB7XG4gICAgICAuLi5iYXNlQ29uZmlnLnJlc29sdmUsXG4gICAgICBhbGlhczogW1xuICAgICAgICAuLi5iYXNlQ29uZmlnLnJlc29sdmUuYWxpYXMsXG4gICAgICBdXG4gICAgfVxuICB9XG59KVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFrYSxTQUFTLG9CQUFvQjtBQUMvYixPQUFPLFdBQVc7QUFLbEIsT0FBTyxvQkFBb0I7QUFIM0IsSUFBSSxVQUFVLFFBQVEsSUFBSSxXQUFXO0FBS3JDLElBQU8sc0JBQVEsYUFBYSxPQUFPLEVBQUUsU0FBUyxLQUFLLE1BQU07QUFDdkQsUUFBTSxhQUFjLE1BQU0sZUFBZSxFQUFFLFNBQVMsS0FBSyxDQUFDO0FBQzFELFNBQU87QUFBQSxJQUNMLEdBQUc7QUFBQSxJQUVILFFBQVE7QUFBQSxNQUNOLEdBQUcsV0FBVztBQUFBLE1BQ2QsYUFBYSxLQUFLLFVBQVUsT0FBTztBQUFBLE1BQ25DLGdCQUFnQixLQUFLLFVBQVUsU0FBUztBQUFBLE1BQ3hDLGtCQUFrQixLQUFLLFVBQVUsYUFBYTtBQUFBLElBQ2hEO0FBQUEsSUFFQSxTQUFTO0FBQUEsTUFDUCxHQUFHLFdBQVc7QUFBQSxNQUNkLE1BQU07QUFBQSxRQUNKLE1BQU07QUFBQTtBQUFBLFVBRUosRUFBRSxLQUFLLGFBQWEsV0FBVyxHQUFHO0FBQUE7QUFBQTtBQUFBLFFBR3BDO0FBQUEsUUFDQSxZQUFZLENBQUMsT0FBTyxJQUFJO0FBQUEsTUFDMUIsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUVBLFNBQVM7QUFBQSxNQUNQLEdBQUcsV0FBVztBQUFBLE1BQ2QsT0FBTztBQUFBLFFBQ0wsR0FBRyxXQUFXLFFBQVE7QUFBQSxNQUN4QjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
package/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ import Task from './front/src/components/Task.vue'
1
2
 
2
- export { }
3
+ export { Task }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/task-frontend",
3
- "version": "0.8.32",
3
+ "version": "0.8.33",
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",
@@ -34,42 +34,42 @@
34
34
  "dependencies": {
35
35
  "@codemirror/language": "6.10.1",
36
36
  "@dotenvx/dotenvx": "0.27.0",
37
- "@fortawesome/fontawesome-free": "^6.4.2",
38
- "@live-change/access-control-frontend": "^0.8.32",
39
- "@live-change/access-control-service": "^0.8.32",
40
- "@live-change/backup-service": "^0.8.32",
41
- "@live-change/blog-frontend": "^0.8.32",
42
- "@live-change/blog-service": "^0.8.32",
43
- "@live-change/cli": "^0.8.32",
44
- "@live-change/content-frontend": "^0.8.32",
45
- "@live-change/content-service": "^0.8.32",
46
- "@live-change/dao": "^0.8.32",
47
- "@live-change/dao-vue3": "^0.8.32",
48
- "@live-change/dao-websocket": "^0.8.32",
49
- "@live-change/db-client": "^0.8.32",
50
- "@live-change/email-service": "^0.8.32",
51
- "@live-change/framework": "^0.8.32",
52
- "@live-change/frontend-auto-form": "^0.8.32",
53
- "@live-change/frontend-base": "^0.8.32",
54
- "@live-change/geoip-service": "^0.8.32",
55
- "@live-change/image-frontend": "^0.8.32",
56
- "@live-change/locale-settings-service": "^0.8.32",
57
- "@live-change/password-authentication-service": "^0.8.32",
58
- "@live-change/prosemirror-service": "^0.8.32",
59
- "@live-change/secret-code-service": "^0.8.32",
60
- "@live-change/secret-link-service": "^0.8.32",
61
- "@live-change/session-service": "^0.8.32",
62
- "@live-change/task-service": "^0.8.32",
63
- "@live-change/upload-frontend": "^0.8.32",
64
- "@live-change/url-frontend": "^0.8.32",
65
- "@live-change/url-service": "^0.8.32",
66
- "@live-change/user-frontend": "^0.8.32",
67
- "@live-change/user-identification-service": "^0.8.32",
68
- "@live-change/user-service": "^0.8.32",
69
- "@live-change/vote-service": "^0.8.32",
70
- "@live-change/vue3-components": "^0.8.32",
71
- "@live-change/vue3-ssr": "^0.8.32",
72
- "@live-change/wysiwyg-frontend": "^0.8.32",
37
+ "@fortawesome/fontawesome-free": "^6.5.2",
38
+ "@live-change/access-control-frontend": "^0.8.33",
39
+ "@live-change/access-control-service": "^0.8.33",
40
+ "@live-change/backup-service": "^0.8.33",
41
+ "@live-change/blog-frontend": "^0.8.33",
42
+ "@live-change/blog-service": "^0.8.33",
43
+ "@live-change/cli": "^0.8.33",
44
+ "@live-change/content-frontend": "^0.8.33",
45
+ "@live-change/content-service": "^0.8.33",
46
+ "@live-change/dao": "^0.8.33",
47
+ "@live-change/dao-vue3": "^0.8.33",
48
+ "@live-change/dao-websocket": "^0.8.33",
49
+ "@live-change/db-client": "^0.8.33",
50
+ "@live-change/email-service": "^0.8.33",
51
+ "@live-change/framework": "^0.8.33",
52
+ "@live-change/frontend-auto-form": "^0.8.33",
53
+ "@live-change/frontend-base": "^0.8.33",
54
+ "@live-change/geoip-service": "^0.8.33",
55
+ "@live-change/image-frontend": "^0.8.33",
56
+ "@live-change/locale-settings-service": "^0.8.33",
57
+ "@live-change/password-authentication-service": "^0.8.33",
58
+ "@live-change/prosemirror-service": "^0.8.33",
59
+ "@live-change/secret-code-service": "^0.8.33",
60
+ "@live-change/secret-link-service": "^0.8.33",
61
+ "@live-change/session-service": "^0.8.33",
62
+ "@live-change/task-service": "^0.8.33",
63
+ "@live-change/upload-frontend": "^0.8.33",
64
+ "@live-change/url-frontend": "^0.8.33",
65
+ "@live-change/url-service": "^0.8.33",
66
+ "@live-change/user-frontend": "^0.8.33",
67
+ "@live-change/user-identification-service": "^0.8.33",
68
+ "@live-change/user-service": "^0.8.33",
69
+ "@live-change/vote-service": "^0.8.33",
70
+ "@live-change/vue3-components": "^0.8.33",
71
+ "@live-change/vue3-ssr": "^0.8.33",
72
+ "@live-change/wysiwyg-frontend": "^0.8.33",
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.32",
94
+ "@live-change/codeceptjs-helper": "^0.8.33",
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": "9ea7767670a99404794087726223064c45d798d3"
105
+ "gitHead": "98ff6f9c09e5fc1f408010df6cc8038eff571276"
106
106
  }
@@ -39,13 +39,20 @@ const getWood = task({
39
39
  }
40
40
  },
41
41
  async execute({ woodType }, { service, task }, emit) {
42
+ task.progress(0, 1, 'finding tree')
42
43
  await sleep(workDuration)
44
+ if(Math.random() < 0.1) {
45
+ throw "Getting wood failed"
46
+ }
47
+ task.progress(1, 2, 'cutting tree')
48
+ await sleep(workDuration)
49
+ task.progress(2, 2, 'done')
43
50
  return {
44
51
  type: 'Wood',
45
52
  woodType
46
53
  }
47
54
  }
48
- })
55
+ }, definition)
49
56
 
50
57
  const cutWood = task({
51
58
  name: 'cutWood',
@@ -72,12 +79,13 @@ const cutWood = task({
72
79
  },
73
80
  async execute({ wood }, { service, task }, emit) {
74
81
  await sleep(workDuration)
82
+ if(Math.random() < 0.1) throw "Wood cutting failed"
75
83
  return Array(4).fill(0).map(() => ({
76
84
  type: 'Plank',
77
85
  woodType: wood.woodType
78
86
  }))
79
87
  }
80
- })
88
+ }, definition)
81
89
 
82
90
  const makePlanks = task({
83
91
  name: 'makePlanks',
@@ -98,14 +106,119 @@ const makePlanks = task({
98
106
  }
99
107
  }
100
108
  },
101
- async execute({ type }, { service, task }, emit) {
102
- const wood = await workerQueue.add(task.run(getWood, { type }))
109
+ async execute({ woodType }, { service, task }, emit) {
110
+ task.progress(0, 4, 'getting wood')
111
+ const wood = await workerQueue.add(() => task.run(getWood, { woodType, to: task.id }))
112
+ task.progress(1, 4, 'waiting')
103
113
  await sleep(pauseDuration)
104
- const planks = await workerQueue.add(task.run(cutWood, { wood }))
114
+ task.progress(2, 4, 'cutting wood')
115
+ const planks = await workerQueue.add(() => task.run(cutWood, { wood, to: task.id }))
116
+ task.progress(3, 4, 'waiting')
105
117
  await sleep(pauseDuration)
118
+ task.progress(4, 4, 'done')
106
119
  return planks
107
120
  }
108
- })
121
+ }, definition)
122
+
123
+ const placePlank = task({
124
+ name: 'placePlank',
125
+ properties: {
126
+ plank: {
127
+ type: 'Plank'
128
+ },
129
+ to: {
130
+ type: String
131
+ },
132
+ index: {
133
+ type: Number
134
+ }
135
+ },
136
+ async execute({ plank, to, index }, { service, task }, emit) {
137
+ await sleep(workDuration)
138
+ return {
139
+ type: 'placedPlank',
140
+ plank, index
141
+ }
142
+ }
143
+ }, definition)
144
+
145
+ const buildWall = task({
146
+ name: 'buildWall',
147
+ properties: {
148
+ planks: {
149
+ type: Array,
150
+ of: {
151
+ type: 'Plank'
152
+ }
153
+ },
154
+ wallSize: {
155
+ type: Number
156
+ }
157
+ },
158
+ returns: {
159
+ type: 'Wall',
160
+ properties: {
161
+ size: {
162
+ type: Number
163
+ }
164
+ }
165
+ },
166
+ async execute({ planks, wallSize }, { service, task }, emit) {
167
+ task.progress(0, 2 + wallSize, 'planning')
168
+ await sleep(pauseDuration)
169
+ let plankCounter = 0
170
+ task.progress(1 + plankCounter, 2 + wallSize, 'building')
171
+ await Promise.all(planks.map((plank, index) => workerQueue.add(
172
+ async () => {
173
+ const result = await task.run(placePlank, { plank, to: task.id, index })
174
+ plankCounter ++
175
+ task.progress(1 + plankCounter, 2 + wallSize, 'building')
176
+ return result
177
+ }
178
+ )))
179
+ task.progress(1 + plankCounter, 2 + wallSize, 'waiting')
180
+ await sleep(pauseDuration)
181
+ task.progress(2 + plankCounter, 2 + wallSize, 'done')
182
+ return {
183
+ type: 'Wall',
184
+ size: wallSize
185
+ }
186
+ }
187
+ }, definition)
188
+
189
+ const buildRoof = task({
190
+ name: 'buildRoof',
191
+ properties: {
192
+ planks: {
193
+ type: Array,
194
+ of: {
195
+ type: 'Plank'
196
+ }
197
+ },
198
+ roofSize: {
199
+ type: Number
200
+ }
201
+ },
202
+ returns: {
203
+ type: 'Roof',
204
+ properties: {
205
+ size: {
206
+ type: Number
207
+ }
208
+ }
209
+ },
210
+ async execute({ planks, roofSize }, { service, task }, emit) {
211
+ await sleep(pauseDuration)
212
+ await Promise.all(planks.map((plank, index) => workerQueue.add(
213
+ () => task.run(placePlank, { plank, to: task.id, index })
214
+ )))
215
+ await sleep(pauseDuration)
216
+ return {
217
+ type: 'Roof',
218
+ size: roofSize
219
+ }
220
+ }
221
+ }, definition)
109
222
 
110
223
  const buildShelter = task({
111
224
  name: "buildShelter",
@@ -147,51 +260,58 @@ const buildShelter = task({
147
260
  // compute roof size
148
261
  const roofSize = width * length
149
262
  // compute total plank blocks amount
150
- const howManyPlanks = wall1Size * 2 + wall2Size * 2 + roof
263
+ const howManyPlanks = wall1Size * 2 + wall2Size * 2 + roofSize
151
264
 
152
265
  let planksCounter = 0
153
- task.progress(planksCounter, howManyPlanks)
266
+ task.progress(planksCounter, howManyPlanks * 2, 'gathering materials')
154
267
  // gather planks
155
268
  const planks = await Promise.all( // do planks in parallel
156
269
  Array(howManyPlanks / 4)
157
270
  .fill(0)
158
271
  .map(
159
- () => workerQueue.add(async () => {
160
- const planks = await task.run(makePlanks, { woodType })
272
+ async (v, index) => {
273
+ const planks = await task.run(makePlanks, { woodType, to: task.id, index })
161
274
  planksCounter += 4
162
- task.progress(planksCounter, howManyPlanks)
275
+ await task.progress(planksCounter, howManyPlanks * 2)
163
276
  return planks
164
- })
277
+ }
165
278
  )
166
279
  )
167
280
 
281
+ task.progress(planksCounter, howManyPlanks * 2, 'waiting')
168
282
  await sleep(pauseDuration)
283
+ task.progress(planksCounter, howManyPlanks * 2, 'building walls')
169
284
 
170
- let placedPlanks = 0
171
285
  // build walls
172
286
  const walls = await Promise.all( // do walls in parallel
173
- [wall1, wall2, wall1, wall2].map(
287
+ [wall1Size, wall2Size, wall1Size, wall2Size].map(
174
288
  async (wallSize) => {
175
- const wall = await workerQueue.add(task.run(buildWall, { planks, wallSize }))
176
- placedPlanks += wallSize
177
- task.progress(planksCounter, howManyPlanks)
289
+ const wall = await task.run(buildWall, { planks, wallSize })
290
+ planksCounter += wallSize
291
+ await task.progress(planksCounter, howManyPlanks * 2)
178
292
  return wall
179
293
  }
180
294
  )
181
295
  )
182
-
296
+
297
+ task.progress(planksCounter, howManyPlanks * 2, 'waiting')
183
298
  await sleep(pauseDuration)
299
+ task.progress(planksCounter, howManyPlanks * 2, 'building roof')
184
300
 
185
301
  // build roof
186
- const roof = await workerQueue.add(
187
- async () => {
188
- const roof = await task.run(buildRoof, { planks })
189
- placedPlanks += roofSize
302
+ const roof =
303
+ await (async () => {
304
+ const roof = await task.run(buildRoof, { planks, roofSize })
305
+ planksCounter += roofSize
306
+ await task.progress(planksCounter, howManyPlanks * 2)
190
307
  return roof
191
- }
192
- )
193
-
308
+ })()
309
+
310
+ console.log("ROOF", roof)
311
+
312
+ task.progress(planksCounter, howManyPlanks * 2, 'waiting')
194
313
  await sleep(pauseDuration)
314
+ task.progress(planksCounter, howManyPlanks * 2, 'done')
195
315
 
196
316
  return {
197
317
  type: 'Shelter',
@@ -199,7 +319,7 @@ const buildShelter = task({
199
319
  roof
200
320
  }
201
321
  }
202
- })
322
+ }, definition)
203
323
 
204
324
  definition.action({
205
325
  name: "buildShelter",
@@ -235,8 +355,7 @@ definition.action({
235
355
  }
236
356
  },
237
357
  async execute({ size, woodType, place }, { service, client, command }, emit) {
238
- await buildShelter.start({ size, woodType, place }, 'userAction', command.id)
239
-
358
+ return await buildShelter.start({ size, woodType, place }, 'userAction', command.id)
240
359
  }
241
360
  })
242
361
 
@@ -271,7 +390,6 @@ const Shelter = definition.model({
271
390
 
272
391
  definition.trigger({
273
392
  name: 'taskBuildShelterDone',
274
- }, {
275
393
  properties: {
276
394
  shelter: {
277
395
  type: 'Shelter'
@@ -284,5 +402,21 @@ definition.trigger({
284
402
  }
285
403
  })
286
404
 
405
+ definition.view({
406
+ name: 'shelters',
407
+ properties: {
408
+ ...App.rangeProperties
409
+ },
410
+ returns: {
411
+ type: Array,
412
+ of: {
413
+ type: 'Shelter'
414
+ }
415
+ },
416
+ async daoPath(range) {
417
+ return Shelter.rangePath(range)
418
+ }
419
+ })
420
+
287
421
 
288
422
  export default definition