353 lines
10 KiB
Vue
353 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
AnyTypes,
|
|
type CommandParameterData,
|
|
type DynamicDataType,
|
|
type OptionalDynamicComponentData,
|
|
} from '@/composables/dynamic.ts';
|
|
import { computed, defineAsyncComponent, inject, type Ref, ref } from 'vue';
|
|
import CommandParameterListConfigurator from '@/components/CommandParameterListConfigurator.vue';
|
|
|
|
const TelemetryValue = defineAsyncComponent(
|
|
() => import('@/components/TelemetryValue.vue'),
|
|
);
|
|
const GridLayout = defineAsyncComponent(
|
|
() => import('@/components/layout/GridLayout.vue'),
|
|
);
|
|
const CommandInput = defineAsyncComponent(
|
|
() => import('@/components/CommandInput.vue'),
|
|
);
|
|
|
|
const model = defineModel<OptionalDynamicComponentData>('data', {
|
|
required: true,
|
|
});
|
|
|
|
const selection = defineModel<symbol>('selection');
|
|
|
|
const props = defineProps<{
|
|
editable: boolean;
|
|
}>();
|
|
|
|
const busy = ref(false);
|
|
|
|
// Provide a fallback option
|
|
const inputs = inject<Ref<{ [id: string]: DynamicDataType }>>(
|
|
'inputs',
|
|
ref({}),
|
|
);
|
|
|
|
const thisSymbol = Symbol();
|
|
|
|
const isSelected = computed(() => {
|
|
return selection.value == thisSymbol && props.editable;
|
|
});
|
|
|
|
function selectThis(e: Event) {
|
|
if (props.editable) {
|
|
// Only do this when we are editable
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}
|
|
selection.value = thisSymbol;
|
|
}
|
|
|
|
function deleteThis() {
|
|
model.value = {
|
|
type: 'none',
|
|
};
|
|
}
|
|
|
|
function makeText() {
|
|
model.value = {
|
|
type: 'text',
|
|
text: '',
|
|
justify_right: false,
|
|
};
|
|
}
|
|
|
|
function makeTelemetry() {
|
|
model.value = {
|
|
type: 'telemetry',
|
|
data: '',
|
|
};
|
|
}
|
|
|
|
function makeGrid() {
|
|
model.value = {
|
|
type: 'grid',
|
|
columns: 1,
|
|
equal_width: false,
|
|
cells: [],
|
|
};
|
|
}
|
|
|
|
function addRow() {
|
|
const grid = model.value;
|
|
if (grid.type == 'grid') {
|
|
const row: OptionalDynamicComponentData[] = [];
|
|
for (let i = 0; i < grid.columns; i++) {
|
|
row.push({ type: 'none' });
|
|
}
|
|
grid.cells.push(row);
|
|
model.value = grid;
|
|
}
|
|
}
|
|
|
|
function deleteRow() {
|
|
const grid = model.value;
|
|
if (grid.type == 'grid') {
|
|
grid.cells.pop();
|
|
model.value = grid;
|
|
}
|
|
}
|
|
|
|
function addColumn() {
|
|
const grid = model.value;
|
|
if (grid.type == 'grid') {
|
|
for (let i = 0; i < grid.cells.length; i++) {
|
|
grid.cells[i].push({ type: 'none' });
|
|
}
|
|
grid.columns += 1;
|
|
model.value = grid;
|
|
}
|
|
}
|
|
|
|
function deleteColumn() {
|
|
const grid = model.value;
|
|
if (grid.type == 'grid') {
|
|
for (let i = 0; i < grid.cells.length; i++) {
|
|
grid.cells[i].pop();
|
|
}
|
|
grid.columns -= 1;
|
|
model.value = grid;
|
|
}
|
|
}
|
|
|
|
function makeInput() {
|
|
model.value = {
|
|
type: 'input',
|
|
id: [...Array(32)]
|
|
.map(() => Math.floor(Math.random() * 16).toString(16))
|
|
.join(''),
|
|
data_type: 'Float32',
|
|
};
|
|
}
|
|
|
|
function makeCommandButton() {
|
|
model.value = {
|
|
type: 'command_button',
|
|
text: 'Button Text',
|
|
command_name: '',
|
|
parameters: {},
|
|
};
|
|
}
|
|
|
|
async function sendCommand(command: {
|
|
command_name: string;
|
|
parameters: { [key: string]: CommandParameterData };
|
|
}) {
|
|
busy.value = true;
|
|
|
|
const params: { [key: string]: DynamicDataType } = {};
|
|
for (const param_name in command.parameters) {
|
|
const parameter = command.parameters[param_name];
|
|
switch (parameter.type) {
|
|
case 'constant':
|
|
params[param_name] = parameter.value;
|
|
break;
|
|
case 'input':
|
|
params[param_name] = inputs.value[parameter.id];
|
|
break;
|
|
}
|
|
}
|
|
|
|
await fetch(`/api/cmd/${command.command_name}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(params),
|
|
});
|
|
busy.value = false;
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<div class="row">
|
|
<button
|
|
v-if="model.type != 'none'"
|
|
@click.stop.prevent="deleteThis"
|
|
>
|
|
Delete
|
|
</button>
|
|
<button v-if="model.type != 'text'" @click.stop.prevent="makeText">
|
|
Make Text
|
|
</button>
|
|
<button
|
|
v-if="model.type != 'telemetry'"
|
|
@click.stop.prevent="makeTelemetry"
|
|
>
|
|
Make Telemetry
|
|
</button>
|
|
<button v-if="model.type != 'grid'" @click.stop.prevent="makeGrid">
|
|
Make Grid
|
|
</button>
|
|
<button
|
|
v-if="model.type != 'input'"
|
|
@click.stop.prevent="makeInput"
|
|
>
|
|
Make Input
|
|
</button>
|
|
<button
|
|
v-if="model.type != 'command_button'"
|
|
@click.stop.prevent="makeCommandButton"
|
|
>
|
|
Make Command Button
|
|
</button>
|
|
</div>
|
|
</Teleport>
|
|
<template v-if="model.type == 'none'">
|
|
<span
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
@click="selectThis"
|
|
></span>
|
|
</template>
|
|
<template v-else-if="model.type == 'text'">
|
|
<span
|
|
:class="`${model.justify_right ? 'justify-right' : ''} ${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
@click="selectThis"
|
|
>
|
|
{{ model.text }}
|
|
</span>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<div class="row">
|
|
<label>Text: </label>
|
|
<input v-model="model.text" />
|
|
</div>
|
|
<div class="row">
|
|
<label>Justify Right: </label>
|
|
<input type="checkbox" v-model="model.justify_right" />
|
|
</div>
|
|
</Teleport>
|
|
</template>
|
|
<template v-else-if="model.type == 'telemetry'">
|
|
<span
|
|
v-if="editable"
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
@click="selectThis"
|
|
>
|
|
{{ '{' }} {{ model.data }} {{ '}' }}
|
|
</span>
|
|
<TelemetryValue
|
|
v-else
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
:data="model.data"
|
|
@click="selectThis"
|
|
></TelemetryValue>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<label>Telemetry Item: </label>
|
|
<input v-model="model.data" />
|
|
</Teleport>
|
|
</template>
|
|
<template v-else-if="model.type == 'grid'">
|
|
<GridLayout
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
:cols="model.columns"
|
|
:equal_col_width="model.equal_width"
|
|
@click="selectThis"
|
|
>
|
|
<template v-for="x in model.cells.length" :key="x">
|
|
<template v-for="y in model.columns" :key="y">
|
|
<DynamicComponent
|
|
v-model:data="model.cells[x - 1][y - 1]"
|
|
:editable="editable"
|
|
v-model:selection="selection"
|
|
></DynamicComponent>
|
|
</template>
|
|
</template>
|
|
</GridLayout>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<div class="row">
|
|
<label>Equal Width: </label>
|
|
<input type="checkbox" v-model="model.equal_width" />
|
|
</div>
|
|
<div class="row">
|
|
<button @click.stop.prevent="addRow">Add Row</button>
|
|
<button
|
|
:disabled="model.cells.length <= 0"
|
|
@click.stop.prevent="deleteRow"
|
|
>
|
|
Delete Row
|
|
</button>
|
|
<button @click.stop.prevent="addColumn">Add Column</button>
|
|
<button
|
|
:disabled="model.columns <= 0"
|
|
@click.stop.prevent="deleteColumn"
|
|
>
|
|
Delete Column
|
|
</button>
|
|
</div>
|
|
</Teleport>
|
|
</template>
|
|
<template v-else-if="model.type == 'input'">
|
|
<span
|
|
v-if="editable"
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
@click="selectThis"
|
|
>
|
|
{{ '[' }} {{ model.id }} {{ ']' }}
|
|
</span>
|
|
<CommandInput
|
|
v-else
|
|
:type="model.data_type"
|
|
v-model="inputs[model.id]"
|
|
></CommandInput>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<div class="row">
|
|
<label>Input ID: </label>
|
|
<input v-model="model.id" />
|
|
</div>
|
|
<div class="row">
|
|
<label>Data Type: </label>
|
|
<select v-model="model.data_type">
|
|
<option v-for="type in AnyTypes" :key="type" :value="type">
|
|
{{ type }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</Teleport>
|
|
</template>
|
|
<template v-else-if="model.type == 'command_button'">
|
|
<button
|
|
:disabled="busy"
|
|
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
|
|
@click.stop.prevent="
|
|
(e) => (editable ? selectThis(e) : sendCommand(model as any))
|
|
"
|
|
>
|
|
{{ model.text }}
|
|
</button>
|
|
<Teleport v-if="isSelected" to="#inspector">
|
|
<div class="row">
|
|
<label>Button Text: </label>
|
|
<input v-model="model.text" />
|
|
</div>
|
|
<div class="row">
|
|
<label>Command: </label>
|
|
<input v-model="model.command_name" />
|
|
</div>
|
|
<CommandParameterListConfigurator
|
|
:key="model.command_name"
|
|
:command_name="model.command_name"
|
|
v-model="model.parameters"
|
|
></CommandParameterListConfigurator>
|
|
</Teleport>
|
|
</template>
|
|
<template v-else> ERROR: Unknown data: {{ model }} </template>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
@use '@/assets/variables';
|
|
</style>
|