implement driver add update remove and improve rename tree experience
This commit is contained in:
@@ -3,10 +3,9 @@ import axios from 'axios';
|
|||||||
|
|
||||||
const host = window.location.hostname;
|
const host = window.location.hostname;
|
||||||
const port = 8100;
|
const port = 8100;
|
||||||
const baseURL = `http://${host}:${port}`;
|
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: baseURL,
|
baseURL: `http://${host}:${port}`,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@@ -4,11 +4,8 @@ import { initWebSocket } from '../vueLib/services/websocket';
|
|||||||
|
|
||||||
export default boot(({ app }) => {
|
export default boot(({ app }) => {
|
||||||
const $q = app.config.globalProperties.$q as QVueGlobals;
|
const $q = app.config.globalProperties.$q as QVueGlobals;
|
||||||
const host = window.location.hostname;
|
|
||||||
const port = 8100;
|
|
||||||
|
|
||||||
const randomId = Math.floor(Math.random() * 10001); // random number from 0 to 10000
|
const ws = initWebSocket(window.location.hostname, 8100, $q);
|
||||||
const ws = initWebSocket(`ws://${host}:${port}/ws?id=q${randomId}`, $q);
|
|
||||||
|
|
||||||
app.config.globalProperties.$socket = ws;
|
app.config.globalProperties.$socket = ws;
|
||||||
ws.connect();
|
ws.connect();
|
||||||
|
@@ -66,18 +66,14 @@ const internalShowDialog = ref(props.showDialog);
|
|||||||
watch(
|
watch(
|
||||||
() => props.showDialog,
|
() => props.showDialog,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
console.log('watch showDialog', newValue);
|
|
||||||
internalShowDialog.value = newValue;
|
internalShowDialog.value = newValue;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
watch(internalShowDialog, (newValue) => {
|
watch(internalShowDialog, (newValue) => {
|
||||||
console.log('watch internalShowDialog', newValue);
|
|
||||||
emit('update:showDialog', newValue);
|
emit('update:showDialog', newValue);
|
||||||
if (!newValue) {
|
if (!newValue) {
|
||||||
console.log('emit cancel');
|
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
} else {
|
} else {
|
||||||
console.log('emit confirmed');
|
|
||||||
emit('confirmed');
|
emit('confirmed');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
'text-left',
|
'text-left',
|
||||||
!props.row.path.includes('System') && props.row.path !== 'DBM'
|
props.row.path?.split(':')[0] !== 'System' && props.row.path !== 'DBM'
|
||||||
? 'cursor-pointer'
|
? 'cursor-pointer'
|
||||||
: '',
|
: '',
|
||||||
'q-mx-sm',
|
'q-mx-sm',
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
'text-center',
|
'text-center',
|
||||||
!props.row.path.includes('System') && props.row.path !== 'DBM'
|
props.row.path?.split(':')[0] !== 'System' && props.row.path !== 'DBM'
|
||||||
? 'cursor-pointer'
|
? 'cursor-pointer'
|
||||||
: '',
|
: '',
|
||||||
'q-mx-sm',
|
'q-mx-sm',
|
||||||
@@ -43,15 +43,18 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-value="props">
|
<template v-slot:body-cell-value="props">
|
||||||
<q-td :props="props" @click="openDialog(props.row)">
|
<q-td :props="props" @click="openDialog(props.row, 'value')">
|
||||||
<div :class="['text-center', 'cursor-pointer', 'q-mx-sm']">
|
<div :class="['text-center', 'cursor-pointer', 'q-mx-sm']">
|
||||||
{{ props.row.value }}
|
{{ props.row.value }}
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-drivers="props">
|
<template v-slot:body-cell-drivers="props">
|
||||||
<q-td :props="props" @click="openDialog(props.row, 'driver')">
|
<q-td :props="props" @click="openDialog(props.row, 'drivers')">
|
||||||
<div v-if="props.row.type !== 'none'" :class="['cursor-pointer']">
|
<div
|
||||||
|
v-if="props.row.type !== 'NONE' || props.row.path?.split(':')[0] !== 'System'"
|
||||||
|
:class="['cursor-pointer']"
|
||||||
|
>
|
||||||
<q-icon size="sm" name="cell_tower" :color="props.row.drivers ? 'blue-5' : 'grey-4'" />
|
<q-icon size="sm" name="cell_tower" :color="props.row.drivers ? 'blue-5' : 'grey-4'" />
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
@@ -59,6 +62,7 @@
|
|||||||
</q-table>
|
</q-table>
|
||||||
<RenameDialog width="400px" button-ok-label="Rename" ref="renameDialog" />
|
<RenameDialog width="400px" button-ok-label="Rename" ref="renameDialog" />
|
||||||
<UpdateDialog width="400px" button-ok-label="Write" ref="updateDialog" />
|
<UpdateDialog width="400px" button-ok-label="Write" ref="updateDialog" />
|
||||||
|
<UpdateDriver width="400px" ref="updateDriverDialog" />
|
||||||
<UpdateDatatype
|
<UpdateDatatype
|
||||||
width="400px"
|
width="400px"
|
||||||
button-ok-label="Update"
|
button-ok-label="Update"
|
||||||
@@ -72,6 +76,7 @@
|
|||||||
import UpdateDialog from './dialog/UpdateValueDialog.vue';
|
import UpdateDialog from './dialog/UpdateValueDialog.vue';
|
||||||
import RenameDialog from './dialog/RenameDatapoint.vue';
|
import RenameDialog from './dialog/RenameDatapoint.vue';
|
||||||
import UpdateDatatype from './dialog/UpdateDatatype.vue';
|
import UpdateDatatype from './dialog/UpdateDatatype.vue';
|
||||||
|
import UpdateDriver from './dialog/UpdateDriverDialog.vue';
|
||||||
import type { QTableProps } from 'quasar';
|
import type { QTableProps } from 'quasar';
|
||||||
import type { Subscribe } from '../models/Subscribe';
|
import type { Subscribe } from '../models/Subscribe';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
@@ -80,10 +85,12 @@ import { convertFromType } from './Datapoint';
|
|||||||
|
|
||||||
const renameDialog = ref();
|
const renameDialog = ref();
|
||||||
const updateDialog = ref();
|
const updateDialog = ref();
|
||||||
|
const updateDriverDialog = ref();
|
||||||
const updateDatatype = ref();
|
const updateDatatype = ref();
|
||||||
|
|
||||||
const openDialog = (sub: Subscribe, type?: string) => {
|
const openDialog = (sub: Subscribe, type?: string) => {
|
||||||
if (sub.path?.includes('System') || sub.path === 'DBM') return;
|
console.log(11, sub);
|
||||||
|
if (sub.path?.split(':')[0] === 'System' && sub.path !== 'DBM') return;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'type':
|
case 'type':
|
||||||
updateDatatype.value.open(sub.uuid);
|
updateDatatype.value.open(sub.uuid);
|
||||||
@@ -91,10 +98,14 @@ const openDialog = (sub: Subscribe, type?: string) => {
|
|||||||
case 'rename':
|
case 'rename':
|
||||||
renameDialog.value.open(sub.uuid);
|
renameDialog.value.open(sub.uuid);
|
||||||
break;
|
break;
|
||||||
default:
|
case 'value':
|
||||||
if (sub.type === 'none') return;
|
if (sub.type === 'NONE') return;
|
||||||
updateDialog.value?.open(ref(sub), type);
|
updateDialog.value?.open(ref(sub), type);
|
||||||
break;
|
break;
|
||||||
|
case 'drivers':
|
||||||
|
if (sub.type === 'NONE') return;
|
||||||
|
updateDriverDialog.value?.open(sub);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
class="q-mt-lg q-mb-none q-pl-lg q-pr-xl"
|
class="q-mt-lg q-mb-none q-pl-lg q-pr-xl"
|
||||||
filled
|
filled
|
||||||
v-model="path"
|
v-model="addingForm.path"
|
||||||
label=""
|
label=""
|
||||||
:rules="[(val) => !!val || 'Path is required']"
|
:rules="[(val) => !!val || 'Path is required']"
|
||||||
>
|
>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<span class="text-caption text-primary non-editable-prefix">Path *</span>
|
<span class="text-caption text-primary non-editable-prefix">Path *</span>
|
||||||
<span class="text-body2 text-grey-6 non-editable-prefix"
|
<span class="text-body2 text-grey-6 non-editable-prefix"
|
||||||
>{{ prefix }}{{ staticPrefix }}</span
|
>{{ addingForm.prefix }}{{ addingForm.staticPrefix }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
<DataTypes class="q-mt-lg q-pl-md q-pr-xl" flat v-model:datatype="datatype"></DataTypes>
|
<DataTypes class="q-mt-lg q-pl-md q-pr-xl" flat v-model:datatype="datatype"></DataTypes>
|
||||||
<div class="q-pl-lg">
|
<div class="q-pl-lg">
|
||||||
<div class="text-grey text-bold">Read Write Access</div>
|
<div class="text-grey text-bold">Read Write Access</div>
|
||||||
<q-checkbox v-model="read">Read</q-checkbox>
|
<q-checkbox v-model="addingForm.read">Read</q-checkbox>
|
||||||
<q-checkbox v-model="write">Write</q-checkbox>
|
<q-checkbox v-model="addingForm.write">Write</q-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<q-input
|
<q-input
|
||||||
:type="valueType"
|
:type="valueType"
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
label="Value"
|
label="Value"
|
||||||
class="q-pl-md q-pr-xl"
|
class="q-pl-md q-pr-xl"
|
||||||
filled
|
filled
|
||||||
v-model="value"
|
v-model="addingForm.value"
|
||||||
></q-input>
|
></q-input>
|
||||||
<q-btn no-caps class="q-mb-xl q-mx-xl q-px-lg" @click="onSubmit" color="primary">{{
|
<q-btn no-caps class="q-mb-xl q-mx-xl q-px-lg" @click="onSubmit" color="primary">{{
|
||||||
props.buttonOkLabel
|
props.buttonOkLabel
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import DialogFrame from '../../dialog/DialogFrame.vue';
|
import DialogFrame from '../../dialog/DialogFrame.vue';
|
||||||
import { useNotify } from '../../general/useNotify';
|
import { useNotify } from '../../general/useNotify';
|
||||||
import DataTypes from '../../buttons/DataTypes.vue';
|
import DataTypes from '../../buttons/DataTypes.vue';
|
||||||
@@ -56,16 +56,21 @@ import { convertToType } from '../Datapoint';
|
|||||||
import { catchError } from 'src/vueLib/models/error';
|
import { catchError } from 'src/vueLib/models/error';
|
||||||
|
|
||||||
const { NotifyResponse } = useNotify();
|
const { NotifyResponse } = useNotify();
|
||||||
|
|
||||||
|
const addingForm = reactive({
|
||||||
|
path: '',
|
||||||
|
value: '',
|
||||||
|
staticPrefix: '',
|
||||||
|
read: true,
|
||||||
|
write: true,
|
||||||
|
prefix: 'DBM:',
|
||||||
|
});
|
||||||
const Dialog = ref();
|
const Dialog = ref();
|
||||||
const path = ref('');
|
|
||||||
const staticPrefix = ref('');
|
|
||||||
const value = ref('');
|
|
||||||
const valueType = ref<'text' | 'number'>('text');
|
const valueType = ref<'text' | 'number'>('text');
|
||||||
const read = ref(true);
|
|
||||||
const write = ref(true);
|
|
||||||
const datatype = ref('None');
|
const datatype = ref('None');
|
||||||
const addForm = ref();
|
const addForm = ref();
|
||||||
const prefix = 'DBM:';
|
|
||||||
|
|
||||||
const open = (uuid: string) => {
|
const open = (uuid: string) => {
|
||||||
Dialog.value?.open();
|
Dialog.value?.open();
|
||||||
@@ -84,15 +89,15 @@ function onSubmit() {
|
|||||||
if (success) {
|
if (success) {
|
||||||
type = convertToType(datatype.value);
|
type = convertToType(datatype.value);
|
||||||
|
|
||||||
if (read.value) access = 'R';
|
if (addingForm.read) access = 'R';
|
||||||
if (write.value) access += 'W';
|
if (addingForm.write) access += 'W';
|
||||||
if (access == '') access = 'R';
|
if (access == '') access = 'R';
|
||||||
|
|
||||||
setRequest(staticPrefix.value + path.value, type, value.value, access)
|
setRequest(addingForm.staticPrefix + addingForm.path, type, addingForm.value, access)
|
||||||
.then((respond) => {
|
.then((respond) => {
|
||||||
if (respond) {
|
if (respond) {
|
||||||
respond.forEach((set) => {
|
respond.forEach((set) => {
|
||||||
NotifyResponse("Datapoint '" + prefix + set.path + "' added");
|
NotifyResponse("Datapoint '" + addingForm.prefix + set.path + "' added");
|
||||||
});
|
});
|
||||||
addRawSubscription(respond[0]);
|
addRawSubscription(respond[0]);
|
||||||
UpdateTable();
|
UpdateTable();
|
||||||
@@ -102,7 +107,7 @@ function onSubmit() {
|
|||||||
NotifyResponse(catchError(err), 'error');
|
NotifyResponse(catchError(err), 'error');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (path.value === '') {
|
if (addingForm.path === '') {
|
||||||
NotifyResponse("Field 'Path' is requierd", 'error');
|
NotifyResponse("Field 'Path' is requierd", 'error');
|
||||||
return;
|
return;
|
||||||
} else NotifyResponse('Form not validated', 'error');
|
} else NotifyResponse('Form not validated', 'error');
|
||||||
@@ -133,8 +138,8 @@ function getDatapoint(uuid: string) {
|
|||||||
getRequest(uuid, '', 1)
|
getRequest(uuid, '', 1)
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
if (resp[0]) {
|
if (resp[0]) {
|
||||||
staticPrefix.value = resp[0].path ?? '';
|
addingForm.staticPrefix = resp[0].path ?? '';
|
||||||
if (staticPrefix.value !== '') staticPrefix.value += ':';
|
if (addingForm.staticPrefix !== '') addingForm.staticPrefix += ':';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
class="q-mt-lg q-mb-none q-pl-md q-mx-lg"
|
class="q-mt-lg q-mb-none q-pl-md q-mx-lg"
|
||||||
filled
|
filled
|
||||||
v-model="path"
|
v-model="copyData.path"
|
||||||
label="Current Path"
|
label="Current Path"
|
||||||
label-color="primary"
|
label-color="primary"
|
||||||
readonly
|
readonly
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
class="q-mt-lg q-mt-none q-pl-md q-mx-lg"
|
class="q-mt-lg q-mt-none q-pl-md q-mx-lg"
|
||||||
filled
|
filled
|
||||||
v-model="copyPath"
|
v-model="copyData.copyPath"
|
||||||
label="New Path *"
|
label="New Path *"
|
||||||
label-color="primary"
|
label-color="primary"
|
||||||
@keyup.enter="onSubmit"
|
@keyup.enter="onSubmit"
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import DialogFrame from '../../dialog/DialogFrame.vue';
|
import DialogFrame from '../../dialog/DialogFrame.vue';
|
||||||
import { useNotify } from '../../general/useNotify';
|
import { useNotify } from '../../general/useNotify';
|
||||||
import { getRequest, setsRequest } from 'src/vueLib/models/Request';
|
import { getRequest, setsRequest } from 'src/vueLib/models/Request';
|
||||||
@@ -44,11 +44,14 @@ import { datapointRequestForCopy } from '../Datapoint';
|
|||||||
import { catchError } from 'src/vueLib/models/error';
|
import { catchError } from 'src/vueLib/models/error';
|
||||||
|
|
||||||
const { NotifyResponse } = useNotify();
|
const { NotifyResponse } = useNotify();
|
||||||
|
const copyData = reactive({
|
||||||
|
path: '',
|
||||||
|
copyPath: '',
|
||||||
|
prefix: 'DBM:',
|
||||||
|
});
|
||||||
|
|
||||||
const Dialog = ref();
|
const Dialog = ref();
|
||||||
const path = ref('');
|
|
||||||
const copyPath = ref('');
|
|
||||||
const copyForm = ref();
|
const copyForm = ref();
|
||||||
const prefix = 'DBM:';
|
|
||||||
|
|
||||||
const open = (uuid: string) => {
|
const open = (uuid: string) => {
|
||||||
Dialog.value?.open();
|
Dialog.value?.open();
|
||||||
@@ -58,18 +61,18 @@ const open = (uuid: string) => {
|
|||||||
function onSubmit() {
|
function onSubmit() {
|
||||||
copyForm.value.validate().then((success: undefined) => {
|
copyForm.value.validate().then((success: undefined) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
if (copyPath.value === path.value) {
|
if (copyData.copyPath === copyData.path) {
|
||||||
NotifyResponse('copy path can not be the same as current path', 'error');
|
NotifyResponse('copy path can not be the same as current path', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const absolutePath = path.value.slice(prefix.length);
|
const absolutePath = copyData.path.slice(copyData.prefix.length);
|
||||||
const absolutecopyPath = copyPath.value.slice(prefix.length);
|
const absolutecopyPath = copyData.copyPath.slice(copyData.prefix.length);
|
||||||
|
|
||||||
getRequest('', absolutecopyPath, 1)
|
getRequest('', absolutecopyPath, 1)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response?.length > 0) {
|
if (response?.length > 0) {
|
||||||
NotifyResponse("path '" + copyPath.value + "' already exists", 'warning');
|
NotifyResponse("path '" + copyData.copyPath + "' already exists", 'warning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -80,7 +83,7 @@ function onSubmit() {
|
|||||||
setsRequest(
|
setsRequest(
|
||||||
datapointRequestForCopy(response, absolutePath, absolutecopyPath),
|
datapointRequestForCopy(response, absolutePath, absolutecopyPath),
|
||||||
).catch((err) => console.error(err));
|
).catch((err) => console.error(err));
|
||||||
NotifyResponse(copyPath.value + ' copied');
|
NotifyResponse(copyData.copyPath + ' copied');
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
||||||
} else {
|
} else {
|
||||||
@@ -89,7 +92,7 @@ function onSubmit() {
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (copyPath.value === '') {
|
if (copyData.copyPath === '') {
|
||||||
NotifyResponse("Field 'New Path' is requierd", 'error');
|
NotifyResponse("Field 'New Path' is requierd", 'error');
|
||||||
return;
|
return;
|
||||||
} else NotifyResponse('Form not validated', 'error');
|
} else NotifyResponse('Form not validated', 'error');
|
||||||
@@ -120,8 +123,8 @@ function getDatapoint(uuid: string) {
|
|||||||
getRequest(uuid)
|
getRequest(uuid)
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
if (resp[0]) {
|
if (resp[0]) {
|
||||||
path.value = prefix + resp[0].path;
|
copyData.path = copyData.prefix + resp[0].path;
|
||||||
copyPath.value = prefix + resp[0].path;
|
copyData.copyPath = copyData.prefix + resp[0].path;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
||||||
|
226
src/vueLib/dbm/dialog/DriverDialog.vue
Normal file
226
src/vueLib/dbm/dialog/DriverDialog.vue
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<template>
|
||||||
|
<DialogFrame ref="Dialog" :width="props.width" :header-title="localDialogLabel">
|
||||||
|
<q-card-section
|
||||||
|
v-if="props.dialogLabel || localDialogLabel"
|
||||||
|
class="text-bold text-left q-mb-none q-pb-none"
|
||||||
|
:class="'text-' + props.labelColor"
|
||||||
|
>{{ props.dialogLabel || localDialogLabel }}</q-card-section
|
||||||
|
>
|
||||||
|
<q-card-section v-if="props.text" class="text-center" style="white-space: pre-line">{{
|
||||||
|
props.text
|
||||||
|
}}</q-card-section>
|
||||||
|
<q-form ref="form">
|
||||||
|
<q-card-section class="q-gutter-xs row q-col-gutter-xs">
|
||||||
|
<div>
|
||||||
|
<q-select
|
||||||
|
class="col-8"
|
||||||
|
filled
|
||||||
|
label="Driver Name"
|
||||||
|
type="text"
|
||||||
|
name="Type"
|
||||||
|
dense
|
||||||
|
:options="options"
|
||||||
|
:rules="[(val) => !!val || 'Name is required']"
|
||||||
|
v-model="driverForm.type"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
class="col-8"
|
||||||
|
filled
|
||||||
|
label="Bus"
|
||||||
|
type="text"
|
||||||
|
name="Bus"
|
||||||
|
dense
|
||||||
|
:rules="[(val) => !!val || 'Bus is required']"
|
||||||
|
v-model="driverForm.bus"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-if="driverForm.isAddress"
|
||||||
|
class="col-8"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
label="Address"
|
||||||
|
type="number"
|
||||||
|
name="Address"
|
||||||
|
v-model.number="driverForm.address"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="!driverForm.isAddress" class="q-gutter-xs row q-col-gutter-xs">
|
||||||
|
<q-input
|
||||||
|
class="col-8"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
label="Subscribe"
|
||||||
|
type="text"
|
||||||
|
name="Address"
|
||||||
|
v-model="driverForm.subscribe"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
class="col-8"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
label="Publish"
|
||||||
|
type="text"
|
||||||
|
name="Address"
|
||||||
|
v-model="driverForm.publish"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-form>
|
||||||
|
<q-card-actions class="text-primary">
|
||||||
|
<q-btn v-if="props.buttonCancelLabel" flat :label="props.buttonCancelLabel" v-close-popup />
|
||||||
|
<q-btn
|
||||||
|
class="q-mb-xl q-ml-lg q-px-lg"
|
||||||
|
v-if="props.buttonOkLabel"
|
||||||
|
color="primary"
|
||||||
|
no-caps
|
||||||
|
:label="props.buttonOkLabel"
|
||||||
|
@click="updateDriver"
|
||||||
|
>
|
||||||
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</DialogFrame>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, watch } from 'vue';
|
||||||
|
import DialogFrame from '../../dialog/DialogFrame.vue';
|
||||||
|
import type { Driver } from '../../models/Drivers';
|
||||||
|
import { setRequest } from 'src/vueLib/models/Request';
|
||||||
|
import { addRawSubscriptions } from 'src/vueLib/models/Subscriptions';
|
||||||
|
import { convertToSubscribe, type RawSubs } from 'src/vueLib/models/Subscribe';
|
||||||
|
import { useNotify } from 'src/vueLib/general/useNotify';
|
||||||
|
import { UpdateTable } from '../updateTable';
|
||||||
|
import { updateDriverTable, type DriverTableRow } from 'src/vueLib/models/driverTable';
|
||||||
|
|
||||||
|
const { NotifyResponse } = useNotify();
|
||||||
|
|
||||||
|
const Dialog = ref();
|
||||||
|
const options = ['ArtNetDriver', 'OSCDriver'];
|
||||||
|
const driverForm = reactive({
|
||||||
|
type: 'ArtNetDriver',
|
||||||
|
bus: '',
|
||||||
|
isAddress: true,
|
||||||
|
address: 0,
|
||||||
|
subscribe: '',
|
||||||
|
publish: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
buttonOkLabel: {
|
||||||
|
type: String,
|
||||||
|
default: 'OK',
|
||||||
|
},
|
||||||
|
labelColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary',
|
||||||
|
},
|
||||||
|
dialogLabel: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
buttonCancelLabel: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '300px',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const localDialogLabel = ref('');
|
||||||
|
const driver = ref<Driver>();
|
||||||
|
let dpUuid = '';
|
||||||
|
const form = ref();
|
||||||
|
const address = ref();
|
||||||
|
const topic = ref();
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => driverForm.type,
|
||||||
|
(val) => {
|
||||||
|
driverForm.isAddress = val === options[0];
|
||||||
|
if (driverForm.isAddress) {
|
||||||
|
driverForm.subscribe = '';
|
||||||
|
driverForm.publish = '';
|
||||||
|
topic.value = undefined;
|
||||||
|
} else {
|
||||||
|
driverForm.address = -1;
|
||||||
|
address.value = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const open = (uuid: string, drvs: DriverTableRow, type: 'add' | 'edit') => {
|
||||||
|
switch (type) {
|
||||||
|
case 'add':
|
||||||
|
localDialogLabel.value = 'Add Driver';
|
||||||
|
driverForm.type = 'ArtNetDriver';
|
||||||
|
driverForm.isAddress = true;
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
localDialogLabel.value = 'Edit Driver';
|
||||||
|
driverForm.type = drvs.type;
|
||||||
|
driverForm.bus = drvs.bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpUuid = uuid;
|
||||||
|
driver.value = drvs;
|
||||||
|
|
||||||
|
if (drvs.address) driverForm.address = drvs.address;
|
||||||
|
if (drvs.subscribe) driverForm.subscribe = drvs.subscribe;
|
||||||
|
if (drvs.publish) driverForm.publish = drvs.publish;
|
||||||
|
|
||||||
|
Dialog.value?.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateDriver() {
|
||||||
|
form.value?.validate();
|
||||||
|
if (!driverForm.type || !driverForm.bus) {
|
||||||
|
NotifyResponse('Please fill in all required fields', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (driverForm.address > -1) {
|
||||||
|
address.value = [driverForm.address];
|
||||||
|
}
|
||||||
|
if (driverForm.subscribe !== '' || driverForm.publish !== '') {
|
||||||
|
topic.value = { subscribe: [driverForm.subscribe], publish: [driverForm.publish] };
|
||||||
|
}
|
||||||
|
|
||||||
|
setRequest('', undefined, undefined, undefined, dpUuid, {
|
||||||
|
type: driverForm.type,
|
||||||
|
buses: [
|
||||||
|
{
|
||||||
|
name: driverForm.bus,
|
||||||
|
address: address.value,
|
||||||
|
topic: topic.value,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.then((resp) => {
|
||||||
|
addRawSubscriptions(resp as RawSubs);
|
||||||
|
|
||||||
|
resp.forEach((set) => {
|
||||||
|
updateDriverTable(convertToSubscribe(set));
|
||||||
|
});
|
||||||
|
|
||||||
|
UpdateTable();
|
||||||
|
Dialog.value.close();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
NotifyResponse(err, 'error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.outercard {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -10,7 +10,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
class="q-mt-lg q-mb-none q-pl-md q-mx-lg"
|
class="q-mt-lg q-mb-none q-pl-md q-mx-lg"
|
||||||
filled
|
filled
|
||||||
v-model="path"
|
v-model="removeData.path"
|
||||||
label="Current Path"
|
label="Current Path"
|
||||||
label-color="primary"
|
label-color="primary"
|
||||||
readonly
|
readonly
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
class="q-mt-lg q-mt-none q-pl-md q-mx-lg"
|
class="q-mt-lg q-mt-none q-pl-md q-mx-lg"
|
||||||
filled
|
filled
|
||||||
v-model="newPath"
|
v-model="removeData.newPath"
|
||||||
label="New Path *"
|
label="New Path *"
|
||||||
label-color="primary"
|
label-color="primary"
|
||||||
@keyup.enter="onSubmit"
|
@keyup.enter="onSubmit"
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import DialogFrame from '../../dialog/DialogFrame.vue';
|
import DialogFrame from '../../dialog/DialogFrame.vue';
|
||||||
import { useNotify } from '../../general/useNotify';
|
import { useNotify } from '../../general/useNotify';
|
||||||
import { getRequest, setRequest } from 'src/vueLib/models/Request';
|
import { getRequest, setRequest } from 'src/vueLib/models/Request';
|
||||||
@@ -49,10 +49,13 @@ import { buildTree } from '../dbmTree';
|
|||||||
const { NotifyResponse } = useNotify();
|
const { NotifyResponse } = useNotify();
|
||||||
const Dialog = ref();
|
const Dialog = ref();
|
||||||
const datapoint = ref();
|
const datapoint = ref();
|
||||||
const path = ref('');
|
const removeData = reactive({
|
||||||
const newPath = ref('');
|
path: '',
|
||||||
|
newPath: '',
|
||||||
|
prefix: 'DBM:',
|
||||||
|
});
|
||||||
|
|
||||||
const copyForm = ref();
|
const copyForm = ref();
|
||||||
const prefix = 'DBM:';
|
|
||||||
|
|
||||||
const open = (uuid: string) => {
|
const open = (uuid: string) => {
|
||||||
Dialog.value?.open();
|
Dialog.value?.open();
|
||||||
@@ -62,14 +65,13 @@ const open = (uuid: string) => {
|
|||||||
function onSubmit() {
|
function onSubmit() {
|
||||||
copyForm.value.validate().then((success: undefined) => {
|
copyForm.value.validate().then((success: undefined) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
if (newPath.value === path.value) {
|
if (removeData.newPath === removeData.path) {
|
||||||
NotifyResponse('same name', 'warning');
|
NotifyResponse('same name', 'warning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRequest('', newPath.value.slice(prefix.length), 1)
|
getRequest('', removeData.newPath.slice(removeData.prefix.length), 1)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log(10, response);
|
|
||||||
if (response?.length > 0) {
|
if (response?.length > 0) {
|
||||||
NotifyResponse("path '" + response[0]?.path + "' already exists", 'warning');
|
NotifyResponse("path '" + response[0]?.path + "' already exists", 'warning');
|
||||||
return;
|
return;
|
||||||
@@ -83,22 +85,24 @@ function onSubmit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRequest(
|
setRequest(
|
||||||
newPath.value.slice(prefix.length),
|
removeData.newPath.slice(removeData.prefix.length),
|
||||||
datapoint.value.type,
|
datapoint.value.type,
|
||||||
datapoint.value.value,
|
datapoint.value.value,
|
||||||
datapoint.value.rights,
|
datapoint.value.rights,
|
||||||
datapoint.value.uuid,
|
datapoint.value.uuid,
|
||||||
|
undefined,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
addRawSubscriptions(res as RawSubs);
|
addRawSubscriptions(res as RawSubs);
|
||||||
|
console.log(80, res);
|
||||||
buildTree(convertToSubscribes(res as RawSubs));
|
buildTree(convertToSubscribes(res as RawSubs));
|
||||||
UpdateTable();
|
UpdateTable();
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(err, 'error'));
|
.catch((err) => NotifyResponse(err, 'error'));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (newPath.value === '') {
|
if (removeData.newPath === '') {
|
||||||
NotifyResponse("Field 'New Path' is requierd", 'error');
|
NotifyResponse("Field 'New Path' is requierd", 'error');
|
||||||
return;
|
return;
|
||||||
} else NotifyResponse('Form not validated', 'error');
|
} else NotifyResponse('Form not validated', 'error');
|
||||||
@@ -130,8 +134,8 @@ function getDatapoint(uuid: string) {
|
|||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
if (resp[0]) {
|
if (resp[0]) {
|
||||||
datapoint.value = resp[0];
|
datapoint.value = resp[0];
|
||||||
path.value = prefix + resp[0].path;
|
removeData.path = removeData.prefix + resp[0].path;
|
||||||
newPath.value = prefix + resp[0].path;
|
removeData.newPath = removeData.prefix + resp[0].path;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
.catch((err) => NotifyResponse(catchError(err), 'error'));
|
||||||
|
199
src/vueLib/dbm/dialog/UpdateDriverDialog.vue
Normal file
199
src/vueLib/dbm/dialog/UpdateDriverDialog.vue
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<DialogFrame ref="Dialog" :width="props.width" :header-title="datapoint?.path">
|
||||||
|
<q-card-section
|
||||||
|
v-if="props.dialogLabel || localDialogLabel"
|
||||||
|
class="text-bold text-left q-mb-none q-pb-none"
|
||||||
|
:class="'text-' + props.labelColor"
|
||||||
|
>{{ props.dialogLabel || localDialogLabel }}</q-card-section
|
||||||
|
>
|
||||||
|
<q-card-section>
|
||||||
|
<q-table
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
virtual-scroll
|
||||||
|
:rows-per-page-options="[0]"
|
||||||
|
:rows="drivers"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="type"
|
||||||
|
>
|
||||||
|
<!-- add symbol on top right of table-->
|
||||||
|
<template v-slot:top-right>
|
||||||
|
<q-btn
|
||||||
|
size="sm"
|
||||||
|
ripple
|
||||||
|
rounded
|
||||||
|
color="primary"
|
||||||
|
icon="add"
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
@click="handleRow(driver, 'add')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-slot:body-cell-settings="props">
|
||||||
|
<q-td :props="props" class="cursor-pointer">
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
size="sm"
|
||||||
|
icon="more_vert"
|
||||||
|
@click="(evt) => openSubMenu(evt, props.row)"
|
||||||
|
></q-btn>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
<q-menu ref="contextMenuRef" context-menu>
|
||||||
|
<q-list>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section class="cursor-pointer" @click="handleRow(driver, 'edit')">
|
||||||
|
Edit
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section class="text-negative cursor-pointer" @click="deleteDriver(driver)">
|
||||||
|
Delete
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section v-if="props.text" class="text-center" style="white-space: pre-line">{{
|
||||||
|
props.text
|
||||||
|
}}</q-card-section>
|
||||||
|
<q-card-actions align="left" class="text-primary">
|
||||||
|
<q-btn v-if="props.buttonCancelLabel" flat :label="props.buttonCancelLabel" v-close-popup>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
class="q-mb-xl q-ml-lg q-mt-none"
|
||||||
|
v-if="props.buttonOkLabel"
|
||||||
|
color="primary"
|
||||||
|
no-caps
|
||||||
|
:label="props.buttonOkLabel"
|
||||||
|
v-close-popup
|
||||||
|
>
|
||||||
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</DialogFrame>
|
||||||
|
<DriverDialog :button-ok-label="driverOkLabel" ref="driverDialog"></DriverDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import DialogFrame from '../../dialog/DialogFrame.vue';
|
||||||
|
import DriverDialog from './DriverDialog.vue';
|
||||||
|
import { convertToSubscribe, type Subscribe } from '../../models/Subscribe';
|
||||||
|
import type { Driver } from '../../models/Drivers';
|
||||||
|
import { driverDefault } from '../../models/Drivers';
|
||||||
|
import type { DriverTableRow } from 'src/vueLib/models/driverTable';
|
||||||
|
import { updateDriverTable, useDriverTable } from 'src/vueLib/models/driverTable';
|
||||||
|
import { deleteRequest } from 'src/vueLib/models/Request';
|
||||||
|
import { useNotify } from 'src/vueLib/general/useNotify';
|
||||||
|
import type { Bus } from 'src/vueLib/models/Bus';
|
||||||
|
|
||||||
|
const { NotifyResponse } = useNotify();
|
||||||
|
const Dialog = ref();
|
||||||
|
const driverDialog = ref();
|
||||||
|
const writeValue = ref();
|
||||||
|
const onlyRead = ref(false);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
buttonOkLabel: {
|
||||||
|
type: String,
|
||||||
|
default: 'OK',
|
||||||
|
},
|
||||||
|
labelColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary',
|
||||||
|
},
|
||||||
|
dialogLabel: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
buttonCancelLabel: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '300px',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const datapoint = ref();
|
||||||
|
const localDialogLabel = ref('');
|
||||||
|
const contextMenuRef = ref();
|
||||||
|
const table = useDriverTable();
|
||||||
|
const drivers = table.driverTable;
|
||||||
|
const driver: Driver = { type: '' };
|
||||||
|
const driverOkLabel = ref('');
|
||||||
|
const columns = table.columns;
|
||||||
|
|
||||||
|
const open = (sub: Subscribe) => {
|
||||||
|
datapoint.value = sub;
|
||||||
|
if (datapoint.value.rights == 'R') onlyRead.value = true;
|
||||||
|
table.emptyTable();
|
||||||
|
|
||||||
|
localDialogLabel.value = 'Update Drivers';
|
||||||
|
updateDriverTable(sub);
|
||||||
|
|
||||||
|
writeValue.value = sub.drivers;
|
||||||
|
Dialog.value?.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
function openSubMenu(evt: Event, d: DriverTableRow) {
|
||||||
|
if (d) {
|
||||||
|
const bus: Bus = {
|
||||||
|
name: d.bus,
|
||||||
|
};
|
||||||
|
bus.name = d.bus;
|
||||||
|
if (d.address) bus.address = d.address !== undefined ? [d.address] : [];
|
||||||
|
if (d.subscribe || d.publish)
|
||||||
|
bus.topic = {
|
||||||
|
subscribe:
|
||||||
|
typeof d.subscribe === 'string' ? d.subscribe.split(',').map((s) => s.trim()) : [],
|
||||||
|
publish: typeof d.publish === 'string' ? d.publish.split(',').map((s) => s.trim()) : [],
|
||||||
|
};
|
||||||
|
|
||||||
|
driver.type = d.type;
|
||||||
|
driver.buses = [bus];
|
||||||
|
}
|
||||||
|
const mouseEvent = evt as MouseEvent;
|
||||||
|
contextMenuRef.value?.show(mouseEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRow(driver: Driver | undefined, type: 'add' | 'edit') {
|
||||||
|
driverOkLabel.value = 'Add';
|
||||||
|
switch (type) {
|
||||||
|
case 'add':
|
||||||
|
driver = driverDefault;
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
driverOkLabel.value = 'Update';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
driverDialog.value?.open(datapoint.value.uuid, driver, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteDriver(driver: Driver | undefined) {
|
||||||
|
deleteRequest(datapoint.value.uuid, '', driver)
|
||||||
|
.then((resp) => {
|
||||||
|
resp.forEach((set) => {
|
||||||
|
updateDriverTable(convertToSubscribe(set));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
NotifyResponse(err, 'error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.outercard {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -6,7 +6,7 @@
|
|||||||
:class="'text-' + props.labelColor"
|
:class="'text-' + props.labelColor"
|
||||||
>{{ props.dialogLabel ? props.dialogLabel : localDialogLabel }}</q-card-section
|
>{{ props.dialogLabel ? props.dialogLabel : localDialogLabel }}</q-card-section
|
||||||
>
|
>
|
||||||
<q-card-section v-if="drivers && drivers.length == 0">
|
<q-card-section v-if="datapoint.type !== 'BIT'">
|
||||||
<q-input
|
<q-input
|
||||||
class="q-px-md q-ma-sm"
|
class="q-px-md q-ma-sm"
|
||||||
label="current value"
|
label="current value"
|
||||||
@@ -27,15 +27,20 @@
|
|||||||
></q-input>
|
></q-input>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section v-else>
|
<q-card-section v-else>
|
||||||
<q-table
|
<div class="column q-pr-xs q-ma-sm">
|
||||||
flat
|
<div class="row items-center q-gutter-sm">
|
||||||
dense
|
<div>current value</div>
|
||||||
virtual-scroll
|
<div class="row items-left">
|
||||||
:rows-per-page-options="[0]"
|
<q-toggle class="readonly-toggle" left-label v-model="inputValue"></q-toggle>
|
||||||
:rows="drivers"
|
</div>
|
||||||
:columns="columns"
|
</div>
|
||||||
>
|
<div class="row items-center q-gutter-lg">
|
||||||
</q-table>
|
<div>new value</div>
|
||||||
|
<div class="row items-left">
|
||||||
|
<q-toggle left-label v-model="writeValue"></q-toggle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section v-if="props.text" class="text-center" style="white-space: pre-line">{{
|
<q-card-section v-if="props.text" class="text-center" style="white-space: pre-line">{{
|
||||||
props.text
|
props.text
|
||||||
@@ -63,15 +68,16 @@ import type { Subscribe } from '../../models/Subscribe';
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { setValues } from '../../services/websocket';
|
import { setValues } from '../../services/websocket';
|
||||||
import { useNotify } from '../../general/useNotify';
|
import { useNotify } from '../../general/useNotify';
|
||||||
import type { QTableProps } from 'quasar';
|
|
||||||
import type { Driver } from '../../models/Drivers';
|
|
||||||
import { catchError } from 'src/vueLib/models/error';
|
import { catchError } from 'src/vueLib/models/error';
|
||||||
|
|
||||||
const { NotifyResponse } = useNotify();
|
const { NotifyResponse } = useNotify();
|
||||||
const Dialog = ref();
|
const Dialog = ref();
|
||||||
|
const localDialogLabel = ref('');
|
||||||
const writeValue = ref();
|
const writeValue = ref();
|
||||||
const onlyRead = ref(false);
|
const onlyRead = ref(false);
|
||||||
const writeType = ref<'text' | 'number'>('text');
|
const writeType = ref<'text' | 'number'>('text');
|
||||||
|
const datapoint = ref();
|
||||||
|
const inputValue = ref(datapoint?.value);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
buttonOkLabel: {
|
buttonOkLabel: {
|
||||||
@@ -100,33 +106,14 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const datapoint = ref();
|
const open = (sub: Ref<Subscribe>) => {
|
||||||
const inputValue = ref(datapoint?.value);
|
|
||||||
const localDialogLabel = ref('');
|
|
||||||
const drivers = ref<Driver[]>([]);
|
|
||||||
const columns = [
|
|
||||||
{ name: 'type', label: 'Driver Name', field: 'type', align: 'left' },
|
|
||||||
{ name: 'bus', label: 'Bus Name', field: 'bus', align: 'center' },
|
|
||||||
{ name: 'address', label: 'Address', field: 'address', align: 'center' },
|
|
||||||
] as QTableProps['columns'];
|
|
||||||
|
|
||||||
const open = (sub: Ref<Subscribe>, type?: string) => {
|
|
||||||
datapoint.value = sub.value;
|
datapoint.value = sub.value;
|
||||||
if (datapoint.value.rights == 'R') onlyRead.value = true;
|
if (datapoint.value.rights == 'R') onlyRead.value = true;
|
||||||
drivers.value = [];
|
localDialogLabel.value = 'Update Value';
|
||||||
switch (type) {
|
if (sub.value.type === 'STR') writeType.value = 'text';
|
||||||
case 'driver':
|
else writeType.value = 'number';
|
||||||
localDialogLabel.value = 'Update Drivers';
|
writeValue.value = sub.value.value;
|
||||||
if (sub.value.drivers) drivers.value = Object.values(sub.value.drivers);
|
|
||||||
writeValue.value = sub.value.drivers;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
localDialogLabel.value = 'Update Value';
|
|
||||||
if (sub.value.type === 'STR') writeType.value = 'text';
|
|
||||||
else if (sub.value.type === 'BIT') writeType.value = 'text';
|
|
||||||
else writeType.value = 'number';
|
|
||||||
writeValue.value = sub.value.value;
|
|
||||||
}
|
|
||||||
Dialog.value?.open();
|
Dialog.value?.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,4 +143,8 @@ defineExpose({ open });
|
|||||||
.outercard {
|
.outercard {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
.readonly-toggle {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
7
src/vueLib/models/Bus.ts
Normal file
7
src/vueLib/models/Bus.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { Topic } from './Topic';
|
||||||
|
|
||||||
|
export interface Bus {
|
||||||
|
name: string;
|
||||||
|
address?: number[];
|
||||||
|
topic?: Topic;
|
||||||
|
}
|
@@ -1,5 +1,9 @@
|
|||||||
|
import type { Bus } from './Bus';
|
||||||
export interface Driver {
|
export interface Driver {
|
||||||
type: string;
|
type: string;
|
||||||
addess: number;
|
buses?: Bus[];
|
||||||
value: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const driverDefault = <Driver>{
|
||||||
|
type: '',
|
||||||
|
};
|
||||||
|
@@ -1,14 +1,21 @@
|
|||||||
|
import type { Driver } from './Drivers';
|
||||||
export type Publish = {
|
export type Publish = {
|
||||||
event: string;
|
event: string;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
path: string;
|
path: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
drivers?: Record<string, Driver>;
|
||||||
value: string | number | boolean | null;
|
value: string | number | boolean | null;
|
||||||
hasChild: boolean;
|
hasChild: boolean;
|
||||||
};
|
};
|
||||||
export type Pubs = Publish[];
|
export type Pubs = Publish[];
|
||||||
|
|
||||||
import { updateSubscriptionValue, removeRawSubscriptions } from './Subscriptions';
|
import {
|
||||||
|
updateSubscriptionValue,
|
||||||
|
removeRawSubscriptions,
|
||||||
|
addRawSubscription,
|
||||||
|
removeRawSubscription,
|
||||||
|
} from './Subscriptions';
|
||||||
import { buildTree, buildTreeWithRawSubs, removeNodes } from '../dbm/dbmTree';
|
import { buildTree, buildTreeWithRawSubs, removeNodes } from '../dbm/dbmTree';
|
||||||
import type { RawSubs, RawSubscribe } from '../models/Subscribe';
|
import type { RawSubs, RawSubscribe } from '../models/Subscribe';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
@@ -33,6 +40,11 @@ export function publishToSubscriptions(pubs: Pubs) {
|
|||||||
rawSubs.value.push(pub as RawSubscribe);
|
rawSubs.value.push(pub as RawSubscribe);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (pub.drivers) {
|
||||||
|
removeRawSubscription(pub as RawSubscribe);
|
||||||
|
addRawSubscription(pub as RawSubscribe);
|
||||||
|
UpdateTable();
|
||||||
|
}
|
||||||
updateSubscriptionValue(pub.uuid, pub.value);
|
updateSubscriptionValue(pub.uuid, pub.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Driver } from './Drivers';
|
||||||
import type { Gets } from './Get';
|
import type { Gets } from './Get';
|
||||||
import type { Sets } from './Set';
|
import type { Sets } from './Set';
|
||||||
import type { Subs } from './Subscribe';
|
import type { Subs } from './Subscribe';
|
||||||
@@ -61,10 +62,11 @@ export async function rawSetsRequest(sets: Sets): Promise<Sets> {
|
|||||||
|
|
||||||
export async function setRequest(
|
export async function setRequest(
|
||||||
path: string,
|
path: string,
|
||||||
type: string,
|
type?: string,
|
||||||
value: string | number | boolean,
|
value?: string | number | boolean,
|
||||||
rights?: string,
|
rights?: string,
|
||||||
uuid?: string,
|
uuid?: string,
|
||||||
|
driver?: Driver,
|
||||||
rename?: boolean,
|
rename?: boolean,
|
||||||
): Promise<Sets> {
|
): Promise<Sets> {
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -73,6 +75,7 @@ export async function setRequest(
|
|||||||
value: value,
|
value: value,
|
||||||
rights: rights,
|
rights: rights,
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
|
driver: driver,
|
||||||
rename: rename,
|
rename: rename,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,14 +102,18 @@ export async function setsRequest(sets: Sets): Promise<Sets> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteRequest(uuid?: string, path?: string, rename?: boolean): Promise<Sets> {
|
export async function deleteRequest(
|
||||||
|
uuid?: string,
|
||||||
|
path?: string,
|
||||||
|
driver?: Driver,
|
||||||
|
rename?: boolean,
|
||||||
|
): Promise<Sets> {
|
||||||
let payload = {};
|
let payload = {};
|
||||||
if (uuid) {
|
if (uuid) {
|
||||||
payload = { uuid: uuid, rename: rename };
|
payload = { uuid: uuid, driver: driver, rename: rename };
|
||||||
} else if (path) {
|
} else if (path) {
|
||||||
payload = { path: path };
|
payload = { path: path, driver: driver };
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = await api.delete('/json_data', {
|
const resp = await api.delete('/json_data', {
|
||||||
data: {
|
data: {
|
||||||
set: [payload],
|
set: [payload],
|
||||||
|
@@ -20,6 +20,7 @@ export type RawSubscribe = {
|
|||||||
path?: string;
|
path?: string;
|
||||||
depth?: number;
|
depth?: number;
|
||||||
value?: string | number | boolean | null;
|
value?: string | number | boolean | null;
|
||||||
|
drivers?: Record<string, Driver>;
|
||||||
rights?: string;
|
rights?: string;
|
||||||
hasChild?: boolean;
|
hasChild?: boolean;
|
||||||
};
|
};
|
||||||
|
4
src/vueLib/models/Topic.ts
Normal file
4
src/vueLib/models/Topic.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface Topic {
|
||||||
|
subscribe: string[];
|
||||||
|
publish: string[];
|
||||||
|
}
|
83
src/vueLib/models/driverTable.ts
Normal file
83
src/vueLib/models/driverTable.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import type { QTableColumn } from 'quasar';
|
||||||
|
import type { Subscribe } from './Subscribe';
|
||||||
|
|
||||||
|
export type DriverTableRow = {
|
||||||
|
type: string;
|
||||||
|
bus: string;
|
||||||
|
address?: number | undefined;
|
||||||
|
subscribe?: string;
|
||||||
|
publish?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const driverTable = reactive<DriverTableRow[]>([]);
|
||||||
|
const columns = ref<QTableColumn[]>([]);
|
||||||
|
const baseColumns: QTableColumn[] = [
|
||||||
|
{ name: 'type', label: 'Driver Name', field: 'type', align: 'left' },
|
||||||
|
{ name: 'bus', label: 'Bus Name', field: 'bus', align: 'center' },
|
||||||
|
{ name: 'address', label: 'Address', field: 'address', align: 'center' },
|
||||||
|
{ name: 'settings', label: '', field: 'settings', align: 'center' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function updateDriverTable(sub: Subscribe) {
|
||||||
|
driverTable.length = 0;
|
||||||
|
let hasSubs = false;
|
||||||
|
let hasPubs = false;
|
||||||
|
|
||||||
|
if (sub.drivers)
|
||||||
|
Object.entries(sub.drivers).forEach(([driverName, driverData]) => {
|
||||||
|
driverData.buses?.forEach((bus) => {
|
||||||
|
hasSubs = bus.topic?.subscribe !== undefined || hasSubs;
|
||||||
|
hasPubs = bus.topic?.publish !== undefined || hasPubs;
|
||||||
|
|
||||||
|
const subscribeList = bus.topic?.subscribe ?? [];
|
||||||
|
const publishList = bus.topic?.publish ?? [];
|
||||||
|
|
||||||
|
const addresses = bus.address?.length ? bus.address : [undefined];
|
||||||
|
|
||||||
|
addresses.forEach((addr) => {
|
||||||
|
driverTable.push({
|
||||||
|
type: driverName,
|
||||||
|
bus: bus.name,
|
||||||
|
address: addr,
|
||||||
|
subscribe: subscribeList.join(', '),
|
||||||
|
publish: publishList.join(', '),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
reloadColumns(hasSubs, hasPubs);
|
||||||
|
}
|
||||||
|
export function useDriverTable() {
|
||||||
|
function emptyTable() {
|
||||||
|
driverTable.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
driverTable,
|
||||||
|
emptyTable,
|
||||||
|
columns,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadColumns(hasSubs: boolean, hasPubs: boolean) {
|
||||||
|
columns.value = [...baseColumns];
|
||||||
|
const settingsIndex = columns?.value.findIndex((col) => col.name === 'settings');
|
||||||
|
|
||||||
|
if (hasSubs) {
|
||||||
|
columns.value?.splice(settingsIndex ?? -1, 0, {
|
||||||
|
name: 'subscribe',
|
||||||
|
label: 'subscribe',
|
||||||
|
field: 'subscribe',
|
||||||
|
align: 'left',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (hasPubs) {
|
||||||
|
columns.value?.splice(settingsIndex ?? -1, 0, {
|
||||||
|
name: 'publish',
|
||||||
|
label: 'publish',
|
||||||
|
field: 'publish',
|
||||||
|
align: 'left',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -12,9 +12,11 @@ export let socket: WebSocket | null = null;
|
|||||||
|
|
||||||
const isConnected = ref(false);
|
const isConnected = ref(false);
|
||||||
|
|
||||||
export function initWebSocket(url: string, $q?: QVueGlobals) {
|
export function initWebSocket(host: string, port: number = 8100, $q?: QVueGlobals) {
|
||||||
|
const randomId = Math.floor(Math.random() * 10001); // random number from 0 to 10000
|
||||||
|
|
||||||
const connect = () => {
|
const connect = () => {
|
||||||
socket = new WebSocket(url);
|
socket = new WebSocket(`ws://${host}:${port}/ws?id=q${randomId}`);
|
||||||
|
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
console.log('WebSocket connected');
|
console.log('WebSocket connected');
|
||||||
|
Reference in New Issue
Block a user