From c8e463bb2885b588d7e62dede59905d424d08255 Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Fri, 29 Aug 2025 17:17:49 +0200 Subject: [PATCH 01/13] chore: creation of devices store for better performance in scripts views --- ...eDevicePropertyConstantInstructionItem.vue | 11 ++++--- src/stores/devices.ts | 29 +++++++++++++++++++ src/views/automations/AutomationView.vue | 2 ++ src/views/automations/EditAutomationView.vue | 2 ++ src/views/tasks/EditTaskView.vue | 2 ++ src/views/tasks/TaskView.vue | 2 ++ 6 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/stores/devices.ts diff --git a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue index 7ca6ef0..72f0b85 100644 --- a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue +++ b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue @@ -121,6 +121,7 @@ import { useLoadingOverlayStore } from '@/stores/loading-overlay' import DeviceNameAndGroup from '../DeviceNameAndGroup.vue' import DeviceGroupsDialog from '../DeviceGroupsDialog.vue' import { useGroupsStore } from '@/stores/groups' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id: string @@ -135,6 +136,8 @@ const userInfo = useUserInfoStore() const instruction = ref(props.instruction.instruction as CreateDevicePropertyConstantInstruction) const device = ref() const property = ref>() +const devicesStore = useDevicesStore() +const groupsStore = useGroupsStore() const variableForm = ref({ name: instruction.value.name, @@ -157,13 +160,13 @@ onMounted(async () => await updateInstruction()) async function updateInstruction() { try { loadingOverlay.startLoading() - const deviceGroups = useGroupsStore().deviceGroups(instruction.value.deviceId) + const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) if (deviceGroups.length > 0) { - device.value = useGroupsStore().getDeviceFromGroups(instruction.value.deviceId)! + device.value = groupsStore.getDeviceFromGroups(instruction.value.deviceId)! } else { - device.value = await findDevice(instruction.value.deviceId, userInfo.token) + device.value = devicesStore.getDevice(instruction.value.deviceId) } - property.value = device.value.properties.find( + property.value = device.value?.properties.find( (prop) => prop.id === instruction.value.devicePropertyId, ) } finally { diff --git a/src/stores/devices.ts b/src/stores/devices.ts new file mode 100644 index 0000000..0315929 --- /dev/null +++ b/src/stores/devices.ts @@ -0,0 +1,29 @@ +import { defineStore } from "pinia" +import { useUserInfoStore } from "./user-info" +import { ref } from "vue" +import type { Device, DeviceId } from "@/model/devices-management/Device"; +import { useLoadingOverlayStore } from "./loading-overlay"; +import { getAllDevices } from "@/api/devices-management/requests/devices"; + +export const useDevicesStore = defineStore('devices', () => { + const userInfo = useUserInfoStore() + const devices = ref() + + async function updateDevices() { + const loadingOverlay = useLoadingOverlayStore() + if (userInfo.token) { + try { + loadingOverlay.startLoading() + devices.value = await getAllDevices(userInfo.token) + } finally { + loadingOverlay.stopLoading() + } + } + } + + function getDevice(deviceId: DeviceId) { + return devices.value?.find(d => d.id === deviceId) + } + + return { devices, updateDevices, getDevice } +}); diff --git a/src/views/automations/AutomationView.vue b/src/views/automations/AutomationView.vue index fddf030..5b0fd00 100644 --- a/src/views/automations/AutomationView.vue +++ b/src/views/automations/AutomationView.vue @@ -11,6 +11,7 @@ import Route from '@/router/index' import NavbarLayout from '@/components/NavbarLayout.vue' import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id: string }>() const userInfo = useUserInfoStore() @@ -22,6 +23,7 @@ const loadingOverlay = useLoadingOverlayStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { + await useDevicesStore().updateDevices() try { loadingOverlay.startLoading() const automation = await findAutomation(AutomationId(props.id), userInfo.token) diff --git a/src/views/automations/EditAutomationView.vue b/src/views/automations/EditAutomationView.vue index e3fdeb8..c47eccf 100644 --- a/src/views/automations/EditAutomationView.vue +++ b/src/views/automations/EditAutomationView.vue @@ -19,6 +19,7 @@ import DeviceActionPropertyDialog from '@/components/tasks-automations/DeviceAct import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' import InfoDialogs from '@/components/tasks-automations/InfoDialogs.vue' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id?: string }>() const userInfo = useUserInfoStore() @@ -31,6 +32,7 @@ const successPresenter = useSuccessPresenterStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { + await useDevicesStore().updateDevices() if (props.id) { try { loadingOverlay.startLoading() diff --git a/src/views/tasks/EditTaskView.vue b/src/views/tasks/EditTaskView.vue index f72a34b..3b959a3 100644 --- a/src/views/tasks/EditTaskView.vue +++ b/src/views/tasks/EditTaskView.vue @@ -14,6 +14,7 @@ import DeviceActionPropertyDialog from '@/components/tasks-automations/DeviceAct import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' import InfoDialogs from '@/components/tasks-automations/InfoDialogs.vue' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id?: string }>() const userInfo = useUserInfoStore() @@ -25,6 +26,7 @@ const successPresenter = useSuccessPresenterStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { + await useDevicesStore().updateDevices() if (props.id) { try { loadingOverlay.startLoading() diff --git a/src/views/tasks/TaskView.vue b/src/views/tasks/TaskView.vue index bc53feb..3d98ff8 100644 --- a/src/views/tasks/TaskView.vue +++ b/src/views/tasks/TaskView.vue @@ -10,6 +10,7 @@ import { useLoadingOverlayStore } from '@/stores/loading-overlay' import NavbarLayout from '@/components/NavbarLayout.vue' import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id: string }>() const userInfo = useUserInfoStore() @@ -22,6 +23,7 @@ const taskName = ref('') const taskId = ref() onMounted(async () => { + await useDevicesStore().updateDevices() try { loadingOverlay.startLoading() const task = await findTask(TaskId(props.id), userInfo.token) From 17a443fbfff253484b023949d57de85dbf81f844 Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Fri, 29 Aug 2025 17:28:53 +0200 Subject: [PATCH 02/13] refactor: every asyncronous call to server to retrieve devices now uses the store --- ...eDevicePropertyConstantInstructionItem.vue | 6 +++--- .../DeviceActionInstructionItem.vue | 20 +++++++++---------- .../tasks-automations/InstructionItems.vue | 12 +++++------ 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue index 72f0b85..2692188 100644 --- a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue +++ b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue @@ -150,14 +150,14 @@ watch( () => props.instruction, async (val) => { instruction.value = val.instruction as CreateDevicePropertyConstantInstruction - await updateInstruction() + updateInstruction() }, { immediate: true }, ) -onMounted(async () => await updateInstruction()) +onMounted(() => updateInstruction()) -async function updateInstruction() { +function updateInstruction() { try { loadingOverlay.startLoading() const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) diff --git a/src/components/tasks-automations/DeviceActionInstructionItem.vue b/src/components/tasks-automations/DeviceActionInstructionItem.vue index ae1191e..661f0fe 100644 --- a/src/components/tasks-automations/DeviceActionInstructionItem.vue +++ b/src/components/tasks-automations/DeviceActionInstructionItem.vue @@ -151,15 +151,14 @@ import { import InstructionLayout from './InstructionLayout.vue' import { onMounted, ref, watch } from 'vue' import type { Device, DeviceAction } from '@/model/devices-management/Device' -import { useUserInfoStore } from '@/stores/user-info' import { useInstructionsStore } from '@/stores/instructions' -import { findDevice } from '@/api/devices-management/requests/devices' import { Type } from '@/model/Type' import { getDefaultInput } from './emptyInstructions' import { useLoadingOverlayStore } from '@/stores/loading-overlay' import DeviceGroupsDialog from '../DeviceGroupsDialog.vue' import DeviceNameAndGroup from '../DeviceNameAndGroup.vue' import { useGroupsStore } from '@/stores/groups' +import { useDevicesStore } from '@/stores/devices' const props = defineProps<{ id: string @@ -170,10 +169,11 @@ const props = defineProps<{ const instructionsStore = useInstructionsStore() const loadingOverlay = useLoadingOverlayStore() -const userInfo = useUserInfoStore() const instruction = ref(props.instruction.instruction as DeviceActionInstruction) const device = ref() const action = ref>() +const groupsStore = useGroupsStore() +const devicesStore = useDevicesStore() const selectedAction = ref>() @@ -187,7 +187,7 @@ watch( () => props.instruction, async (val) => { instruction.value = val.instruction as DeviceActionInstruction - await updateInstruction() + updateInstruction() }, { immediate: true }, ) @@ -291,18 +291,18 @@ function variableType(): TypeDTO { } } -onMounted(async () => await updateInstruction()) +onMounted(() => updateInstruction()) -async function updateInstruction() { +function updateInstruction() { try { loadingOverlay.startLoading() - const deviceGroups = useGroupsStore().deviceGroups(instruction.value.deviceId) + const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) if (deviceGroups.length > 0) { - device.value = useGroupsStore().getDeviceFromGroups(instruction.value.deviceId)! + device.value = groupsStore.getDeviceFromGroups(instruction.value.deviceId)! } else { - device.value = await findDevice(instruction.value.deviceId, userInfo.token) + device.value = devicesStore.getDevice(instruction.value.deviceId) } - action.value = device.value.actions.find((act) => act.id === instruction.value.deviceActionId) + action.value = device.value?.actions.find((act) => act.id === instruction.value.deviceActionId) selectedAction.value = action.value } finally { loadingOverlay.stopLoading() diff --git a/src/components/tasks-automations/InstructionItems.vue b/src/components/tasks-automations/InstructionItems.vue index 1427478..fa0f6bc 100644 --- a/src/components/tasks-automations/InstructionItems.vue +++ b/src/components/tasks-automations/InstructionItems.vue @@ -1,10 +1,7 @@ From d11e7cecc79797d8aac1e1c4d517c82ec44691f9 Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Fri, 29 Aug 2025 17:52:51 +0200 Subject: [PATCH 05/13] refactor: now start task instruction uses a store to retrieve tasks --- src/api/scripts/dtos/GetInstructionDTO.ts | 3 ++- .../StartTaskInstructionItem.vue | 17 ++++------------ src/model/scripts/Instruction.ts | 3 ++- src/stores/devices.ts | 11 +--------- src/stores/tasks.ts | 20 +++++++++++++++++++ src/stores/users.ts | 11 +--------- src/views/automations/AutomationView.vue | 6 ++++-- src/views/automations/EditAutomationView.vue | 8 +++++--- src/views/tasks/EditTaskView.vue | 6 ++++-- src/views/tasks/TaskView.vue | 6 ++++-- 10 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 src/stores/tasks.ts diff --git a/src/api/scripts/dtos/GetInstructionDTO.ts b/src/api/scripts/dtos/GetInstructionDTO.ts index 2a9645c..5e3195e 100644 --- a/src/api/scripts/dtos/GetInstructionDTO.ts +++ b/src/api/scripts/dtos/GetInstructionDTO.ts @@ -19,6 +19,7 @@ import { } from './GetInstructionTypeDTO' import { isTypeDTO, typeDeserializer, type TypeDTO } from '@/api/devices-management/dtos/devices/TypeDTO' import { DeviceActionId, DeviceId, DevicePropertyId } from '@/model/devices-management/Device' +import { TaskId } from '@/model/scripts/Script' export interface GetInstructionDTO { type: GetInstructionTypeDTO @@ -204,7 +205,7 @@ export const startTaskDeserializer = Deserializer { return { - taskId: dto.taskId, + taskId: TaskId(dto.taskId), } }, ) diff --git a/src/components/tasks-automations/StartTaskInstructionItem.vue b/src/components/tasks-automations/StartTaskInstructionItem.vue index 1df571a..c2e97ae 100644 --- a/src/components/tasks-automations/StartTaskInstructionItem.vue +++ b/src/components/tasks-automations/StartTaskInstructionItem.vue @@ -17,11 +17,8 @@ import type { Instruction, StartTaskInstruction } from '@/model/scripts/Instruction' import InstructionLayout from './InstructionLayout.vue' import { onMounted, ref, watch } from 'vue' -import { useUserInfoStore } from '@/stores/user-info' -import { useLoadingOverlayStore } from '@/stores/loading-overlay' -import { getAllTasks } from '@/api/scripts/requests/tasks' import { type Task } from '@/model/scripts/Script' -const userInfo = useUserInfoStore() +import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ instruction: Instruction @@ -32,16 +29,10 @@ const props = defineProps<{ const taskName = ref() const tasks = ref() -const loadingOverlay = useLoadingOverlayStore() -onMounted(async () => { - try { - loadingOverlay.startLoading() - tasks.value = await getAllTasks(userInfo.token) +onMounted(() => { + tasks.value = useTasksStore().tasks updateTaskName(props.instruction.instruction as StartTaskInstruction) - } finally { - loadingOverlay.stopLoading() - } }) watch( @@ -52,6 +43,6 @@ watch( ) async function updateTaskName(instruction: StartTaskInstruction) { - taskName.value = tasks.value?.find((t) => t.id === instruction.taskId)?.name + taskName.value = useTasksStore().getTask(instruction.taskId)?.name } diff --git a/src/model/scripts/Instruction.ts b/src/model/scripts/Instruction.ts index a35d5cf..405f0d9 100644 --- a/src/model/scripts/Instruction.ts +++ b/src/model/scripts/Instruction.ts @@ -1,5 +1,6 @@ import type { DeviceActionId, DeviceId, DevicePropertyId } from '../devices-management/Device' import type { Type } from '../Type' +import type { TaskId } from './Script' export enum InstructionType { SendNotificationInstruction = 'SendNotificationInstruction', @@ -55,7 +56,7 @@ export interface WaitInstruction { } export interface StartTaskInstruction { - taskId: string + taskId: TaskId } export interface DeviceActionInstruction { diff --git a/src/stores/devices.ts b/src/stores/devices.ts index 0315929..afd1499 100644 --- a/src/stores/devices.ts +++ b/src/stores/devices.ts @@ -2,7 +2,6 @@ import { defineStore } from "pinia" import { useUserInfoStore } from "./user-info" import { ref } from "vue" import type { Device, DeviceId } from "@/model/devices-management/Device"; -import { useLoadingOverlayStore } from "./loading-overlay"; import { getAllDevices } from "@/api/devices-management/requests/devices"; export const useDevicesStore = defineStore('devices', () => { @@ -10,15 +9,7 @@ export const useDevicesStore = defineStore('devices', () => { const devices = ref() async function updateDevices() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - devices.value = await getAllDevices(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + devices.value = await getAllDevices(userInfo.token) } function getDevice(deviceId: DeviceId) { diff --git a/src/stores/tasks.ts b/src/stores/tasks.ts new file mode 100644 index 0000000..45eb869 --- /dev/null +++ b/src/stores/tasks.ts @@ -0,0 +1,20 @@ +import { getAllTasks } from "@/api/scripts/requests/tasks"; +import type { Task, TaskId } from "@/model/scripts/Script"; +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { useUserInfoStore } from "./user-info"; + +export const useTasksStore = defineStore('tasks', () => { + const userInfo = useUserInfoStore() + const tasks = ref() + + async function updateTasks() { + tasks.value = await getAllTasks(userInfo.token) + } + + function getTask(taskId: TaskId) { + return tasks.value?.find(t => t.id === taskId) + } + + return { tasks, updateTasks, getTask } +}); diff --git a/src/stores/users.ts b/src/stores/users.ts index 12f34af..5a819d9 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -1,7 +1,6 @@ import { defineStore } from "pinia"; import { useUserInfoStore } from "./user-info"; import { ref } from "vue"; -import { useLoadingOverlayStore } from "./loading-overlay"; import type { User } from "@/model/users-management/User"; import { getAllUsers } from "@/api/users-management/requests/users"; @@ -10,15 +9,7 @@ export const useUsersStore = defineStore('users', () => { const users = ref() async function updateUsers() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - users.value = await getAllUsers(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + users.value = await getAllUsers(userInfo.token) } function getUser(email: string) { diff --git a/src/views/automations/AutomationView.vue b/src/views/automations/AutomationView.vue index cebf655..6094598 100644 --- a/src/views/automations/AutomationView.vue +++ b/src/views/automations/AutomationView.vue @@ -13,6 +13,7 @@ import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-prese import { useErrorPresenterStore } from '@/stores/error-presenter' import { useDevicesStore } from '@/stores/devices' import { useUsersStore } from '@/stores/users' +import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id: string }>() const userInfo = useUserInfoStore() @@ -24,10 +25,11 @@ const loadingOverlay = useLoadingOverlayStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() try { loadingOverlay.startLoading() + await useDevicesStore().updateDevices() + await useUsersStore().updateUsers() + await useTasksStore().updateTasks() const automation = await findAutomation(AutomationId(props.id), userInfo.token) instructionsStore.instructions = automation.instructions automationName.value = automation.name diff --git a/src/views/automations/EditAutomationView.vue b/src/views/automations/EditAutomationView.vue index 1b31ad8..05b2789 100644 --- a/src/views/automations/EditAutomationView.vue +++ b/src/views/automations/EditAutomationView.vue @@ -21,6 +21,7 @@ import { useErrorPresenterStore } from '@/stores/error-presenter' import InfoDialogs from '@/components/tasks-automations/InfoDialogs.vue' import { useDevicesStore } from '@/stores/devices' import { useUsersStore } from '@/stores/users' +import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id?: string }>() const userInfo = useUserInfoStore() @@ -33,11 +34,12 @@ const successPresenter = useSuccessPresenterStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() if (props.id) { try { loadingOverlay.startLoading() + await useDevicesStore().updateDevices() + await useUsersStore().updateUsers() + await useTasksStore().updateTasks() const automation = await findAutomation(AutomationId(props.id), userInfo.token) instructionsStore.instructions = automation.instructions automationName.value = automation.name @@ -146,6 +148,6 @@ function showToastMessage(msg: string) {
- + diff --git a/src/views/tasks/EditTaskView.vue b/src/views/tasks/EditTaskView.vue index 6a88ce8..e884392 100644 --- a/src/views/tasks/EditTaskView.vue +++ b/src/views/tasks/EditTaskView.vue @@ -16,6 +16,7 @@ import { useErrorPresenterStore } from '@/stores/error-presenter' import InfoDialogs from '@/components/tasks-automations/InfoDialogs.vue' import { useDevicesStore } from '@/stores/devices' import { useUsersStore } from '@/stores/users' +import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id?: string }>() const userInfo = useUserInfoStore() @@ -27,11 +28,12 @@ const successPresenter = useSuccessPresenterStore() const errorPresenter = useErrorPresenterStore() onMounted(async () => { - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() if (props.id) { try { loadingOverlay.startLoading() + await useDevicesStore().updateDevices() + await useUsersStore().updateUsers() + await useTasksStore().updateTasks() const task = await findTask(TaskId(props.id), userInfo.token) instructionsStore.instructions = task.instructions taskName.value = task.name diff --git a/src/views/tasks/TaskView.vue b/src/views/tasks/TaskView.vue index 9080828..cf28d63 100644 --- a/src/views/tasks/TaskView.vue +++ b/src/views/tasks/TaskView.vue @@ -12,6 +12,7 @@ import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-prese import { useErrorPresenterStore } from '@/stores/error-presenter' import { useDevicesStore } from '@/stores/devices' import { useUsersStore } from '@/stores/users' +import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id: string }>() const userInfo = useUserInfoStore() @@ -24,10 +25,11 @@ const taskName = ref('') const taskId = ref() onMounted(async () => { - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() try { loadingOverlay.startLoading() + await useDevicesStore().updateDevices() + await useUsersStore().updateUsers() + await useTasksStore().updateTasks() const task = await findTask(TaskId(props.id), userInfo.token) instructionsStore.instructions = task.instructions taskName.value = task.name From 36888425dde155dc280b07c9d2c46ca65adbf000 Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Fri, 29 Aug 2025 18:39:19 +0200 Subject: [PATCH 06/13] refactor: now device groups dialog is just one changing based on chosen device --- src/App.vue | 2 ++ src/components/DeviceGroupsButton.vue | 3 +- src/components/DeviceGroupsDialog.vue | 30 ++++++++++++------- ...eDevicePropertyConstantInstructionItem.vue | 3 -- .../DeviceActionInstructionItem.vue | 3 -- src/main.ts | 11 ++++++- src/stores/devices.ts | 13 ++++++-- src/stores/groups.ts | 24 +++++++++++---- src/stores/tasks.ts | 13 ++++++-- src/stores/users.ts | 13 ++++++-- .../admin/device-groups/DeviceGroupView.vue | 3 -- .../manage-devices/ManageDevicesView.vue | 2 -- .../users-permissions/UserPermissionsView.vue | 3 -- src/views/automations/AutomationView.vue | 6 ---- src/views/automations/EditAutomationView.vue | 6 ---- src/views/devices/DeviceView.vue | 2 -- src/views/devices/DevicesView.vue | 2 -- src/views/tasks/EditTaskView.vue | 6 ---- src/views/tasks/TaskView.vue | 6 ---- 19 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/App.vue b/src/App.vue index 6fa3bca..d3c72d5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,6 +3,7 @@ import { RouterView } from 'vue-router' import LoadingOverlay from './components/LoadingOverlay.vue' import ErrorPresenter from './components/ErrorPresenter.vue' import SuccessPresenter from './components/SuccessPresenter.vue' +import DeviceGroupsDialog from './components/DeviceGroupsDialog.vue' - - diff --git a/src/views/tasks/EditTaskView.vue b/src/views/tasks/EditTaskView.vue index e884392..f72a34b 100644 --- a/src/views/tasks/EditTaskView.vue +++ b/src/views/tasks/EditTaskView.vue @@ -14,9 +14,6 @@ import DeviceActionPropertyDialog from '@/components/tasks-automations/DeviceAct import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' import InfoDialogs from '@/components/tasks-automations/InfoDialogs.vue' -import { useDevicesStore } from '@/stores/devices' -import { useUsersStore } from '@/stores/users' -import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id?: string }>() const userInfo = useUserInfoStore() @@ -31,9 +28,6 @@ onMounted(async () => { if (props.id) { try { loadingOverlay.startLoading() - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() - await useTasksStore().updateTasks() const task = await findTask(TaskId(props.id), userInfo.token) instructionsStore.instructions = task.instructions taskName.value = task.name diff --git a/src/views/tasks/TaskView.vue b/src/views/tasks/TaskView.vue index cf28d63..bc53feb 100644 --- a/src/views/tasks/TaskView.vue +++ b/src/views/tasks/TaskView.vue @@ -10,9 +10,6 @@ import { useLoadingOverlayStore } from '@/stores/loading-overlay' import NavbarLayout from '@/components/NavbarLayout.vue' import { presentSuccess, useSuccessPresenterStore } from '@/stores/success-presenter' import { useErrorPresenterStore } from '@/stores/error-presenter' -import { useDevicesStore } from '@/stores/devices' -import { useUsersStore } from '@/stores/users' -import { useTasksStore } from '@/stores/tasks' const props = defineProps<{ id: string }>() const userInfo = useUserInfoStore() @@ -27,9 +24,6 @@ const taskId = ref() onMounted(async () => { try { loadingOverlay.startLoading() - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() - await useTasksStore().updateTasks() const task = await findTask(TaskId(props.id), userInfo.token) instructionsStore.instructions = task.instructions taskName.value = task.name From 5b654d6c0543186636871ea122b8724fc742b3bf Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Fri, 29 Aug 2025 18:43:36 +0200 Subject: [PATCH 07/13] fix: task id of empty start task is now a TaskId --- src/components/tasks-automations/emptyInstructions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/tasks-automations/emptyInstructions.ts b/src/components/tasks-automations/emptyInstructions.ts index 6a3b36e..5824c53 100644 --- a/src/components/tasks-automations/emptyInstructions.ts +++ b/src/components/tasks-automations/emptyInstructions.ts @@ -11,6 +11,7 @@ import type { DeviceActionInstruction, } from '@/model/scripts/Instruction' import { ConditionOperatorType } from '@/model/scripts/Instruction' +import { TaskId } from '@/model/scripts/Script' import { Type } from '@/model/Type' export function EmptyIfInstruction(): IfInstruction { @@ -46,7 +47,7 @@ export function EmptyWaitInstruction(): WaitInstruction { export function EmptyStartTaskInstruction(): StartTaskInstruction { return { - taskId: '', + taskId: TaskId(''), } } From 176fd8fe1ae645734790a99eb3cdd8756d053ddc Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Sat, 30 Aug 2025 15:42:05 +0200 Subject: [PATCH 08/13] refactor: decoupling logic from presentation --- src/components/DeviceGroupsDialog.vue | 2 +- ...eDevicePropertyConstantInstructionItem.vue | 2 +- .../DeviceActionInstructionItem.vue | 2 +- src/main.ts | 26 ++++++++++++------- src/stores/devices.ts | 11 +------- src/stores/groups.ts | 15 +++-------- src/stores/tasks.ts | 11 +------- src/stores/users.ts | 11 +------- 8 files changed, 26 insertions(+), 54 deletions(-) diff --git a/src/components/DeviceGroupsDialog.vue b/src/components/DeviceGroupsDialog.vue index 83ba4b4..4ef00f5 100644 --- a/src/components/DeviceGroupsDialog.vue +++ b/src/components/DeviceGroupsDialog.vue @@ -12,7 +12,7 @@ const dialog = useTemplateRef('groups_info') groupsStore.$subscribe(() => { if (groupsStore.selectedDevice) { - device.value = groupsStore.getDeviceFromGroups(groupsStore.selectedDevice) + device.value = groupsStore.findDevice(groupsStore.selectedDevice) deviceGroups.value = groupsStore.selectedGroups dialog.value?.showModal() } diff --git a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue index 7fad0bf..ff10506 100644 --- a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue +++ b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue @@ -159,7 +159,7 @@ function updateInstruction() { loadingOverlay.startLoading() const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) if (deviceGroups.length > 0) { - device.value = groupsStore.getDeviceFromGroups(instruction.value.deviceId)! + device.value = groupsStore.findDevice(instruction.value.deviceId)! } else { device.value = devicesStore.getDevice(instruction.value.deviceId) } diff --git a/src/components/tasks-automations/DeviceActionInstructionItem.vue b/src/components/tasks-automations/DeviceActionInstructionItem.vue index a44473a..2c2451a 100644 --- a/src/components/tasks-automations/DeviceActionInstructionItem.vue +++ b/src/components/tasks-automations/DeviceActionInstructionItem.vue @@ -295,7 +295,7 @@ function updateInstruction() { loadingOverlay.startLoading() const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) if (deviceGroups.length > 0) { - device.value = groupsStore.getDeviceFromGroups(instruction.value.deviceId)! + device.value = groupsStore.findDevice(instruction.value.deviceId)! } else { device.value = devicesStore.getDevice(instruction.value.deviceId) } diff --git a/src/main.ts b/src/main.ts index d9d985f..f2fbe88 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,7 +20,7 @@ const app = createApp(App) app.use(createPinia()) app.use(router) -useLoadingOverlayStore() +const loadingOverlay = useLoadingOverlayStore() // Loading a session token if it exists const userInfo = useUserInfoStore() @@ -46,16 +46,24 @@ app.config.errorHandler = (err) => { } userInfo.$subscribe(async () => { - await useGroupsStore().updateGroups() - await useDevicesStore().updateDevices() - await useUsersStore().updateUsers() - await useTasksStore().updateTasks() + await setupStores() }) -useGroupsStore().updateGroups() -useDevicesStore().updateDevices() -useUsersStore().updateUsers() -useTasksStore().updateTasks() +setupStores() + +async function setupStores() { + if (userInfo.token) { + try { + loadingOverlay.startLoading() + await useGroupsStore().updateGroups() + await useDevicesStore().updateDevices() + await useUsersStore().updateUsers() + await useTasksStore().updateTasks() + } finally { + loadingOverlay.stopLoading() + } + } +} // During development it's possible to set a VITE_USER_INFO object to skip login: // VITE_USER_INFO='{"email": "a@email.com", "nickname": "Foo", "token": "blablabla", "role": "Admin" }' npm run dev diff --git a/src/stores/devices.ts b/src/stores/devices.ts index 6dd8d1d..c2eee34 100644 --- a/src/stores/devices.ts +++ b/src/stores/devices.ts @@ -3,22 +3,13 @@ import { useUserInfoStore } from "./user-info" import { ref } from "vue" import type { Device, DeviceId } from "@/model/devices-management/Device"; import { getAllDevices } from "@/api/devices-management/requests/devices"; -import { useLoadingOverlayStore } from "./loading-overlay"; export const useDevicesStore = defineStore('devices', () => { const userInfo = useUserInfoStore() const devices = ref([]) async function updateDevices() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - devices.value = await getAllDevices(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + devices.value = await getAllDevices(userInfo.token) } function getDevice(deviceId: DeviceId) { diff --git a/src/stores/groups.ts b/src/stores/groups.ts index 2951222..42003f2 100644 --- a/src/stores/groups.ts +++ b/src/stores/groups.ts @@ -4,7 +4,6 @@ import { defineStore } from "pinia"; import { ref } from "vue"; import { useUserInfoStore } from "./user-info"; import { type DeviceId } from "@/model/devices-management/Device"; -import { useLoadingOverlayStore } from "./loading-overlay"; export const useGroupsStore = defineStore('groups', () => { const userInfo = useUserInfoStore() @@ -13,15 +12,7 @@ export const useGroupsStore = defineStore('groups', () => { const selectedDevice = ref() async function updateGroups() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - groups.value = await getAllDeviceGroups(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + groups.value = await getAllDeviceGroups(userInfo.token) } function deviceGroups(deviceId: DeviceId, show: boolean = false) { @@ -34,7 +25,7 @@ export const useGroupsStore = defineStore('groups', () => { return selectedGroups.value } - function getDeviceFromGroups(deviceId: DeviceId) { + function findDevice(deviceId: DeviceId) { return groups.value.filter((g) => g.devices.map(d => d.id).includes(deviceId) )[0].devices.find( @@ -46,5 +37,5 @@ export const useGroupsStore = defineStore('groups', () => { selectedDevice.value = undefined } - return { groups, selectedGroups, selectedDevice, updateGroups, deviceGroups, getDeviceFromGroups, resetSelectedDevice } + return { groups, selectedGroups, selectedDevice, updateGroups, deviceGroups, findDevice, resetSelectedDevice } }) diff --git a/src/stores/tasks.ts b/src/stores/tasks.ts index f7a04a1..4c59ff2 100644 --- a/src/stores/tasks.ts +++ b/src/stores/tasks.ts @@ -3,22 +3,13 @@ import type { Task, TaskId } from "@/model/scripts/Script"; import { defineStore } from "pinia"; import { ref } from "vue"; import { useUserInfoStore } from "./user-info"; -import { useLoadingOverlayStore } from "./loading-overlay"; export const useTasksStore = defineStore('tasks', () => { const userInfo = useUserInfoStore() const tasks = ref([]) async function updateTasks() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - tasks.value = await getAllTasks(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + tasks.value = await getAllTasks(userInfo.token) } function getTask(taskId: TaskId) { diff --git a/src/stores/users.ts b/src/stores/users.ts index 2bdd266..c8938d6 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -3,22 +3,13 @@ import { useUserInfoStore } from "./user-info"; import { ref } from "vue"; import type { User } from "@/model/users-management/User"; import { getAllUsers } from "@/api/users-management/requests/users"; -import { useLoadingOverlayStore } from "./loading-overlay"; export const useUsersStore = defineStore('users', () => { const userInfo = useUserInfoStore() const users = ref([]) async function updateUsers() { - const loadingOverlay = useLoadingOverlayStore() - if (userInfo.token) { - try { - loadingOverlay.startLoading() - users.value = await getAllUsers(userInfo.token) - } finally { - loadingOverlay.stopLoading() - } - } + users.value = await getAllUsers(userInfo.token) } function getUser(email: string) { From cd435c4e5ff066f796d97aeb340ad0dd1e7441a4 Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Sat, 30 Aug 2025 16:13:54 +0200 Subject: [PATCH 09/13] refactor: now store for groups and store for dialogs are decoupled --- src/components/DeviceGroupsButton.vue | 7 +++---- src/components/DeviceGroupsDialog.vue | 17 +++++++--------- ...eDevicePropertyConstantInstructionItem.vue | 2 +- .../DeviceActionInstructionItem.vue | 3 +-- src/stores/groups-dialog.ts | 19 ++++++++++++++++++ src/stores/groups.ts | 20 ++++--------------- 6 files changed, 35 insertions(+), 33 deletions(-) create mode 100644 src/stores/groups-dialog.ts diff --git a/src/components/DeviceGroupsButton.vue b/src/components/DeviceGroupsButton.vue index eb0f0ff..7c2b1e5 100644 --- a/src/components/DeviceGroupsButton.vue +++ b/src/components/DeviceGroupsButton.vue @@ -1,6 +1,7 @@ diff --git a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue index ff10506..01c04f6 100644 --- a/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue +++ b/src/components/tasks-automations/CreateDevicePropertyConstantInstructionItem.vue @@ -157,7 +157,7 @@ onMounted(() => updateInstruction()) function updateInstruction() { try { loadingOverlay.startLoading() - const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) + const deviceGroups = groupsStore.getGroupsOfDevice(instruction.value.deviceId) if (deviceGroups.length > 0) { device.value = groupsStore.findDevice(instruction.value.deviceId)! } else { diff --git a/src/components/tasks-automations/DeviceActionInstructionItem.vue b/src/components/tasks-automations/DeviceActionInstructionItem.vue index 2c2451a..72e1f6b 100644 --- a/src/components/tasks-automations/DeviceActionInstructionItem.vue +++ b/src/components/tasks-automations/DeviceActionInstructionItem.vue @@ -293,7 +293,7 @@ onMounted(() => updateInstruction()) function updateInstruction() { try { loadingOverlay.startLoading() - const deviceGroups = groupsStore.deviceGroups(instruction.value.deviceId) + const deviceGroups = groupsStore.getGroupsOfDevice(instruction.value.deviceId) if (deviceGroups.length > 0) { device.value = groupsStore.findDevice(instruction.value.deviceId)! } else { @@ -332,5 +332,4 @@ function closeDialog() { const dialog = document.getElementById(props.id.toString()) as HTMLDialogElement dialog.close() } - diff --git a/src/stores/groups-dialog.ts b/src/stores/groups-dialog.ts new file mode 100644 index 0000000..56b0e34 --- /dev/null +++ b/src/stores/groups-dialog.ts @@ -0,0 +1,19 @@ +import { defineStore } from "pinia" +import { computed, ref } from "vue" +import { useGroupsStore } from "./groups" +import type { DeviceId } from "@/model/devices-management/Device" + +export const useGroupsDialogStore = defineStore('groups-dialog', () => { + const selectedDeviceGroups = computed(() => selectedDevice.value ? useGroupsStore().getGroupsOfDevice(selectedDevice.value!) : []) + const selectedDevice = ref() + + function showDeviceGroups(deviceId: DeviceId) { + selectedDevice.value = deviceId + } + + function closeDialog() { + selectedDevice.value = undefined + } + + return { selectedDeviceGroups, selectedDevice, showDeviceGroups, closeDialog } +}) diff --git a/src/stores/groups.ts b/src/stores/groups.ts index 42003f2..43a31f9 100644 --- a/src/stores/groups.ts +++ b/src/stores/groups.ts @@ -8,34 +8,22 @@ import { type DeviceId } from "@/model/devices-management/Device"; export const useGroupsStore = defineStore('groups', () => { const userInfo = useUserInfoStore() const groups = ref([]) - const selectedGroups = ref([]) - const selectedDevice = ref() async function updateGroups() { groups.value = await getAllDeviceGroups(userInfo.token) } - function deviceGroups(deviceId: DeviceId, show: boolean = false) { - selectedGroups.value = groups.value.filter((g) => + function getGroupsOfDevice(deviceId: DeviceId) { + return groups.value.filter((g) => g.devices.map(d => d.id).includes(deviceId) ) - if (show) { - selectedDevice.value = deviceId - } - return selectedGroups.value } function findDevice(deviceId: DeviceId) { - return groups.value.filter((g) => - g.devices.map(d => d.id).includes(deviceId) - )[0].devices.find( + return getGroupsOfDevice(deviceId)[0].devices.find( (d) => d.id === deviceId, )! } - function resetSelectedDevice() { - selectedDevice.value = undefined - } - - return { groups, selectedGroups, selectedDevice, updateGroups, deviceGroups, findDevice, resetSelectedDevice } + return { groups, updateGroups, getGroupsOfDevice, findDevice } }) From b9efb23e5137c5b9f792c3fdce6d5746789a8c4c Mon Sep 17 00:00:00 2001 From: Corrado Stortini Date: Sat, 30 Aug 2025 16:20:11 +0200 Subject: [PATCH 10/13] refactor: findDevice on groups store is not usefull anymore because devicesstore is fast enough --- src/components/DeviceGroupsDialog.vue | 4 ++-- .../CreateDevicePropertyConstantInstructionItem.vue | 9 +-------- .../tasks-automations/DeviceActionInstructionItem.vue | 9 +-------- src/stores/groups.ts | 8 +------- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/components/DeviceGroupsDialog.vue b/src/components/DeviceGroupsDialog.vue index 49c9f03..804c2ac 100644 --- a/src/components/DeviceGroupsDialog.vue +++ b/src/components/DeviceGroupsDialog.vue @@ -1,7 +1,7 @@