Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c8e463b
chore: creation of devices store for better performance in scripts views
Corstor Aug 29, 2025
e142c9f
feat: add info button for scripts permissions page
MarkRagg Aug 29, 2025
17a443f
refactor: every asyncronous call to server to retrieve devices now us…
Corstor Aug 29, 2025
07732ad
refactor: now use a store for retrieving users for send notification …
Corstor Aug 29, 2025
56cefbb
refactor: also trigger component uses devices store
Corstor Aug 29, 2025
d11e7ce
refactor: now start task instruction uses a store to retrieve tasks
Corstor Aug 29, 2025
88bc1a6
chore: showing device actions description
Ventus218 Aug 29, 2025
3688842
refactor: now device groups dialog is just one changing based on chos…
Corstor Aug 29, 2025
5b654d6
fix: task id of empty start task is now a TaskId
Corstor Aug 29, 2025
f900f25
fix: fix info text
MarkRagg Aug 29, 2025
dd7beda
refactor: move info button in the general scripts permissions page
MarkRagg Aug 30, 2025
81f4ba5
fix: fix wrong word in info text
MarkRagg Aug 30, 2025
e076f04
feat: add info button to users permissions
MarkRagg Aug 30, 2025
bbbace3
Merge pull request #67 from DomoticASW/feature/device-action-descript…
Ventus218 Aug 30, 2025
176fd8f
refactor: decoupling logic from presentation
Corstor Aug 30, 2025
cd435c4
refactor: now store for groups and store for dialogs are decoupled
Corstor Aug 30, 2025
b9efb23
refactor: findDevice on groups store is not usefull anymore because d…
Corstor Aug 30, 2025
1705cb1
refactor: remove useless loading overlay and async signature where no…
Corstor Aug 31, 2025
ef68336
refactor: make setup of stores parallel
Corstor Aug 31, 2025
5b99796
chore: remove duplicate call
Corstor Aug 31, 2025
def70e1
fix: fix info text
MarkRagg Aug 31, 2025
61a21b3
Merge pull request #68 from DomoticASW/refactor/better-performance
Ventus218 Aug 31, 2025
1326166
chore: removed loading overlay for reg.req. badge
Ventus218 Aug 31, 2025
a9310ac
chore: remove loadingOverlay if skeletons are used
Ventus218 Aug 31, 2025
5d1edb6
chore: parallel fetching of data to load faster
Ventus218 Aug 31, 2025
379a4d9
fix: linting issues
Ventus218 Aug 31, 2025
e25ee54
Merge pull request #66 from DomoticASW/feature/add-permissions-info
Ventus218 Sep 1, 2025
646e5e2
Merge pull request #69 from DomoticASW/feature/reduce-impact-of-loadi…
MarkRagg Sep 1, 2025
331d334
docs: updated README with setup info
Ventus218 Sep 1, 2025
634c59f
chore: format code with default formatter
Ventus218 Sep 1, 2025
17d64c1
chore: add git hook to check code formatting
Ventus218 Sep 1, 2025
cd1ab55
ci: add github action to check code format
Ventus218 Sep 1, 2025
4fb77f1
Merge pull request #72 from DomoticASW/feature/polishing-codebase
Ventus218 Sep 1, 2025
dbf8c55
chore: improved accessibility for ValueIOControl
Ventus218 Aug 29, 2025
2f018c2
chore: use span instead of i html element
Ventus218 Aug 29, 2025
0748134
chore: better accessibility for ManageDevicesView
Ventus218 Aug 29, 2025
1208355
chore: better accessibility for DeviceGroupsView
Ventus218 Aug 29, 2025
ca3da69
refactor: add groups to device event trigger
Corstor Sep 1, 2025
b434c91
refactor: add groups to device chosen in device event trigger dialog
Corstor Sep 1, 2025
df95cdd
refactor: use of code formatter
Corstor Sep 1, 2025
e2df632
chore: use p instead of h in dialog titles
Ventus218 Sep 1, 2025
20d9587
chore: nicer req requests indicator
Ventus218 Sep 1, 2025
b7b638f
Merge pull request #74 from DomoticASW/refactor/groups-on-device-even…
Ventus218 Sep 1, 2025
e8b0303
Merge pull request #75 from DomoticASW/feature/nicer-indication-for-r…
Ventus218 Sep 1, 2025
73c6f24
Merge pull request #73 from DomoticASW/feature/accessibility
Corstor Sep 1, 2025
a1f50aa
chore: add labels with right names and ids to inputs
Corstor Sep 1, 2025
10e1393
fix: put hidden class to wait instructions labels
Corstor Sep 1, 2025
de529cb
Merge pull request #76 from DomoticASW/feature/accessability-scripts
Corstor Sep 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/code-format.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Code format

on: pull_request

jobs:
code-format:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: 'npm'
- run: npm ci
- run: npm run format-check
4 changes: 2 additions & 2 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
"printWidth": 100,
"trailingComma": "es5"
}
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# client

This template should help get you started developing with Vue 3 in Vite.
This is the client SPA for DomoticASW, it is deployed as a submodule inside DomoticASW's server.

## Recommended IDE Setup

Expand All @@ -14,9 +14,10 @@ TypeScript cannot handle type information for `.vue` imports by default, so we r

See [Vite Configuration Reference](https://vite.dev/config/).

## Project Setup
## Setup

```sh
./setup.sh
npm install
```

Expand Down
14 changes: 14 additions & 0 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.

# Redirect output to stderr.
exec 1>&2

if ! npm run format-check; then
echo Run \"npm run format\" to fix
exit 1
fi
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"type-check": "vue-tsc --build",
"lint": "eslint .",
"lint-fix": "npm run lint --fix",
"format": "prettier --write src/"
"format": "prettier --write src/",
"format-check": "prettier --check src/"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.11",
Expand Down
16 changes: 8 additions & 8 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ 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'
</script>

<template>
<div class="flex justify-center">
<ErrorPresenter>
<LoadingOverlay>
<div class="h-full w-full max-w-5xl">
<RouterView />
<SuccessPresenter>
</SuccessPresenter>
</div>
</LoadingOverlay>

<LoadingOverlay>
<div class="h-full w-full max-w-5xl">
<RouterView />
<SuccessPresenter> </SuccessPresenter>
<DeviceGroupsDialog />
</div>
</LoadingOverlay>
</ErrorPresenter>
</div>
</template>
Expand Down
23 changes: 11 additions & 12 deletions src/api/Deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export type Deserializer<T> = (json: unknown) => T
export function Deserializer<From, To>(
checkDeserializable: (obj: unknown) => obj is From,
deserialize: (obj: From) => To,
deserializationError?: (obj: unknown) => string): Deserializer<To> {

deserializationError?: (obj: unknown) => string
): Deserializer<To> {
return (json) => {
if (checkDeserializable(json)) {
return deserialize(json)
Expand All @@ -29,19 +29,18 @@ export function arrayDeserializer<T>(itemDeserializer: Deserializer<T>): Deseria
if (!Array.isArray(obj)) {
throw DeserializeError(`Expecting an array but ${typeof obj} was found`)
}
return obj.map(item => itemDeserializer(item))
return obj.map((item) => itemDeserializer(item))
}
}

function isBoolean(o: unknown): o is boolean {
return o != undefined && typeof o == "boolean"
return o != undefined && typeof o == 'boolean'
}
export const booleanDeserializer: Deserializer<boolean> =
Deserializer(
isBoolean,
(obj) => obj,
(obj) => `Expecting a boolean but ${typeof obj} was found`
)
export const booleanDeserializer: Deserializer<boolean> = Deserializer(
isBoolean,
(obj) => obj,
(obj) => `Expecting a boolean but ${typeof obj} was found`
)

export interface DeserializeError {
message: string
Expand All @@ -50,7 +49,7 @@ export interface DeserializeError {

export function DeserializeError(cause?: string): DeserializeError {
return {
message: "There was an error while deserializing a response from the server.",
cause
message: 'There was an error while deserializing a response from the server.',
cause,
}
}
16 changes: 7 additions & 9 deletions src/api/IdDTO.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Deserializer } from "./Deserializer";
import { Deserializer } from './Deserializer'

export interface IdDTO {
id: string
}

export function isIdDTO(o: unknown): o is IdDTO {
return o != undefined && typeof o == "object" &&
"id" in o && typeof o.id == "string"
return o != undefined && typeof o == 'object' && 'id' in o && typeof o.id == 'string'
}

export const idDeserializer =
Deserializer<IdDTO, string>(
isIdDTO,
(dto) => dto.id,
(obj) => `Unable to deserialize ${obj} into a string id since it was not an IdDTO`
)
export const idDeserializer = Deserializer<IdDTO, string>(
isIdDTO,
(dto) => dto.id,
(obj) => `Unable to deserialize ${obj} into a string id since it was not an IdDTO`
)
13 changes: 9 additions & 4 deletions src/api/ServerError.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Deserializer } from "./Deserializer"
import { Deserializer } from './Deserializer'

export interface ServerError {
__brand: string
Expand All @@ -7,9 +7,14 @@ export interface ServerError {
}

export function isServerError(o: unknown): o is ServerError {
return o != undefined && typeof o == "object" &&
"__brand" in o && typeof o.__brand == "string" &&
"message" in o && typeof o.message == "string"
return (
o != undefined &&
typeof o == 'object' &&
'__brand' in o &&
typeof o.__brand == 'string' &&
'message' in o &&
typeof o.message == 'string'
)
}

export const toServerErrorDeserializer: Deserializer<ServerError> = Deserializer(
Expand Down
22 changes: 13 additions & 9 deletions src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { DeserializeError, type Deserializer } from "./Deserializer"
import { toServerErrorDeserializer } from "./ServerError"
import { DeserializeError, type Deserializer } from './Deserializer'
import { toServerErrorDeserializer } from './ServerError'

/**
* Does the same as `request` plus setting the Authorization header to token if it is not already set.
*/
export async function authorizedRequest(url: RequestInfo | URL, token: string, init?: RequestInit): Promise<Response> {
export async function authorizedRequest(
url: RequestInfo | URL,
token: string,
init?: RequestInit
): Promise<Response> {
const headers = new Headers(init?.headers) // Ensuring that the type of init.headers is Headers
if (!headers.has("Authorization")) {
headers.append("Authorization", token)
if (!headers.has('Authorization')) {
headers.append('Authorization', token)
}
return await request(url, { ...init, headers })
}
Expand All @@ -21,8 +25,8 @@ export async function authorizedRequest(url: RequestInfo | URL, token: string, i
*/
export async function request(url: RequestInfo | URL, init?: RequestInit): Promise<Response> {
const headers = new Headers(init?.headers) // Ensuring that the type of init.headers is Headers
if (!headers.has("Content-Type")) {
headers.append("Content-Type", "application/json")
if (!headers.has('Content-Type')) {
headers.append('Content-Type', 'application/json')
}
const response = await fetch(url, { ...init, headers })
if (!response.ok) {
Expand All @@ -41,14 +45,14 @@ export async function deserializeBody<T>(res: Response, deserializer: Deserializ
// Passing through a text representation as res.json() uses JSON.parse and will fail in case of empty body
const bodyAsText = await res.text()
if (bodyAsText.trim().length == 0) {
throw DeserializeError("Response body was empty")
throw DeserializeError('Response body was empty')
}

let body: object
try {
body = JSON.parse(bodyAsText)
} catch (e) {
throw DeserializeError("Unable to parse json from response body.\n" + (e as Error).message)
throw DeserializeError('Unable to parse json from response body.\n' + (e as Error).message)
}

if (!res.ok) {
Expand Down
40 changes: 23 additions & 17 deletions src/api/devices-management/dtos/device-groups/DeviceGroupDTO.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DeviceGroupId, type DeviceGroup } from "@/model/devices-management/DeviceGroup"
import { Deserializer } from "../../../Deserializer"
import { deviceDeserializer, isDeviceDTO, type DeviceDTO } from "../devices/DeviceDTO"
import { DeviceGroupId, type DeviceGroup } from '@/model/devices-management/DeviceGroup'
import { Deserializer } from '../../../Deserializer'
import { deviceDeserializer, isDeviceDTO, type DeviceDTO } from '../devices/DeviceDTO'

export interface DeviceGroupDTO {
id: string
Expand All @@ -9,19 +9,25 @@ export interface DeviceGroupDTO {
}

export function isDeviceGroupDTO(o: unknown): o is DeviceGroupDTO {
return o != undefined && typeof o === "object" &&
"id" in o && typeof o.id === "string" &&
"name" in o && typeof o.name === "string" &&
"devices" in o && Array.isArray(o.devices) && o.devices.every(isDeviceDTO)
return (
o != undefined &&
typeof o === 'object' &&
'id' in o &&
typeof o.id === 'string' &&
'name' in o &&
typeof o.name === 'string' &&
'devices' in o &&
Array.isArray(o.devices) &&
o.devices.every(isDeviceDTO)
)
}

export const deviceGroupDeserializer =
Deserializer<DeviceGroupDTO, DeviceGroup>(
isDeviceGroupDTO,
(dto) => ({
id: DeviceGroupId(dto.id),
name: dto.name,
devices: dto.devices.map(deviceDeserializer)
}),
(obj) => `Unable to parse ${obj} into a DeviceGroup since it was not a DeviceGroupDTO`
)
export const deviceGroupDeserializer = Deserializer<DeviceGroupDTO, DeviceGroup>(
isDeviceGroupDTO,
(dto) => ({
id: DeviceGroupId(dto.id),
name: dto.name,
devices: dto.devices.map(deviceDeserializer),
}),
(obj) => `Unable to parse ${obj} into a DeviceGroup since it was not a DeviceGroupDTO`
)
36 changes: 20 additions & 16 deletions src/api/devices-management/dtos/devices/ColorDTO.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@

import { Color } from "@/model/devices-management/Types";
import { Deserializer } from "../../../Deserializer";
import { Color } from '@/model/devices-management/Types'
import { Deserializer } from '../../../Deserializer'

export interface ColorDTO {
readonly r: number;
readonly g: number;
readonly b: number;
readonly r: number
readonly g: number
readonly b: number
}

export function isColorDTO(o: unknown): o is ColorDTO {
return o != undefined && typeof o == "object" &&
"r" in o && typeof o.r == "number" &&
"g" in o && typeof o.g == "number" &&
"b" in o && typeof o.b == "number"
return (
o != undefined &&
typeof o == 'object' &&
'r' in o &&
typeof o.r == 'number' &&
'g' in o &&
typeof o.g == 'number' &&
'b' in o &&
typeof o.b == 'number'
)
}

export const colorDeserializer =
Deserializer<ColorDTO, Color>(
isColorDTO,
(dto) => Color(dto.r, dto.g, dto.b),
(obj) => `Unable to deserialize ${obj} into a Color since it was not a ColorDTO`
)
export const colorDeserializer = Deserializer<ColorDTO, Color>(
isColorDTO,
(dto) => Color(dto.r, dto.g, dto.b),
(obj) => `Unable to deserialize ${obj} into a Color since it was not a ColorDTO`
)
Loading