diff --git a/frontend/src/components/CommandInput.vue b/frontend/src/components/CommandInput.vue new file mode 100644 index 0000000..32b8176 --- /dev/null +++ b/frontend/src/components/CommandInput.vue @@ -0,0 +1,40 @@ + + + + + + UNKNOWN INPUT + + + diff --git a/frontend/src/components/CommandParameter.vue b/frontend/src/components/CommandParameter.vue index e1e5490..07d6b3c 100644 --- a/frontend/src/components/CommandParameter.vue +++ b/frontend/src/components/CommandParameter.vue @@ -1,36 +1,22 @@ {{ parameter.name }} - - - UNKNOWN INPUT + diff --git a/frontend/src/components/CommandParameterDataConfigurator.vue b/frontend/src/components/CommandParameterDataConfigurator.vue new file mode 100644 index 0000000..94af44c --- /dev/null +++ b/frontend/src/components/CommandParameterDataConfigurator.vue @@ -0,0 +1,29 @@ + + + + + Value: + + + + ID: + + + + + diff --git a/frontend/src/components/CommandParameterListConfigurator.vue b/frontend/src/components/CommandParameterListConfigurator.vue new file mode 100644 index 0000000..1df1e6a --- /dev/null +++ b/frontend/src/components/CommandParameterListConfigurator.vue @@ -0,0 +1,99 @@ + + + + + + + + {{ param.name }} + + Constant + Input + + + + + + + Loading... + + + + diff --git a/frontend/src/components/CommandSender.vue b/frontend/src/components/CommandSender.vue index 37d1315..ef301e2 100644 --- a/frontend/src/components/CommandSender.vue +++ b/frontend/src/components/CommandSender.vue @@ -3,12 +3,13 @@ import type { CommandDefinition } from '@/composables/command.ts'; import { ref } from 'vue'; import CommandParameter from '@/components/CommandParameter.vue'; import FlexDivider from '@/components/FlexDivider.vue'; +import type { DynamicDataType } from '@/composables/dynamic.ts'; const props = defineProps<{ command: CommandDefinition | null; }>(); -const parameters = ref({}); // eslint-disable-line @typescript-eslint/no-explicit-any +const parameters = ref<{ [key: string]: DynamicDataType }>({}); const busy = ref(false); const result = ref(''); diff --git a/frontend/src/components/DynamicComponent.vue b/frontend/src/components/DynamicComponent.vue index 14d947a..e8d30ab 100644 --- a/frontend/src/components/DynamicComponent.vue +++ b/frontend/src/components/DynamicComponent.vue @@ -1,6 +1,12 @@ @@ -123,20 +193,30 @@ function deleteColumn() { Make Grid + + Make Input + + + Make Command Button + - {{ model.text }} @@ -155,7 +235,7 @@ function deleteColumn() { {{ '{' }} {{ model.data }} {{ '}' }} @@ -163,7 +243,7 @@ function deleteColumn() { v-else :class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`" :data="model.data" - @click.stop.prevent="selectThis" + @click="selectThis" > Telemetry Item: @@ -175,7 +255,7 @@ function deleteColumn() { :class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`" :cols="model.columns" :equal_col_width="model.equal_width" - @click.stop.prevent="selectThis" + @click="selectThis" > @@ -210,6 +290,60 @@ function deleteColumn() { + + + {{ '[' }} {{ model.id }} {{ ']' }} + + + + + Input ID: + + + + Data Type: + + + {{ type }} + + + + + + + (editable ? selectThis(e) : sendCommand(model as any)) + " + > + {{ model.text }} + + + + Button Text: + + + + Command: + + + + + ERROR: Unknown data: {{ model }} diff --git a/frontend/src/components/TelemetryLine.vue b/frontend/src/components/TelemetryLine.vue index 8c7fe01..ef2fda7 100644 --- a/frontend/src/components/TelemetryLine.vue +++ b/frontend/src/components/TelemetryLine.vue @@ -23,6 +23,11 @@ import { AXIS_DATA, type AxisData } from '@/graph/axis'; import ValueLabel from '@/components/ValueLabel.vue'; import { type Point, PointLine } from '@/graph/line'; import TooltipDialog from '@/components/TooltipDialog.vue'; +import { + type DynamicDataType, + isBooleanType, + isNumericType, +} from '@/composables/dynamic.ts'; const props = defineProps<{ data: string; @@ -98,13 +103,9 @@ watch([value], ([val]) => { if (val_t >= min_x) { const raw_item_val = val.value[telemetry_data.value!.data_type]; let item_val = 0; - if ( - ['Float32', 'Float64'].some( - (e) => e == telemetry_data.value!.data_type, - ) - ) { + if (isNumericType(telemetry_data.value!.data_type)) { item_val = raw_item_val as number; - } else if (telemetry_data.value!.data_type == 'Boolean') { + } else if (isBooleanType(telemetry_data.value!.data_type)) { item_val = (raw_item_val as boolean) ? 1 : 0; } const new_item = { @@ -140,15 +141,13 @@ watch( const response = (await res.json()) as TelemetryDataItem[]; for (const data_item of response) { const val_t = Date.parse(data_item.timestamp); - const raw_item_val = data_item.value[type]; + const raw_item_val = data_item.value[ + type + ] as DynamicDataType; let item_val = 0; - if ( - ['Float32', 'Float64'].some( - (e) => e == telemetry_data.value!.data_type, - ) - ) { + if (isNumericType(type)) { item_val = raw_item_val as number; - } else if (type == 'Boolean') { + } else if (isBooleanType(type)) { item_val = (raw_item_val as boolean) ? 1 : 0; } const new_item = { diff --git a/frontend/src/composables/command.ts b/frontend/src/composables/command.ts index 13f4439..4798dc8 100644 --- a/frontend/src/composables/command.ts +++ b/frontend/src/composables/command.ts @@ -1,9 +1,10 @@ import { ref, toValue, watchEffect } from 'vue'; import { type MaybeRefOrGetter } from 'vue'; +import type { AnyTypeId } from '@/composables/dynamic.ts'; export interface CommandParameterDefinition { name: string; - data_type: string; + data_type: AnyTypeId; } export interface CommandDefinition { @@ -30,7 +31,7 @@ export function useAllCommands() { return { data, error }; } -export function ueCommand(name: MaybeRefOrGetter) { +export function useCommand(name: MaybeRefOrGetter) { const data = ref(null); // eslint-disable-next-line @typescript-eslint/no-explicit-any const error = ref(null); diff --git a/frontend/src/composables/dynamic.ts b/frontend/src/composables/dynamic.ts index eb4f340..2e9e409 100644 --- a/frontend/src/composables/dynamic.ts +++ b/frontend/src/composables/dynamic.ts @@ -1,3 +1,29 @@ +export const NumericTypes = ['Float32', 'Float64'] as const; +export type NumericTypeId = (typeof NumericTypes)[number]; +export const BooleanTypes = ['Boolean'] as const; +export type BooleanTypeId = (typeof BooleanTypes)[number]; +export const AnyTypes = [...NumericTypes, ...BooleanTypes] as const; +export type AnyTypeId = (typeof AnyTypes)[number]; + +export function isNumericType(type: AnyTypeId): type is NumericTypeId { + return NumericTypes.some((it) => it == type); +} +export function isBooleanType(type: AnyTypeId): type is BooleanTypeId { + return BooleanTypes.some((it) => it == type); +} + +export type DynamicDataType = number | boolean; + +export type CommandParameterData = + | { + type: 'constant'; + value: DynamicDataType; + } + | { + type: 'input'; + id: string; + }; + export type DynamicComponentData = | { type: 'text'; text: string; justify_right: boolean } | { type: 'telemetry'; data: string } @@ -6,6 +32,17 @@ export type DynamicComponentData = columns: number; equal_width: boolean; cells: OptionalDynamicComponentData[][]; + } + | { + type: 'input'; + id: string; + data_type: AnyTypeId; + } + | { + type: 'command_button'; + text: string; + command_name: string; + parameters: { [key: string]: CommandParameterData }; }; export type OptionalDynamicComponentData = diff --git a/frontend/src/composables/telemetry.ts b/frontend/src/composables/telemetry.ts index bc4bcef..fa56db8 100644 --- a/frontend/src/composables/telemetry.ts +++ b/frontend/src/composables/telemetry.ts @@ -1,10 +1,11 @@ import { ref, toValue, watchEffect } from 'vue'; import { type MaybeRefOrGetter } from 'vue'; +import type { AnyTypeId } from '@/composables/dynamic.ts'; export interface TelemetryDefinition { uuid: string; name: string; - data_type: string; + data_type: AnyTypeId; } export function useAllTelemetry() { diff --git a/frontend/src/views/PanelView.vue b/frontend/src/views/PanelView.vue index 5e46f52..2e6aea3 100644 --- a/frontend/src/views/PanelView.vue +++ b/frontend/src/views/PanelView.vue @@ -1,7 +1,10 @@