Files
lightController/src/composables/dbm/dbmTree.ts
Adrian Zürcher 3e2b95c1c3 update dbmData and Subscription so it is reactive
new save load scenes
2025-06-19 19:30:28 +02:00

176 lines
4.6 KiB
TypeScript

import type { Subs, Subscribe } from 'src/models/Subscribe';
import type { Ref } from 'vue';
import { nextTick, computed, reactive, ref } from 'vue';
import { setValues } from 'src/services/websocket';
import { NotifyResponse } from 'src/composables/notify';
import type { QVueGlobals } from 'quasar';
const Subscriptions = reactive<Record<string, Subscribe>>({});
export const dbmData = reactive<TreeNode[]>([]);
export interface TreeNode {
path: string | undefined;
key?: string; // optional: useful for QTree's node-key
value?: string | number | boolean | undefined;
lazy: boolean;
children?: TreeNode[];
}
export function buildTree(subs: Subs): TreeNode[] {
type TreeMap = {
[key: string]: {
__children: TreeMap;
uuid?: string;
value?: string | undefined;
lazy: boolean;
};
};
const root: TreeMap = {};
for (const item of subs) {
if (item.path) {
Subscriptions[item.path] = item;
}
const pathParts = item.path?.split(':') ?? [];
let current = root;
for (let i = 0; i < pathParts.length; i++) {
const part = pathParts[i];
if (!part) continue;
if (!current[part]) {
current[part] = { __children: {}, lazy: true };
}
// Optionally attach uuid only at the final part
if (i === pathParts.length - 1 && item.uuid) {
current[part].uuid = item.uuid;
current[part].value = item.value !== undefined ? String(item.value) : '';
current[part].lazy = item.hasChild ?? false;
}
current = current[part].__children;
}
}
function convert(map: TreeMap): TreeNode[] {
return reactive(
Object.entries(map).map(([path, node]) => ({
path,
key: node.uuid ?? path, // `key` is used by QTree
value: node.value,
lazy: node.lazy,
children: convert(node.__children),
})),
);
}
return [
{
path: 'DBM',
key: '00000000-0000-0000-0000-000000000000',
lazy: true,
children: convert(root),
},
];
}
export function getTreeElementByPath(path: string) {
const sub = dbmData.find((s) => s.path === path);
return ref(sub);
}
export function getSubscriptionsByUuid(uid: string) {
const sub = Object.values(Subscriptions).find((sub) => sub.uuid === uid);
return ref(sub);
}
export function addChildrentoTree(subs: Subs) {
const ZERO_UUID = '00000000-0000-0000-0000-000000000000';
const existingIds = new Set(Object.values(Subscriptions).map((sub) => sub.uuid));
const newSubs = subs
.filter((sub) => sub.uuid !== ZERO_UUID) // Skip UUIDs with all zeroes
.filter((sub) => !existingIds.has(sub.uuid));
for (const sub of newSubs) {
if (sub.path !== undefined) {
Subscriptions[sub.path] = sub;
} else {
console.warn('Skipping sub with undefined path', sub);
}
}
void nextTick(() => {
dbmData.splice(0, dbmData.length, ...buildTree(Object.values(Subscriptions)));
});
}
export function removeSubtreeByParentKey(parentKey: string) {
function removeChildrenAndMarkLazy(nodes: TreeNode[], targetKey: string): boolean {
for (const node of nodes) {
if (node.key === targetKey) {
delete node.children;
node.lazy = true;
return true;
}
if (node.children) {
const found = removeChildrenAndMarkLazy(node.children, targetKey);
if (found) return true;
}
}
return false;
}
removeChildrenAndMarkLazy(dbmData, parentKey);
}
export function getSubscriptionsByPath(path: string) {
return ref(Subscriptions[path]);
}
export function getAllSubscriptions() {
return Object.values(Subscriptions);
}
export function updateValue(
path1: string,
$q: QVueGlobals,
toggle?: Ref<boolean>,
path2?: string,
path3?: string,
value3?: number,
) {
return computed({
get() {
const sub = getSubscriptionsByPath(toggle?.value && path2 ? path2 : path1);
const value = sub?.value ? Number(sub.value.value ?? 0) : 0;
return value;
},
set(val) {
const baseValue = val;
const setPaths = [];
if (toggle?.value && path2) {
setPaths.push({ path: path2, value: baseValue });
} else {
setPaths.push({ path: path1, value: baseValue });
}
if (path3) {
setPaths.push({ path: path3, value: value3 ? value3 : baseValue });
}
setValues(setPaths)
.then((response) => NotifyResponse($q, response))
.catch((err) => {
NotifyResponse(
$q,
`Failed to update [${path1 + ' ' + path2 + ' ' + path3}]: ${err}`,
'error',
);
});
},
});
}