@live-change/task-frontend 0.9.159 → 0.9.162

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.
@@ -10,6 +10,23 @@
10
10
  "taskFailed": "Task failed",
11
11
  "taskDone": "Task done"
12
12
  },
13
+ "cron": {
14
+ "scheduledTasks": "Scheduled Tasks",
15
+ "taskType": "Task Type",
16
+ "schedules": "Schedules",
17
+ "intervals": "Intervals",
18
+ "createTask": "Create New Cron Task",
19
+ "createSchedule": "Create Schedule",
20
+ "createInterval": "Create Interval",
21
+ "description": "Description",
22
+ "minute": "Minute (0-59)",
23
+ "hour": "Hour (0-23)",
24
+ "day": "Day (1-31)",
25
+ "month": "Month (1-12)",
26
+ "taskToRun": "Task to Run",
27
+ "intervalMs": "Interval (ms)",
28
+ "waitMs": "Wait (ms)"
29
+ },
13
30
  "shelter": {
14
31
  "wall": "Wall",
15
32
  "roof": "Roof"
@@ -10,6 +10,23 @@
10
10
  "taskFailed": "Zadanie nie powiodło się",
11
11
  "taskDone": "Zadanie ukończone"
12
12
  },
13
+ "cron": {
14
+ "scheduledTasks": "Zaplanowane zadania",
15
+ "taskType": "Typ zadania",
16
+ "schedules": "Harmonogramy",
17
+ "intervals": "Interwały",
18
+ "createTask": "Utwórz nowe zadanie cron",
19
+ "createSchedule": "Utwórz harmonogram",
20
+ "createInterval": "Utwórz interwał",
21
+ "description": "Opis",
22
+ "minute": "Minuta (0-59)",
23
+ "hour": "Godzina (0-23)",
24
+ "day": "Dzień (1-31)",
25
+ "month": "Miesiąc (1-12)",
26
+ "taskToRun": "Zadanie do uruchomienia",
27
+ "intervalMs": "Interwał (ms)",
28
+ "waitMs": "Oczekiwanie (ms)"
29
+ },
13
30
  "shelter": {
14
31
  "wall": "Ściana",
15
32
  "roof": "Dach"
package/front/src/App.vue CHANGED
@@ -14,7 +14,16 @@
14
14
  const locale = useLocale()
15
15
  locale.captureLocale()
16
16
 
17
- import { ViewRoot, NavBar, UpdateBanner } from "@live-change/frontend-base"
17
+ import {
18
+ provideAutoViewComponents,
19
+ provideAutoInputConfiguration,
20
+ provideMetadataBasedAutoInputConfiguration,
21
+ } from "@live-change/frontend-auto-form"
22
+ provideAutoViewComponents()
23
+ provideAutoInputConfiguration()
24
+ provideMetadataBasedAutoInputConfiguration()
25
+
26
+ import { ViewRoot, UpdateBanner } from "@live-change/frontend-base"
18
27
 
19
28
  import { computed } from 'vue'
20
29
  import { useHead } from '@vueuse/head'
@@ -0,0 +1,119 @@
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="intervalData">
4
+ <div class="flex flex-row items-center">
5
+ <i class="pi pi-clock" style="font-size: 1rem" />
6
+ <div class="ml-2">{{ intervalData.description || intervalData.id }}</div>
7
+ </div>
8
+ <div class="flex flex-row items-center gap-4">
9
+ <div class="text-sm">
10
+ Every {{ formatInterval(intervalData.interval) }}
11
+ </div>
12
+ <Button
13
+ :icon="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
14
+ @click="isExpanded = !isExpanded"
15
+ text
16
+ rounded
17
+ />
18
+ </div>
19
+ </div>
20
+
21
+ <div v-if="isExpanded" class="mt-2 p-2 bg-surface-50 dark:bg-surface-800 rounded">
22
+ <div class="grid grid-cols-1 gap-2 text-sm">
23
+ <div><strong>Interval:</strong> {{ formatInterval(intervalData.interval) }} ({{ intervalData.interval }}ms)</div>
24
+ <div v-if="intervalData.wait"><strong>Wait:</strong> {{ formatInterval(intervalData.wait) }} ({{ intervalData.wait }}ms)</div>
25
+ </div>
26
+ <div v-if="intervalData.trigger" class="mt-2">
27
+ <strong>Trigger:</strong>
28
+ <div class="ml-2 text-sm">
29
+ <div><strong>Name:</strong> {{ intervalData.trigger.name }}</div>
30
+ <div><strong>Service:</strong> {{ intervalData.trigger.service || 'any' }}</div>
31
+ <div v-if="intervalData.trigger.properties">
32
+ <strong>Properties:</strong>
33
+ <pre class="text-xs bg-surface-100 dark:bg-surface-700 p-1 rounded mt-1">{{ JSON.stringify(intervalData.trigger.properties, null, 2) }}</pre>
34
+ </div>
35
+ </div>
36
+ </div>
37
+
38
+ <!-- RunState for this Interval -->
39
+ <div v-if="runStateData" class="mt-2">
40
+ <strong>Current Run State:</strong>
41
+ <div class="ml-2 text-sm p-2 bg-surface-100 dark:bg-surface-700 rounded">
42
+ <div class="flex items-center">
43
+ <i :class="['pi', runStateIcon, runStateColor]" style="font-size: 1rem" />
44
+ <span class="ml-2">{{ runStateData.state }}</span>
45
+ </div>
46
+ <div v-if="runStateData.tasks?.length" class="mt-1">
47
+ <i class="pi pi-list" />
48
+ {{ runStateData.tasks.length }} task{{ runStateData.tasks.length > 1 ? 's' : '' }}
49
+ </div>
50
+ <div v-if="runStateData.startedAt" class="mt-1">
51
+ <strong>Started At:</strong> {{ new Date(runStateData.startedAt).toLocaleString() }}
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </template>
58
+
59
+ <script setup>
60
+ import { ref, computed, watch } from 'vue'
61
+ import Button from 'primevue/button'
62
+ import { usePath, live } from '@live-change/vue3-ssr'
63
+
64
+ const props = defineProps({
65
+ interval: {
66
+ type: Object,
67
+ required: true
68
+ }
69
+ })
70
+
71
+ const intervalData = computed(() => props.interval)
72
+ const isExpanded = ref(false)
73
+ const runStateData = ref(null)
74
+ const path = usePath()
75
+
76
+ // Watch for interval changes and fetch run state
77
+ watch(() => props.interval?.id, async (newId) => {
78
+ if (newId) {
79
+ try {
80
+ // Get run state for this specific interval
81
+ const runStatePath = path.cron_RunState.to(['cron_Interval', newId])
82
+ runStateData.value = await live(runStatePath)
83
+ } catch (error) {
84
+ console.error('Error fetching run state:', error)
85
+ runStateData.value = null
86
+ }
87
+ }
88
+ }, { immediate: true })
89
+
90
+ function formatInterval(ms) {
91
+ if (!ms) return 'N/A'
92
+
93
+ const seconds = Math.floor(ms / 1000)
94
+ const minutes = Math.floor(seconds / 60)
95
+ const hours = Math.floor(minutes / 60)
96
+ const days = Math.floor(hours / 24)
97
+
98
+ if (days > 0) return `${days} day${days > 1 ? 's' : ''}`
99
+ if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''}`
100
+ if (minutes > 0) return `${minutes} minute${minutes > 1 ? 's' : ''}`
101
+ return `${seconds} second${seconds > 1 ? 's' : ''}`
102
+ }
103
+
104
+ const runStateIcon = computed(() => {
105
+ switch(runStateData.value?.state) {
106
+ case 'running': return 'pi-play'
107
+ case 'waiting': return 'pi-hourglass pi-spin'
108
+ default: return 'pi-question'
109
+ }
110
+ })
111
+
112
+ const runStateColor = computed(() => {
113
+ switch(runStateData.value?.state) {
114
+ case 'running': return 'text-blue-600'
115
+ case 'waiting': return 'text-orange-600'
116
+ default: return ''
117
+ }
118
+ })
119
+ </script>
@@ -0,0 +1,119 @@
1
+ <template>
2
+ <div class="bg-surface-0 dark:bg-surface-900 py-1 px-6 shadow flex items-center justify-content-between
3
+ relative md:sticky top-0 z-20"
4
+ style="min-height: 80px" key="navbar">
5
+
6
+ <router-link to="/" class="no-underline mr-0 lg:mr-12">
7
+ <div class="flex items-center text-2xl text-surface-800 dark:text-surface-50 font-medium">
8
+ <img src="/images/logo.svg" alt="Logo" class="w-12 mr-3">
9
+ <span class="hidden md:block">
10
+ Live
11
+ </span>
12
+ <span class="hidden md:block text-primary-400">
13
+ Change
14
+ </span>
15
+ <span class="hidden md:block ml-2">
16
+ App
17
+ </span>
18
+ </div>
19
+ </router-link>
20
+
21
+ <div class="align-items-center flex-grow-1 justify-content-between hidden lg:block lg:ml-6 absolute lg:static w-full
22
+ bg-surface-0 dark:bg-surface-900 left-0 top-1/1 z-1 shadow lg:shadow-none top-menu
23
+ dark:border-t-1 dark:border-surface-700 md:dark:border-t-0">
24
+ <ul class="list-none p-0 m-0 flex items-end lg:items-center select-none flex-col lg:flex-row justify-end">
25
+ <li class="w-1/1 lg:w-auto">
26
+ <router-link
27
+ :to="'/'" v-ripple
28
+ class="flex justify-end px-6 p-3 lg:px-3 lg:py-2 items-center
29
+ text-surface-600 hover:text-900 hover:bg-surface-100
30
+ dark:text-primary-400 dark:hover:text-primary-100 dark:hover:bg-surface-800
31
+ font-medium text-2xl md:text-xl border-round cursor-pointer transition-colors
32
+ transition-duration-150 p-ripple no-underline">
33
+ <!-- <i class="pi pi-home mr-2"></i>-->
34
+ <span>Home</span>
35
+ </router-link>
36
+ </li>
37
+ <li class="w-1/1 lg:w-auto">
38
+ <router-link
39
+ :to="'/_task'" v-ripple
40
+ class="flex justify-end px-6 p-3 lg:px-3 lg:py-2 items-center
41
+ text-surface-600 hover:text-900 hover:bg-surface-100
42
+ dark:text-primary-400 dark:hover:text-primary-100 dark:hover:bg-surface-800
43
+ font-medium text-2xl md:text-xl border-round cursor-pointer transition-colors
44
+ transition-duration-150 p-ripple no-underline">
45
+ <i class="pi pi-list mr-2"></i>
46
+ <span>Tasks</span>
47
+ </router-link>
48
+ </li>
49
+ <li class="w-1/1 lg:w-auto">
50
+ <router-link
51
+ :to="'/_task/cron'" v-ripple
52
+ class="flex justify-end px-6 p-3 lg:px-3 lg:py-2 items-center
53
+ text-surface-600 hover:text-900 hover:bg-surface-100
54
+ dark:text-primary-400 dark:hover:text-primary-100 dark:hover:bg-surface-800
55
+ font-medium text-2xl md:text-xl border-round cursor-pointer transition-colors
56
+ transition-duration-150 p-ripple no-underline">
57
+ <i class="pi pi-clock mr-2"></i>
58
+ <span>Cron</span>
59
+ </router-link>
60
+ </li>
61
+ <li v-if="!client.user" class="w-1/1 lg:w-auto">
62
+ <router-link
63
+ :to="{ name: 'user:signInEmail' }" v-ripple
64
+ class="flex justify-end px-6 p-3 lg:px-3 lg:py-2 align-items-center
65
+ text-surface-600 hover:text-900 hover:bg-surface-100
66
+ dark:text-primary-400 dark:hover:text-primary-100 dark:hover:bg-surface-800
67
+ font-medium text-2xl md:text-xl border-round cursor-pointer transition-colors
68
+ transition-duration-150 p-ripple no-underline">
69
+ <!-- <i class="pi pi-home mr-2"></i>-->
70
+ <span>Sign in</span>
71
+ </router-link>
72
+ </li>
73
+ <li v-if="!client.user" class="w-1/1 lg:w-auto">
74
+ <router-link
75
+ :to="{ name: 'user:signUpEmail' }" v-ripple
76
+ class="flex justify-end px-6 p-3 lg:px-3 lg:py-2 align-items-center
77
+ text-surface-600 hover:text-900 hover:bg-surface-100
78
+ dark:text-primary-400 dark:hover:text-primary-100 dark:hover:bg-surface-800
79
+ font-medium text-2xl md:text-xl border-round cursor-pointer transition-colors
80
+ transition-duration-150 p-ripple no-underline">
81
+ <!-- <i class="pi pi-home mr-2"></i>-->
82
+ <span>Sign up</span>
83
+ </router-link>
84
+ </li>
85
+ </ul>
86
+ </div>
87
+
88
+ <div class="flex grow"></div>
89
+
90
+ <NotificationsIcon v-if="client.user" />
91
+
92
+ <UserIcon v-if="client.user" />
93
+
94
+ <a v-ripple class="cursor-pointer flex items-center justify-content-center no-underline lg:hidden text-surface-700 dark:text-surface-100 p-ripple
95
+ ml-2 hover:bg-surface-100 dark:hover:bg-surface-700 p-2"
96
+ v-styleclass="{
97
+ selector: '.top-menu', enterFromClass: 'hidden', leaveToClass: 'hidden', hideOnOutsideClick: true
98
+ }">
99
+ <i class="pi pi-bars" style="font-size: 2.46rem;"></i>
100
+ </a>
101
+
102
+
103
+ </div>
104
+ </template>
105
+
106
+ <script setup>
107
+
108
+ import { NotificationsIcon } from "@live-change/user-frontend"
109
+
110
+ import { UserIcon } from "@live-change/user-frontend"
111
+ import { client as useClient, useApi } from '@live-change/vue3-ssr'
112
+ const client = useClient()
113
+
114
+
115
+ </script>
116
+
117
+ <style scoped>
118
+
119
+ </style>
@@ -0,0 +1,128 @@
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="scheduleData">
4
+ <div class="flex flex-row items-center">
5
+ <i class="pi pi-calendar" style="font-size: 1rem" />
6
+ <div class="ml-2">{{ scheduleData.description || scheduleData.id }}</div>
7
+ </div>
8
+ <div class="flex flex-row items-center gap-4">
9
+ <div class="text-sm">
10
+ {{ formatSchedule(scheduleData) }}
11
+ </div>
12
+ <Button
13
+ :icon="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
14
+ @click="isExpanded = !isExpanded"
15
+ text
16
+ rounded
17
+ />
18
+ </div>
19
+ </div>
20
+
21
+ <div v-if="isExpanded" class="mt-2 p-2 bg-surface-50 dark:bg-surface-800 rounded">
22
+ <div class="grid grid-cols-2 gap-2 text-sm">
23
+ <div><strong>Minute:</strong> {{ scheduleData.minute || '*' }}</div>
24
+ <div><strong>Hour:</strong> {{ scheduleData.hour || '*' }}</div>
25
+ <div><strong>Day:</strong> {{ scheduleData.day || '*' }}</div>
26
+ <div><strong>Day of Week:</strong> {{ scheduleData.dayOfWeek || '*' }}</div>
27
+ <div><strong>Month:</strong> {{ scheduleData.month || '*' }}</div>
28
+ </div>
29
+ <div v-if="scheduleData.trigger" class="mt-2">
30
+ <strong>Trigger:</strong>
31
+ <div class="ml-2 text-sm">
32
+ <div><strong>Name:</strong> {{ scheduleData.trigger.name }}</div>
33
+ <div><strong>Service:</strong> {{ scheduleData.trigger.service || 'any' }}</div>
34
+ <div v-if="scheduleData.trigger.properties">
35
+ <strong>Properties:</strong>
36
+ <pre class="text-xs bg-surface-100 dark:bg-surface-700 p-1 rounded mt-1">{{ JSON.stringify(scheduleData.trigger.properties, null, 2) }}</pre>
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <!-- RunState for this Schedule -->
42
+ <div v-if="runStateData" class="mt-2">
43
+ <strong>Current Run State:</strong>
44
+ <div class="ml-2 text-sm p-2 bg-surface-100 dark:bg-surface-700 rounded">
45
+ <div class="flex items-center">
46
+ <i :class="['pi', runStateIcon, runStateColor]" style="font-size: 1rem" />
47
+ <span class="ml-2">{{ runStateData.state }}</span>
48
+ </div>
49
+ <div v-if="runStateData.tasks?.length" class="mt-1">
50
+ <i class="pi pi-list" />
51
+ {{ runStateData.tasks.length }} task{{ runStateData.tasks.length > 1 ? 's' : '' }}
52
+ </div>
53
+ <div v-if="runStateData.startedAt" class="mt-1">
54
+ <strong>Started At:</strong> {{ new Date(runStateData.startedAt).toLocaleString() }}
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </template>
61
+
62
+ <script setup>
63
+ import { ref, computed, onMounted, watch } from 'vue'
64
+ import Button from 'primevue/button'
65
+ import { usePath, live } from '@live-change/vue3-ssr'
66
+
67
+ const props = defineProps({
68
+ schedule: {
69
+ type: Object,
70
+ required: true
71
+ }
72
+ })
73
+
74
+ const scheduleData = computed(() => props.schedule)
75
+ const isExpanded = ref(false)
76
+ const runStateData = ref(null)
77
+ const path = usePath()
78
+
79
+ // Watch for schedule changes and fetch run state
80
+ watch(() => props.schedule?.id, async (newId) => {
81
+ if (newId) {
82
+ try {
83
+ // Get the run state for this specific schedule
84
+ const runStatePath = path.cron_RunState.to(['cron_Schedule', newId])
85
+ runStateData.value = await live(runStatePath)
86
+ } catch (error) {
87
+ console.error('Error fetching run state:', error)
88
+ runStateData.value = null
89
+ }
90
+ }
91
+ }, { immediate: true })
92
+
93
+ function formatSchedule(schedule) {
94
+ const parts = []
95
+ if (schedule.minute !== undefined && schedule.minute !== null) parts.push(schedule.minute)
96
+ else parts.push('*')
97
+
98
+ if (schedule.hour !== undefined && schedule.hour !== null) parts.push(schedule.hour)
99
+ else parts.push('*')
100
+
101
+ if (schedule.day !== undefined && schedule.day !== null) parts.push(schedule.day)
102
+ else parts.push('*')
103
+
104
+ if (schedule.month !== undefined && schedule.month !== null) parts.push(schedule.month)
105
+ else parts.push('*')
106
+
107
+ if (schedule.dayOfWeek !== undefined && schedule.dayOfWeek !== null) parts.push(schedule.dayOfWeek)
108
+ else parts.push('*')
109
+
110
+ return parts.join(' ')
111
+ }
112
+
113
+ const runStateIcon = computed(() => {
114
+ switch(runStateData.value?.state) {
115
+ case 'running': return 'pi-play'
116
+ case 'waiting': return 'pi-hourglass pi-spin'
117
+ default: return 'pi-question'
118
+ }
119
+ })
120
+
121
+ const runStateColor = computed(() => {
122
+ switch(runStateData.value?.state) {
123
+ case 'running': return 'text-blue-600'
124
+ case 'waiting': return 'text-orange-600'
125
+ default: return ''
126
+ }
127
+ })
128
+ </script>
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <div class="w-full">
3
+
4
+ <ActionForm
5
+ service="cron"
6
+ action="setInterval"
7
+ :parameters="intervalParameters"
8
+ @done="handleActionDone" />
9
+
10
+
11
+ <div class="bg-surface-0 dark:bg-surface-900 p-3 shadow mb-1">
12
+ <h3>{{ t('cron.intervals') }}</h3>
13
+ <range-viewer :pathFunction="intervalsPathFunction" :key="JSON.stringify(intervalsPathConfig)"
14
+ :canLoadTop="false" :canDropBottom="false"
15
+ loadBottomSensorSize="3000px" dropBottomSensorSize="12000px">
16
+ <template #empty>
17
+ <div class="bg-surface-0 p-3 shadow text-center text-gray-500 text-lg">
18
+ No intervals found...
19
+ </div>
20
+ </template>
21
+
22
+ <template #default="{ item: interval }">
23
+ <IntervalCard :interval="interval" class="mt-1" />
24
+ </template>
25
+ </range-viewer>
26
+ </div>
27
+
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+
33
+ import ScheduleCard from '../components/ScheduleCard.vue'
34
+ import IntervalCard from '../components/IntervalCard.vue'
35
+ import Select from 'primevue/select'
36
+ import InputText from 'primevue/inputtext'
37
+ import InputNumber from 'primevue/inputnumber'
38
+ import Dropdown from 'primevue/dropdown'
39
+ import Button from 'primevue/button'
40
+
41
+
42
+ import { ActionForm } from '@live-change/frontend-auto-form'
43
+
44
+ import { useI18n } from 'vue-i18n'
45
+ const { t } = useI18n()
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 taskType = ref('all')
60
+
61
+ // Available test tasks
62
+ const taskOptions = ref([
63
+ { label: 'Build Shelter', value: 'buildShelter' },
64
+ { label: 'Get Wood', value: 'getWood' },
65
+ { label: 'Cut Wood', value: 'cutWood' },
66
+ { label: 'Make Planks', value: 'makePlanks' },
67
+ { label: 'Build Wall', value: 'buildWall' },
68
+ { label: 'Build Roof', value: 'buildRoof' }
69
+ ])
70
+
71
+ const schedulesPathFunction = computed(() => (range) =>
72
+ path.cron.schedules({ ...reverseRange(range) })
73
+ )
74
+
75
+ const intervalsPathFunction = computed(() => (range) =>
76
+ path.cron.intervals({ ...reverseRange(range) })
77
+ )
78
+
79
+ const services = computed(() => Object.keys(api.metadata.api.value.services))
80
+
81
+
82
+
83
+ </script>
@@ -12,9 +12,12 @@
12
12
  <script setup>
13
13
  import { ref, computed, defineProps } from 'vue'
14
14
  import { usePath, live } from '@live-change/vue3-ssr'
15
- import BuildShelterResult from './components/BuildShelterResult.vue'
16
- import MakePlanksResult from './components/MakePlanksResult.vue'
17
- import Task from './components/Task.vue'
15
+ import BuildShelterResult from '../components/BuildShelterResult.vue'
16
+ import MakePlanksResult from '../components/MakePlanksResult.vue'
17
+ import Task from '../components/Task.vue'
18
+
19
+ import { useI18n } from 'vue-i18n'
20
+ const { t } = useI18n()
18
21
 
19
22
  const props = defineProps({
20
23
  action: {
@@ -67,7 +70,7 @@
67
70
  }
68
71
 
69
72
  const tasksRoot = computed(() => ({
70
- rootType: 'userAction',
73
+ rootType: 'command',
71
74
  root: props.action
72
75
  }))
73
76
 
@@ -45,6 +45,9 @@
45
45
 
46
46
  import Select from 'primevue/select'
47
47
 
48
+ import { useI18n } from 'vue-i18n'
49
+ const { t } = useI18n()
50
+
48
51
  import { ref, computed } from 'vue'
49
52
  import { RangeViewer } from "@live-change/vue3-components"
50
53
 
@@ -60,7 +63,6 @@
60
63
  const taskDefinition = computed(() => api.getServiceDefinition('task').models.Task)
61
64
  const taskStates = computed(() => taskDefinition.value?.properties?.state?.enum)
62
65
 
63
-
64
66
  const state = ref('any')
65
67
  const name = ref('any')
66
68
 
@@ -7,10 +7,19 @@ export function taskAdminRoutes(config = {}) {
7
7
  component: () => import("./pages/TaskAdmin.vue"),
8
8
  props: true
9
9
  }),
10
-
11
10
  ]
12
11
  }
13
12
 
13
+ export function cronAdminRoutes(config = {}) {
14
+ const { prefix = '/', route = (r) => r } = config
15
+ return [
16
+ route({
17
+ name: 'cron:admin', path: prefix, meta: { },
18
+ component: () => import("./pages/CronAdmin.vue"),
19
+ props: true
20
+ }),
21
+ ]
22
+ }
14
23
 
15
24
  import {
16
25
  createMemoryHistory,
@@ -35,12 +44,12 @@ export function routes(config = {}) {
35
44
 
36
45
  route({
37
46
  name: 'index', path: prefix, meta: { },
38
- component: () => import("./Index.vue")
47
+ component: () => import("./pages/Index.vue")
39
48
  }),
40
49
 
41
50
  route({
42
51
  name: 'progress', path: prefix+'progress/:action', meta: { }, props:true,
43
- component: () => import("./ShelterProgress.vue")
52
+ component: () => import("./pages/ShelterProgress.vue")
44
53
  }),
45
54
 
46
55
  ...pagesRoutes,
@@ -48,6 +57,8 @@ export function routes(config = {}) {
48
57
  ...contentEditRoutes({ ...config }),
49
58
 
50
59
  ...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
60
+ ...taskAdminRoutes({ prefix: '/_task', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
61
+ ...cronAdminRoutes({ prefix: '/_cron', route: r => ({ ...r, meta: { ...r.meta, pageType: 'wide' }}) }),
51
62
  ...catchAllPagesRoute({ ...config }),
52
63
  ]
53
64
  }
@@ -40,6 +40,7 @@ export default defineConfig(async ({ command, mode }) => {
40
40
  resolve: {
41
41
  ...baseConfig.resolve,
42
42
  alias: [
43
+ { find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) },
43
44
  ...baseConfig.resolve.alias,
44
45
  ]
45
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/task-frontend",
3
- "version": "0.9.159",
3
+ "version": "0.9.162",
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,43 @@
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.159",
41
- "@live-change/access-control-service": "^0.9.159",
42
- "@live-change/backup-service": "^0.9.159",
43
- "@live-change/blog-frontend": "^0.9.159",
44
- "@live-change/blog-service": "^0.9.159",
45
- "@live-change/cli": "^0.9.159",
46
- "@live-change/content-frontend": "^0.9.159",
47
- "@live-change/content-service": "^0.9.159",
48
- "@live-change/dao": "^0.9.159",
49
- "@live-change/dao-vue3": "^0.9.159",
50
- "@live-change/dao-websocket": "^0.9.159",
51
- "@live-change/db-client": "^0.9.159",
52
- "@live-change/email-service": "^0.9.159",
53
- "@live-change/framework": "^0.9.159",
54
- "@live-change/frontend-auto-form": "^0.9.159",
55
- "@live-change/frontend-base": "^0.9.159",
56
- "@live-change/geoip-service": "^0.9.159",
57
- "@live-change/image-frontend": "^0.9.159",
58
- "@live-change/locale-settings-service": "^0.9.159",
59
- "@live-change/password-authentication-service": "^0.9.159",
60
- "@live-change/prosemirror-service": "^0.9.159",
61
- "@live-change/secret-code-service": "^0.9.159",
62
- "@live-change/secret-link-service": "^0.9.159",
63
- "@live-change/session-service": "^0.9.159",
64
- "@live-change/task-service": "^0.9.159",
65
- "@live-change/upload-frontend": "^0.9.159",
66
- "@live-change/url-frontend": "^0.9.159",
67
- "@live-change/url-service": "^0.9.159",
68
- "@live-change/user-frontend": "^0.9.159",
69
- "@live-change/user-identification-service": "^0.9.159",
70
- "@live-change/user-service": "^0.9.159",
71
- "@live-change/vote-service": "^0.9.159",
72
- "@live-change/vue3-components": "^0.9.159",
73
- "@live-change/vue3-ssr": "^0.9.159",
74
- "@live-change/wysiwyg-frontend": "^0.9.159",
40
+ "@live-change/access-control-frontend": "^0.9.162",
41
+ "@live-change/access-control-service": "^0.9.162",
42
+ "@live-change/backup-service": "^0.9.162",
43
+ "@live-change/blog-frontend": "^0.9.162",
44
+ "@live-change/blog-service": "^0.9.162",
45
+ "@live-change/cli": "^0.9.162",
46
+ "@live-change/content-frontend": "^0.9.162",
47
+ "@live-change/content-service": "^0.9.162",
48
+ "@live-change/cron-service": "^0.9.162",
49
+ "@live-change/dao": "^0.9.162",
50
+ "@live-change/dao-vue3": "^0.9.162",
51
+ "@live-change/dao-websocket": "^0.9.162",
52
+ "@live-change/db-client": "^0.9.162",
53
+ "@live-change/draft-service": "^0.9.162",
54
+ "@live-change/email-service": "^0.9.162",
55
+ "@live-change/framework": "^0.9.162",
56
+ "@live-change/frontend-auto-form": "^0.9.162",
57
+ "@live-change/frontend-base": "^0.9.162",
58
+ "@live-change/geoip-service": "^0.9.162",
59
+ "@live-change/image-frontend": "^0.9.162",
60
+ "@live-change/locale-settings-service": "^0.9.162",
61
+ "@live-change/password-authentication-service": "^0.9.162",
62
+ "@live-change/prosemirror-service": "^0.9.162",
63
+ "@live-change/secret-code-service": "^0.9.162",
64
+ "@live-change/secret-link-service": "^0.9.162",
65
+ "@live-change/session-service": "^0.9.162",
66
+ "@live-change/task-service": "^0.9.162",
67
+ "@live-change/upload-frontend": "^0.9.162",
68
+ "@live-change/url-frontend": "^0.9.162",
69
+ "@live-change/url-service": "^0.9.162",
70
+ "@live-change/user-frontend": "^0.9.162",
71
+ "@live-change/user-identification-service": "^0.9.162",
72
+ "@live-change/user-service": "^0.9.162",
73
+ "@live-change/vote-service": "^0.9.162",
74
+ "@live-change/vue3-components": "^0.9.162",
75
+ "@live-change/vue3-ssr": "^0.9.162",
76
+ "@live-change/wysiwyg-frontend": "^0.9.162",
75
77
  "@vueuse/core": "^12.3.0",
76
78
  "codeceptjs-assert": "^0.0.5",
77
79
  "compression": "^1.7.5",
@@ -93,7 +95,7 @@
93
95
  "vue3-scroll-border": "0.1.7"
94
96
  },
95
97
  "devDependencies": {
96
- "@live-change/codeceptjs-helper": "^0.9.159",
98
+ "@live-change/codeceptjs-helper": "^0.9.162",
97
99
  "codeceptjs": "^3.6.10",
98
100
  "generate-password": "1.7.1",
99
101
  "playwright": "1.49.1",
@@ -104,5 +106,5 @@
104
106
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
105
107
  "license": "ISC",
106
108
  "description": "",
107
- "gitHead": "8a605f68b81ff004da33e71667d2a7c75fe68ee4"
109
+ "gitHead": "59cd1485ca6d76bd87a6634a92d6e661e5803d5e"
108
110
  }
@@ -87,9 +87,15 @@ app.config = {
87
87
  {
88
88
  name: 'vote',
89
89
  },
90
+ {
91
+ name: 'draft',
92
+ },
90
93
  {
91
94
  name: 'task',
92
95
  },
96
+ {
97
+ name: 'cron',
98
+ },
93
99
  {
94
100
  name: 'backup',
95
101
  port: 8007
package/server/init.js CHANGED
@@ -7,4 +7,7 @@ export default async function(services) {
7
7
  const testUser = await createUser(services,
8
8
  'Test User', 'test@test.com', 'Testy123', 'u1', ['writer'])
9
9
 
10
+ const adminUser = await createUser(services,
11
+ 'Test Admin', 'admin@test.com', 'Testy123', 'u1', ['admin'])
12
+
10
13
  }
@@ -19,7 +19,9 @@ import content from '@live-change/content-service'
19
19
  import geoIp from '@live-change/geoip-service'
20
20
  import vote from '@live-change/vote-service'
21
21
  import backup from '@live-change/backup-service'
22
+ import draft from '@live-change/draft-service'
22
23
  import task from '@live-change/task-service'
24
+ import cron from '@live-change/cron-service'
23
25
  import init from './init.js'
24
26
 
25
27
  export {
@@ -44,7 +46,9 @@ export {
44
46
  geoIp,
45
47
  vote,
46
48
  backup,
49
+ draft,
47
50
  task,
51
+ cron,
48
52
  init
49
53
  }
50
54
 
@@ -355,7 +355,7 @@ definition.action({
355
355
  }
356
356
  },
357
357
  async execute({ size, woodType, place }, { service, client, command }, emit) {
358
- return await buildShelter.start({ size, woodType, place }, 'userAction', command.id)
358
+ return await buildShelter.start({ size, woodType, place }, 'command', command.id)
359
359
  }
360
360
  })
361
361
 
@@ -1,273 +0,0 @@
1
- {
2
- "version": "6.0",
3
- "nxVersion": "18.0.6",
4
- "deps": {
5
- "@codemirror/language": "6.10.1",
6
- "@dotenvx/dotenvx": "0.27.0",
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
- "@vueuse/core": "^10.9.0",
44
- "codeceptjs-assert": "^0.0.5",
45
- "compression": "^1.7.4",
46
- "cross-env": "^7.0.3",
47
- "get-port-sync": "1.0.1",
48
- "pica": "^9.0.1",
49
- "pretty-bytes": "^6.1.1",
50
- "primeflex": "^3.3.1",
51
- "primeicons": "^7.0.0",
52
- "primevue": "^3.51.0",
53
- "rollup-plugin-node-builtins": "^2.1.2",
54
- "rollup-plugin-visualizer": "5.12.0",
55
- "serialize-javascript": "^6.0.2",
56
- "serve-static": "^1.15.0",
57
- "v-shared-element": "3.1.1",
58
- "vue": "^3.4.19",
59
- "vue-i18n": "^9.10.1",
60
- "vue-router": "^4.2.5",
61
- "vue3-scroll-border": "0.1.6",
62
- "@live-change/codeceptjs-helper": "0.8.32",
63
- "codeceptjs": "^3.5.12",
64
- "generate-password": "1.7.1",
65
- "playwright": "^1.41.2",
66
- "random-profile-generator": "^2.3.0",
67
- "txtgen": "^3.0.6",
68
- "webdriverio": "^8.31.1"
69
- },
70
- "pathMappings": {},
71
- "nxJsonPlugins": [],
72
- "fileMap": {
73
- "projectFileMap": {},
74
- "nonProjectFiles": [
75
- {
76
- "file": ".gitignore",
77
- "hash": "16528976885761916170"
78
- },
79
- {
80
- "file": "Dockerfile",
81
- "hash": "2886431590462419165"
82
- },
83
- {
84
- "file": "LICENSE",
85
- "hash": "10221119794387200971"
86
- },
87
- {
88
- "file": "data/GeoLite2-Country.mmdb",
89
- "hash": "18418324532701607635"
90
- },
91
- {
92
- "file": "dev.Dockerfile",
93
- "hash": "6907505572289099967"
94
- },
95
- {
96
- "file": "docker/app.initd.sh",
97
- "hash": "5689466769238316025"
98
- },
99
- {
100
- "file": "docker/build-and-upload.sh",
101
- "hash": "9432915210479550333"
102
- },
103
- {
104
- "file": "docker/build-docker-and-upload.sh",
105
- "hash": "9817365185106032741"
106
- },
107
- {
108
- "file": "docker/commit-new-version.sh",
109
- "hash": "5160018103227051012"
110
- },
111
- {
112
- "file": "docker/k8s-rsync-helper.sh",
113
- "hash": "12840580596915123557"
114
- },
115
- {
116
- "file": "docker/onlyDependencies.js",
117
- "hash": "13135394580253028435"
118
- },
119
- {
120
- "file": "docker/parse-args-and-config.sh",
121
- "hash": "11641932740456140593"
122
- },
123
- {
124
- "file": "docker/restore-backup-with-service.sh",
125
- "hash": "10918919254951884109"
126
- },
127
- {
128
- "file": "docker/restore-backup.sh",
129
- "hash": "17157081294258412437"
130
- },
131
- {
132
- "file": "docker/start-service.sh",
133
- "hash": "13107251553503965386"
134
- },
135
- {
136
- "file": "docker/upload-backup-and-restore.sh",
137
- "hash": "16296194178343837935"
138
- },
139
- {
140
- "file": "front/index.html",
141
- "hash": "9934749794764720310"
142
- },
143
- {
144
- "file": "front/locales/en.js",
145
- "hash": "10652573724821059037"
146
- },
147
- {
148
- "file": "front/locales/en.json",
149
- "hash": "7756539891184290419"
150
- },
151
- {
152
- "file": "front/public/favicon.ico",
153
- "hash": "11176796980188620760"
154
- },
155
- {
156
- "file": "front/public/images/empty-photo.svg",
157
- "hash": "9393138513813369674"
158
- },
159
- {
160
- "file": "front/public/images/empty-user-photo.svg",
161
- "hash": "17548039285248668212"
162
- },
163
- {
164
- "file": "front/public/images/logo.svg",
165
- "hash": "5934164668360941413"
166
- },
167
- {
168
- "file": "front/public/images/logo128.png",
169
- "hash": "4924117807669085214"
170
- },
171
- {
172
- "file": "front/src/App.vue",
173
- "hash": "3737234980433726371"
174
- },
175
- {
176
- "file": "front/src/Index.vue",
177
- "hash": "15104691593361452519"
178
- },
179
- {
180
- "file": "front/src/ShelterProgress.vue",
181
- "hash": "10500323481502622407"
182
- },
183
- {
184
- "file": "front/src/analytics/index.js",
185
- "hash": "492811393913301668"
186
- },
187
- {
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"
198
- },
199
- {
200
- "file": "front/src/config.js",
201
- "hash": "4208481022464725661"
202
- },
203
- {
204
- "file": "front/src/entry-client.js",
205
- "hash": "1218837904372604167"
206
- },
207
- {
208
- "file": "front/src/entry-server.js",
209
- "hash": "7377383936979315921"
210
- },
211
- {
212
- "file": "front/src/router.js",
213
- "hash": "15530460209801505227"
214
- },
215
- {
216
- "file": "front/tsconfig.json",
217
- "hash": "6166366661637344199"
218
- },
219
- {
220
- "file": "front/tsconfig.node.json",
221
- "hash": "4208030242441905014"
222
- },
223
- {
224
- "file": "front/vite.config.ts",
225
- "hash": "4804285485121244435"
226
- },
227
- {
228
- "file": "front/vite.config.ts.timestamp-1717571300028-addad6453ee85.mjs",
229
- "hash": "17152765440974688639"
230
- },
231
- {
232
- "file": "index.js",
233
- "hash": "15558335606886518311"
234
- },
235
- {
236
- "file": "package.json",
237
- "hash": "17822390086587439626"
238
- },
239
- {
240
- "file": "server/app.config.js",
241
- "hash": "3863281573320850472"
242
- },
243
- {
244
- "file": "server/init.js",
245
- "hash": "10527942683746245757"
246
- },
247
- {
248
- "file": "server/page.documentType.js",
249
- "hash": "4319267302010918354"
250
- },
251
- {
252
- "file": "server/security.config.js",
253
- "hash": "6483730663450187822"
254
- },
255
- {
256
- "file": "server/services.list.js",
257
- "hash": "4032859481033847252"
258
- },
259
- {
260
- "file": "server/start.js",
261
- "hash": "3387118482182040319"
262
- },
263
- {
264
- "file": "server/testTasks.js",
265
- "hash": "14976257887791558210"
266
- },
267
- {
268
- "file": "start-dev-docker.sh",
269
- "hash": "1356997101209839594"
270
- }
271
- ]
272
- }
273
- }
Binary file
@@ -1,6 +0,0 @@
1
- {
2
- "nodes": {},
3
- "externalNodes": {},
4
- "dependencies": {},
5
- "version": "6.0"
6
- }
File without changes