@live-change/task-frontend 0.9.85 → 0.9.87

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.
@@ -22,5 +22,9 @@ export const datetimeFormats = {
22
22
  "long": {
23
23
  "year": "numeric", "month": "short", "day": "numeric",
24
24
  "weekday": "short", "hour": "numeric", "minute": "numeric"
25
+ },
26
+ "longWithSeconds": {
27
+ "year": "numeric", "month": "short", "day": "numeric",
28
+ "weekday": "short", "hour": "numeric", "minute": "numeric", "second": "numeric"
25
29
  }
26
30
  }
@@ -1,28 +1,27 @@
1
1
  <template>
2
2
  <div>
3
- <div class="text-lg flex flex-row justify-between flex-wrap" :class="taskColor">
3
+ <div class="text-lg flex flex-row justify-between flex-wrap items-center" :class="taskColor">
4
4
  <div class="flex flex-row items-center mr-4">
5
5
  <i :class="['pi', icon, taskColor]" style="font-size: 1rem" />
6
6
  <div :class="['ml-2']">{{ label }}</div>
7
7
  </div>
8
- <div v-if="task?.progress && task?.state !== 'done'" class="w-32 mr-4 grow" style="max-width: 50vw">
8
+ <div v-if="taskData?.progress && taskData?.state !== 'done'" class="w-32 mr-4 grow" style="max-width: 50vw">
9
9
  <ProgressBar :value="Math.floor((100 * taskData.progress.current / taskData.progress.total))" />
10
10
  </div>
11
- <div v-if="task?.retries?.length && taskData.retries.length < taskData.maxRetries" class="mr-4">
11
+ <div v-if="taskData?.retries?.length && taskData.retries.length < taskData.maxRetries" class="mr-4">
12
12
  <i class="pi pi-replay" />
13
13
  {{ taskData.retries.length }} / {{ taskData.maxRetries }}
14
14
  </div>
15
- <div>{{ task?.state !== 'done' ? (task?.progress?.action || task?.state) : 'done' }}</div>
15
+ <div>{{ taskData?.state !== 'done' ? (taskData?.progress?.action || taskData?.state) : 'done' }}</div>
16
16
  </div>
17
- <div v-for="retry in task?.retries" class="ml-6 flex flex-row justify-between text-red-800">
17
+ <div v-for="retry in taskData?.retries" class="ml-6 flex flex-row justify-between text-red-800">
18
18
  {{ retry.error }} at {{ d(retry.failedAt, 'shortestTime')}}
19
19
  </div>
20
- <!-- <pre>{{ taskData.progress }}</pre>-->
21
20
  <div v-if="taskResultComponent && taskData.result" class="m-2">
22
- <component :is="taskResultComponent" :task="task" :result="taskData.result" :taskType="taskType" />
21
+ <component :is="taskResultComponent" :task="taskData" :result="taskData.result" :taskType="taskType" />
23
22
  </div>
24
23
  <div class="ml-6">
25
- <Task v-for="task in childTasks" :key="taskData.id" :task="task" :tasks="allTasks" :taskTypes="taskTypes" />
24
+ <Task v-for="task in childTasks" :key="taskId" :task="task" :tasks="allTasks" :taskTypes="taskTypes" />
26
25
  </div>
27
26
  </div>
28
27
  </template>
@@ -70,7 +69,11 @@
70
69
 
71
70
  const allTasks = computed(() => tasks.value || loadedTasks.value)
72
71
 
73
- const taskData = computed(() => allTasks.value && allTasks.value.find(m => (m.to ?? m.id) === taskId.value))
72
+ const taskData = computed(() =>
73
+ typeof task.value === 'object'
74
+ ? task.value
75
+ : (allTasks.value && allTasks.value.find(m => (m.to ?? m.id) === taskId.value))
76
+ )
74
77
 
75
78
  const taskType = computed(() => taskTypes.value[taskData.value?.type || taskData.value?.name] || {})
76
79
 
@@ -105,6 +108,7 @@
105
108
 
106
109
  const taskColor = computed(() => {
107
110
  console.log("TD", taskData.value, "AT", allTasks.value)
111
+ console.trace('taskColor', taskData.value)
108
112
  switch(taskData.value?.state) {
109
113
  case 'failed': return 'text-red-600'
110
114
  default: {}
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <div class="bg-surface-0 dark:bg-surface-900 px-3 py-1 shadow">
3
+ <div class="flex flex-row justify-between items-center" v-if="taskData">
4
+ <div class="flex flex-row items-center">
5
+ <i :class="['pi', icon, taskColor]" style="font-size: 1rem" />
6
+ <div class="ml-2">{{ taskData.name }}</div>
7
+ <div v-if="taskData.state === 'failed'" class="ml-2 text-red-600 dark:text-red-400">
8
+ {{ taskData.retries[taskData.retries.length - 1]?.error }}
9
+ </div>
10
+ </div>
11
+ <div class="flex flex-row items-center gap-4">
12
+ <div v-if="taskData.retries?.length" >
13
+ <i class="pi pi-replay" />
14
+ {{ taskData.retries.length }} / {{ taskData.maxRetries }}
15
+ </div>
16
+ <time :datetime="taskData.createdAt">
17
+ {{ d(locale.localTime(new Date(taskData.createdAt)), 'shortTime') }}
18
+ </time>
19
+ <Button
20
+ :icon="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
21
+ @click="isExpanded = !isExpanded"
22
+ text
23
+ rounded
24
+ />
25
+ </div>
26
+ </div>
27
+
28
+ <div v-if="isExpanded">
29
+ <TaskAdminDetails :task="task" :tasks="tasks" :taskTypes="taskTypes" />
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup>
35
+ import { ref, computed } from 'vue'
36
+ import Button from 'primevue/button'
37
+ import TaskAdminDetails from './TaskAdminDetails.vue'
38
+
39
+ import { useLocale } from "@live-change/vue3-components"
40
+ const locale = useLocale()
41
+
42
+ import { useI18n } from 'vue-i18n'
43
+ const { d } = useI18n()
44
+
45
+ const props = defineProps({
46
+ task: {
47
+ type: Object,
48
+ required: true
49
+ },
50
+ tasks: {
51
+ type: Array,
52
+ default: () => []
53
+ },
54
+ taskTypes: {
55
+ type: Object,
56
+ default: () => ({})
57
+ }
58
+ })
59
+
60
+ const taskId = computed(() => props.task?.to || props.task?.id || props.task)
61
+
62
+ const taskData = computed(() => props.tasks.find(t => t.to === taskId.value || t.id === taskId.value))
63
+
64
+ const isExpanded = ref(false)
65
+
66
+ const icon = computed(() => {
67
+ switch(props.task?.state) {
68
+ case 'created': return 'pi-sparkles'
69
+ case 'waiting': return 'pi-hourglass pi-spin'
70
+ case 'running': return 'pi-play'
71
+ case 'working': return 'pi-spin pi-spinner'
72
+ case 'done': return 'pi-check'
73
+ case 'failed': return 'pi-exclamation-triangle'
74
+ case 'retrying': return 'pi-replay'
75
+ default: return 'pi-question'
76
+ }
77
+ })
78
+
79
+ const taskColor = computed(() => {
80
+ switch(props.task?.state) {
81
+ case 'failed': return 'text-red-600'
82
+ default: return ''
83
+ }
84
+ })
85
+ </script>
@@ -0,0 +1,171 @@
1
+ <template>
2
+ <div class="mt-2">
3
+ <div v-if="taskData.progress" class="mb-2">
4
+ <ProgressBar :value="Math.floor((100 * taskData.progress.current / taskData.progress.total))" />
5
+ <div class="flex flex-row items-center justify-between">
6
+ <div class="text-sm text-gray-600 dark:text-gray-400">{{ taskData.progress.action }}</div>
7
+ <div class="text-sm text-gray-600 dark:text-gray-400">{{ taskData.progress.current }} / {{ taskData.progress.total }}</div>
8
+ </div>
9
+ </div>
10
+
11
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-2 text-sm">
12
+ <div class="grid grid-cols-2 gap-2 text-sm">
13
+ <div>ID:</div>
14
+ <div>{{ taskData.id }}</div>
15
+ </div>
16
+
17
+ <div class="grid grid-cols-2 gap-2 text-sm">
18
+ <div>State:</div>
19
+ <div>{{ taskData.state }}</div>
20
+ </div>
21
+
22
+ <div class="grid grid-cols-2 gap-2 text-sm">
23
+ <div>Created:</div>
24
+ <div>{{ d(taskData.createdAt, 'longWithSeconds') }}</div>
25
+ </div>
26
+
27
+ <div class="grid grid-cols-2 gap-2 text-sm">
28
+ <div>Started:</div>
29
+ <div>{{ d(taskData.startedAt, 'longWithSeconds') }}</div>
30
+ </div>
31
+
32
+ <div class="grid grid-cols-2 gap-2 text-sm" v-if="taskData.doneAt">
33
+ <div>Duration:</div>
34
+ <div>
35
+ {{ (new Date(taskData.doneAt).getTime() - new Date(taskData.startedAt).getTime()) / 1000 }}s
36
+ </div>
37
+ </div>
38
+
39
+ <div class="grid grid-cols-2 gap-2 text-sm" v-if="taskData.doneAt">
40
+ <div v-if="taskData.doneAt">Done:</div>
41
+ <div v-if="taskData.doneAt">{{ d(taskData.doneAt, 'longWithSeconds') }}</div>
42
+ </div>
43
+ </div>
44
+
45
+ <div v-if="taskData.properties" class="mt-2">
46
+ <div class="font-semibold">Properties:</div>
47
+ <div class="relative">
48
+ <pre
49
+ :class="[
50
+ 'text-sm bg-gray-100 dark:bg-gray-800 p-2 rounded overflow-x-auto whitespace-pre',
51
+ !isPropertiesExpanded && 'overflow-y-hidden'
52
+ ]"
53
+ >{{ JSON.stringify(taskData.properties, null, 2).split('\n')
54
+ .slice(0, !isPropertiesExpanded ? 5 : undefined).join('\n') }}</pre>
55
+
56
+ <div v-if="!isPropertiesExpanded && hasPropertiesOverflow" class="absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-gray-100 dark:from-gray-800 to-transparent" />
57
+ </div>
58
+ <div
59
+ v-if="hasPropertiesOverflow"
60
+ class="mt-1 flex items-center ml-3"
61
+ @click="expandProperties"
62
+ >
63
+ <span class="text-sm text-slate-600 dark:text-slate-400 hover:text-slate-800 dark:hover:text-slate-200 cursor-pointer">
64
+ {{ isPropertiesExpanded ? 'show less' : 'show more' }}
65
+ </span>
66
+ <i :class="['pi', isPropertiesExpanded ? 'pi-chevron-up' : 'pi-chevron-down', 'text-sm cursor-pointer ml-2']" />
67
+ </div>
68
+ </div>
69
+
70
+ <div v-if="taskData.retries?.length" class="mt-2">
71
+ <div class="font-semibold">Retries:</div>
72
+ <TaskRetry
73
+ v-for="(retry, index) in taskData.retries"
74
+ :key="index"
75
+ :retry="retry"
76
+ :index="index"
77
+ />
78
+ </div>
79
+
80
+ <div v-if="taskData.result" class="mt-2">
81
+ <div class="font-semibold">Result:</div>
82
+ <div class="relative">
83
+ <pre
84
+ :class="[
85
+ 'text-sm bg-gray-100 dark:bg-gray-800 p-2 rounded overflow-x-auto whitespace-pre',
86
+ !isResultExpanded && 'overflow-y-hidden'
87
+ ]"
88
+ >{{ JSON.stringify(taskData.result, null, 2).split('\n')
89
+ .slice(0, !isResultExpanded ? 5 : undefined).join('\n') }}</pre>
90
+
91
+ <div v-if="!isResultExpanded && hasOverflow" class="absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-gray-100 dark:from-gray-800 to-transparent" />
92
+
93
+ </div>
94
+ <div
95
+ v-if="hasOverflow"
96
+ class="mt-1 flex items-center ml-3"
97
+ @click="expandResult"
98
+ >
99
+ <span class="text-sm text-slate-600 dark:text-slate-400 hover:text-slate-800 dark:hover:text-slate-200 cursor-pointer">
100
+ {{ isResultExpanded ? 'show less' : 'show more' }}
101
+ </span>
102
+ <i :class="['pi', isResultExpanded ? 'pi-chevron-up' : 'pi-chevron-down', 'text-sm cursor-pointer ml-2']" />
103
+ </div>
104
+ </div>
105
+
106
+ <div v-if="childTasks.length" class="mt-2">
107
+ <div class="font-semibold">Subtasks:</div>
108
+ <div v-for="subtask in childTasks" :key="subtask.id" class="mt-2">
109
+ <TaskAdminCard :task="subtask" :tasks="tasks" :taskTypes="taskTypes" />
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </template>
114
+
115
+ <script setup>
116
+ import { ref, computed } from 'vue'
117
+ import ProgressBar from 'primevue/progressbar'
118
+ import TaskAdminCard from './TaskAdminCard.vue'
119
+ import TaskRetry from './TaskRetry.vue'
120
+
121
+ import { useI18n } from 'vue-i18n'
122
+ const { d } = useI18n()
123
+
124
+ const props = defineProps({
125
+ task: {
126
+ type: Object,
127
+ required: true
128
+ },
129
+ tasks: {
130
+ type: Array,
131
+ default: () => []
132
+ },
133
+ taskTypes: {
134
+ type: Object,
135
+ default: () => ({})
136
+ }
137
+ })
138
+
139
+ const taskId = computed(() => props.task?.to || props.task?.id || props.task)
140
+
141
+ const taskData = computed(() => props.tasks.find(t => t.to === taskId.value || t.id === taskId.value))
142
+
143
+ const childTasks = computed(() => {
144
+ return props.tasks.filter(t => t.causeType === "task_Task" && t.cause === taskId.value)
145
+ })
146
+
147
+ const isResultExpanded = ref(false)
148
+ const isPropertiesExpanded = ref(false)
149
+
150
+ const hasOverflow = computed(() => {
151
+ if (!taskData.value?.result) return false
152
+ const jsonString = JSON.stringify(taskData.value.result, null, 2)
153
+ const lineCount = (jsonString.match(/\n/g) || []).length
154
+ return lineCount > 4
155
+ })
156
+
157
+ const hasPropertiesOverflow = computed(() => {
158
+ if (!taskData.value?.properties) return false
159
+ const jsonString = JSON.stringify(taskData.value.properties, null, 2)
160
+ const lineCount = (jsonString.match(/\n/g) || []).length
161
+ return lineCount > 4
162
+ })
163
+
164
+ const expandResult = () => {
165
+ isResultExpanded.value = !isResultExpanded.value
166
+ }
167
+
168
+ const expandProperties = () => {
169
+ isPropertiesExpanded.value = !isPropertiesExpanded.value
170
+ }
171
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <div class="mt-0 ml-4">
3
+ <div class="flex flex-row items-center">
4
+ <div class="text-red-600 dark:text-red-400">
5
+ {{ index + 1 }}. {{ retry.error }}
6
+ <span class="text-gray-600 dark:text-gray-400">at {{ d(retry.failedAt, 'shortestTime') }}</span>
7
+ </div>
8
+ <i
9
+ v-if="retry.stack"
10
+ :class="['pi', isExpanded ? 'pi-chevron-up' : 'pi-chevron-down', 'text-sm cursor-pointer ml-2']"
11
+ @click="isExpanded = !isExpanded"
12
+ />
13
+ </div>
14
+ <pre v-if="retry.stack && isExpanded" class="text-xs text-red-800 dark:text-red-300 bg-red-50 dark:bg-red-900/30 p-2 rounded mt-1 overflow-x-auto whitespace-pre">{{ retry.stack }}</pre>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup>
19
+ import { ref } from 'vue'
20
+ import { useI18n } from 'vue-i18n'
21
+
22
+ const { d } = useI18n()
23
+
24
+ const props = defineProps({
25
+ retry: {
26
+ type: Object,
27
+ required: true
28
+ },
29
+ index: {
30
+ type: Number,
31
+ required: true
32
+ }
33
+ })
34
+
35
+ const isExpanded = ref(false)
36
+ </script>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div class="w-full">
3
+ <div class="bg-surface-0 dark:bg-surface-900 p-3 shadow mb-1">
4
+ <h2>Tasks</h2>
5
+ <!-- <pre>tasksNames = {{ tasksNames }}</pre>
6
+ <pre>taskStates = {{ taskStates }}</pre> -->
7
+ <div class="flex flex-wrap gap-3 mb-3">
8
+ <div class="flex-1">
9
+ <label for="task-name" class="block mb-2">Task Name</label>
10
+ <Select id="task-name" v-model="name" :options="['any', ...tasksNames]"
11
+ placeholder="Select Task Name" class="w-full" />
12
+ </div>
13
+ <div class="flex-1">
14
+ <label for="task-state" class="block mb-2">Task State</label>
15
+ <Select id="task-state" v-model="state" :options="['any', ...taskStates.map(s => ({label: s, value: s}))]"
16
+ placeholder="Select Task State" class="w-full" />
17
+ </div>
18
+ </div>
19
+ </div>
20
+
21
+ <!-- <pre>tasksPathConfig = {{ tasksPathConfig }}</pre> -->
22
+
23
+ <range-viewer :pathFunction="tasksPathFunction" :key="JSON.stringify(tasksPathConfig)"
24
+ :canLoadTop="false" canDropBottom
25
+ loadBottomSensorSize="4000px" dropBottomSensorSize="3000px">
26
+ <template #empty>
27
+ <div class="bg-surface-0 p-3 shadow text-center text-gray-500 text-lg">
28
+ No tasks found...
29
+ </div>
30
+ </template>
31
+
32
+ <template #default="{ item: task }">
33
+ <TaskAdminCard :task="task" :tasks="task.subTasks" class="mt-1" />
34
+ </template>
35
+ </range-viewer>
36
+
37
+ </div>
38
+
39
+ </template>
40
+
41
+ <script setup>
42
+
43
+ import TaskAdminCard from '../components/TaskAdminCard.vue'
44
+
45
+ import Select from 'primevue/select'
46
+
47
+ import { ref, computed } from 'vue'
48
+ import { RangeViewer } from "@live-change/vue3-components"
49
+
50
+ import { inject } from 'vue'
51
+ const workingZone = inject('workingZone')
52
+
53
+ import { usePath, live, useClient, useActions, reverseRange, useApi } from '@live-change/vue3-ssr'
54
+ const path = usePath()
55
+ const client = useClient()
56
+ const actions = useActions()
57
+ const api = useApi()
58
+
59
+ const taskDefinition = computed(() => api.getServiceDefinition('task').models.Task)
60
+ const taskStates = computed(() => taskDefinition.value?.properties?.state?.enum)
61
+
62
+
63
+ const state = ref('any')
64
+ const name = ref('any')
65
+
66
+ const tasksPathConfig = computed(() => {
67
+ return {
68
+ name: name.value === 'any' ? undefined : name.value,
69
+ state: state.value === 'any' ? undefined : state.value
70
+ }
71
+ })
72
+
73
+ const tasksPathFunction = computed(() => (range) =>
74
+ path.task.independentTasks({ ...tasksPathConfig.value, ...reverseRange(range) })
75
+ .with(task => path.task.tasksByRoot({
76
+ rootType: 'task_Task',
77
+ root: task.id//{ or: [task.to, task.id]}
78
+ }).bind('subTasks'))
79
+
80
+ )
81
+
82
+ const tasksNamesPath = path.task.taskNames({})
83
+
84
+ console.log("TASKS NAMES PATH", tasksNamesPath)
85
+
86
+ const [tasksNamesData] = await Promise.all([
87
+ live(tasksNamesPath)
88
+ ])
89
+ const tasksNames = computed(() => tasksNamesData.value.map(task => task.id))
90
+
91
+ console.log("TASKS NAMES", tasksNames)
92
+
93
+ </script>
@@ -1,3 +1,17 @@
1
+ export function taskAdminRoutes(config = {}) {
2
+ const { prefix = '/', route = (r) => r } = config
3
+ return [
4
+
5
+ route({
6
+ name: 'task:admin', path: prefix, meta: { },
7
+ component: () => import("./pages/TaskAdmin.vue"),
8
+ props: true
9
+ }),
10
+
11
+ ]
12
+ }
13
+
14
+
1
15
  import {
2
16
  createMemoryHistory,
3
17
  createRouter as _createRouter,
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import Task from './front/src/components/Task.vue'
2
2
  import TaskModal from './front/src/components/TaskModal.vue'
3
+ import { taskAdminRoutes } from './front/src/router.js'
3
4
 
4
- export { Task, TaskModal }
5
+ export { Task, TaskModal, taskAdminRoutes }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/task-frontend",
3
- "version": "0.9.85",
3
+ "version": "0.9.87",
4
4
  "scripts": {
5
5
  "memDev": "tsx --inspect --expose-gc server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "tsx server/start.js localDev --enableSessions --initScript ./init.js --dbAccess",
@@ -37,41 +37,41 @@
37
37
  "@codemirror/language": "6.10.1",
38
38
  "@dotenvx/dotenvx": "0.27.0",
39
39
  "@fortawesome/fontawesome-free": "^6.7.2",
40
- "@live-change/access-control-frontend": "^0.9.85",
41
- "@live-change/access-control-service": "^0.9.85",
42
- "@live-change/backup-service": "^0.9.85",
43
- "@live-change/blog-frontend": "^0.9.85",
44
- "@live-change/blog-service": "^0.9.85",
45
- "@live-change/cli": "^0.9.85",
46
- "@live-change/content-frontend": "^0.9.85",
47
- "@live-change/content-service": "^0.9.85",
48
- "@live-change/dao": "^0.9.85",
49
- "@live-change/dao-vue3": "^0.9.85",
50
- "@live-change/dao-websocket": "^0.9.85",
51
- "@live-change/db-client": "^0.9.85",
52
- "@live-change/email-service": "^0.9.85",
53
- "@live-change/framework": "^0.9.85",
54
- "@live-change/frontend-auto-form": "^0.9.85",
55
- "@live-change/frontend-base": "^0.9.85",
56
- "@live-change/geoip-service": "^0.9.85",
57
- "@live-change/image-frontend": "^0.9.85",
58
- "@live-change/locale-settings-service": "^0.9.85",
59
- "@live-change/password-authentication-service": "^0.9.85",
60
- "@live-change/prosemirror-service": "^0.9.85",
61
- "@live-change/secret-code-service": "^0.9.85",
62
- "@live-change/secret-link-service": "^0.9.85",
63
- "@live-change/session-service": "^0.9.85",
64
- "@live-change/task-service": "^0.9.85",
65
- "@live-change/upload-frontend": "^0.9.85",
66
- "@live-change/url-frontend": "^0.9.85",
67
- "@live-change/url-service": "^0.9.85",
68
- "@live-change/user-frontend": "^0.9.85",
69
- "@live-change/user-identification-service": "^0.9.85",
70
- "@live-change/user-service": "^0.9.85",
71
- "@live-change/vote-service": "^0.9.85",
72
- "@live-change/vue3-components": "^0.9.85",
73
- "@live-change/vue3-ssr": "^0.9.85",
74
- "@live-change/wysiwyg-frontend": "^0.9.85",
40
+ "@live-change/access-control-frontend": "^0.9.87",
41
+ "@live-change/access-control-service": "^0.9.87",
42
+ "@live-change/backup-service": "^0.9.87",
43
+ "@live-change/blog-frontend": "^0.9.87",
44
+ "@live-change/blog-service": "^0.9.87",
45
+ "@live-change/cli": "^0.9.87",
46
+ "@live-change/content-frontend": "^0.9.87",
47
+ "@live-change/content-service": "^0.9.87",
48
+ "@live-change/dao": "^0.9.87",
49
+ "@live-change/dao-vue3": "^0.9.87",
50
+ "@live-change/dao-websocket": "^0.9.87",
51
+ "@live-change/db-client": "^0.9.87",
52
+ "@live-change/email-service": "^0.9.87",
53
+ "@live-change/framework": "^0.9.87",
54
+ "@live-change/frontend-auto-form": "^0.9.87",
55
+ "@live-change/frontend-base": "^0.9.87",
56
+ "@live-change/geoip-service": "^0.9.87",
57
+ "@live-change/image-frontend": "^0.9.87",
58
+ "@live-change/locale-settings-service": "^0.9.87",
59
+ "@live-change/password-authentication-service": "^0.9.87",
60
+ "@live-change/prosemirror-service": "^0.9.87",
61
+ "@live-change/secret-code-service": "^0.9.87",
62
+ "@live-change/secret-link-service": "^0.9.87",
63
+ "@live-change/session-service": "^0.9.87",
64
+ "@live-change/task-service": "^0.9.87",
65
+ "@live-change/upload-frontend": "^0.9.87",
66
+ "@live-change/url-frontend": "^0.9.87",
67
+ "@live-change/url-service": "^0.9.87",
68
+ "@live-change/user-frontend": "^0.9.87",
69
+ "@live-change/user-identification-service": "^0.9.87",
70
+ "@live-change/user-service": "^0.9.87",
71
+ "@live-change/vote-service": "^0.9.87",
72
+ "@live-change/vue3-components": "^0.9.87",
73
+ "@live-change/vue3-ssr": "^0.9.87",
74
+ "@live-change/wysiwyg-frontend": "^0.9.87",
75
75
  "@vueuse/core": "^12.3.0",
76
76
  "codeceptjs-assert": "^0.0.5",
77
77
  "compression": "^1.7.5",
@@ -90,10 +90,10 @@
90
90
  "vue": "^3.5.12",
91
91
  "vue-i18n": "^9.10.1",
92
92
  "vue-router": "^4.5.0",
93
- "vue3-scroll-border": "0.1.6"
93
+ "vue3-scroll-border": "0.1.7"
94
94
  },
95
95
  "devDependencies": {
96
- "@live-change/codeceptjs-helper": "^0.9.85",
96
+ "@live-change/codeceptjs-helper": "^0.9.87",
97
97
  "codeceptjs": "^3.6.10",
98
98
  "generate-password": "1.7.1",
99
99
  "playwright": "1.49.1",
@@ -104,5 +104,5 @@
104
104
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
105
105
  "license": "ISC",
106
106
  "description": "",
107
- "gitHead": "126afb0aad3ab6e03aa5742726f429c95c46783a"
107
+ "gitHead": "7a7694ad2801b7ffa16f347aed441ca5f81ab5fd"
108
108
  }