diff --git a/core/frontend/bun.lockb b/core/frontend/bun.lockb
index b74d69f312..4aabf49f45 100755
Binary files a/core/frontend/bun.lockb and b/core/frontend/bun.lockb differ
diff --git a/core/frontend/package.json b/core/frontend/package.json
index 00b12e0440..ede7660ef0 100644
--- a/core/frontend/package.json
+++ b/core/frontend/package.json
@@ -12,6 +12,7 @@
"build": "NODE_ENV=production vite build",
"serve": "echo 'This is a preview server for testing the built website. Please use `dev` command over `serve`.\nStarting preview server in 5 seconds..\n';sleep 5; vite preview",
"lint": "eslint --max-warnings=0 --ext .js,.vue --ignore-path .gitignore --ignore-pattern src/components/vue-tour src && stylelint 'src/**/*.{vue,css,scss}'",
+ "type-check": "vue-tsc --noEmit",
"lint:css": "stylelint 'src/**/*.{vue,css,scss}'",
"lint:css:fix": "stylelint 'src/**/*.{vue,css,scss}' --fix"
},
@@ -77,6 +78,7 @@
"wifi-qr-code-generator": "^1.1.1"
},
"devDependencies": {
+ "@types/three": "0.156.0",
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"@vitejs/plugin-vue": "^1.6.1",
@@ -96,7 +98,7 @@
"stylelint-config-recommended-vue": "^1.6.1",
"stylelint-config-standard": "^40.0.0",
"stylelint-config-standard-scss": "^17.0.0",
- "typescript": "~4.9.5",
+ "typescript": "5.4.5",
"unplugin-vue-components": "^0.25.2",
"vite": "3",
"vite-plugin-compression": "^0.5.1",
@@ -104,6 +106,7 @@
"vite-plugin-wasm": "^3.4.1",
"vue-cli-plugin-vuetify": "~2.4.1",
"vue-template-babel-compiler": "^2.0.0",
+ "vue-tsc": "2.0.29",
"vuetify-loader": "^1.7.0",
"workbox-build": "7.0.0"
}
diff --git a/core/frontend/src/App.vue b/core/frontend/src/App.vue
index 8a1ff20a5a..1054ed8d54 100644
--- a/core/frontend/src/App.vue
+++ b/core/frontend/src/App.vue
@@ -13,11 +13,11 @@
diff --git a/core/frontend/src/components/app/VehicleBanner.vue b/core/frontend/src/components/app/VehicleBanner.vue
index 5ba42f9a01..f19e11e308 100755
--- a/core/frontend/src/components/app/VehicleBanner.vue
+++ b/core/frontend/src/components/app/VehicleBanner.vue
@@ -131,7 +131,7 @@ export default Vue.extend({
}
},
async load_company_logo() {
- this.logo_image = (await bag.getData('vehicle.logo_image_path'))?.url as (string | undefined)
+ this.logo_image = (await bag.getData('vehicle.logo_image_path'))?.url as string | undefined ?? null
if (this.logo_image && !this.logo_image.startsWith('/')) {
this.logo_image = `/${this.vehicle_image}`
}
diff --git a/core/frontend/src/components/autopilot/AutopilotSerialConfiguration.vue b/core/frontend/src/components/autopilot/AutopilotSerialConfiguration.vue
index 4b4aef16b3..f3797acce7 100644
--- a/core/frontend/src/components/autopilot/AutopilotSerialConfiguration.vue
+++ b/core/frontend/src/components/autopilot/AutopilotSerialConfiguration.vue
@@ -94,7 +94,8 @@ import { OneMoreTime } from '@/one-more-time'
import autopilot from '@/store/autopilot_manager'
import system_information from '@/store/system-information'
import { SerialEndpoint } from '@/types/autopilot'
-import { Dictionary, JSONValue } from '@/types/common'
+import { Dictionary } from '@/types/common'
+import { UdevProperties } from '@/types/system-information/serial'
import back_axios from '@/utils/api'
import { isIpAddress } from '@/utils/pattern_validators'
@@ -119,7 +120,7 @@ export default Vue.extend({
G: 'Serial 6',
H: 'Serial 7',
I: 'Serial 8',
- },
+ } as Record,
ports: {} as Dictionary,
fetch_autopilot_serial_config_task: new OneMoreTime({ delay: 10000, disposeWith: this }),
fetch_serial_task: new OneMoreTime({ delay: 10000, disposeWith: this }),
@@ -166,7 +167,7 @@ export default Vue.extend({
const names = [device, driver, serial].filter((name) => name !== undefined)
return names.join(' - ')
},
- deviceInfo(path: string): JSONValue {
+ deviceInfo(path: string): UdevProperties {
return system_information.serial?.ports?.find((port) => port.by_path === path)?.udev_properties ?? {}
},
update_ports(new_ports: SerialEndpoint[]) {
diff --git a/core/frontend/src/components/bridges/BridgeCard.vue b/core/frontend/src/components/bridges/BridgeCard.vue
index 80034d2fb0..86e79e3813 100644
--- a/core/frontend/src/components/bridges/BridgeCard.vue
+++ b/core/frontend/src/components/bridges/BridgeCard.vue
@@ -43,9 +43,9 @@
Info:
- {{ bridgeSerialInfo.serial_info.udev_properties["ID_VENDOR"] }}
+ {{ bridgeSerialInfo.serial_info.udev_properties?.["ID_VENDOR"] }}
/
- {{ bridgeSerialInfo.serial_info.udev_properties["ID_MODEL"] }}
+ {{ bridgeSerialInfo.serial_info.udev_properties?.["ID_MODEL"] }}
diff --git a/core/frontend/src/components/bridges/BridgeCreationDialog.vue b/core/frontend/src/components/bridges/BridgeCreationDialog.vue
index b9394c717a..cebf33f0e9 100644
--- a/core/frontend/src/components/bridges/BridgeCreationDialog.vue
+++ b/core/frontend/src/components/bridges/BridgeCreationDialog.vue
@@ -22,8 +22,8 @@
no-data-text="No serial ports available"
:loading="updating_serial_ports"
item-text="name"
- :item-value="(item) => item.by_path ? item.by_path : item.name"
- :item-disabled="(item) => item.current_user !== null"
+ :item-value="serial_port_value"
+ :item-disabled="is_serial_port_in_use"
dense
>
@@ -272,6 +272,12 @@ export default Vue.extend({
const creation_date = new Date(creation_time)
return `${formatDistanceToNow(creation_time)} ago (${creation_date.toLocaleTimeString()})`
},
+ serial_port_value(item: SerialPortInfo): string {
+ return item.by_path ? item.by_path : item.name
+ },
+ is_serial_port_in_use(item: SerialPortInfo): boolean {
+ return item.current_user !== null
+ },
validate_required_field(input: string | number): (true | string) {
const string_input = String(input)
return isNotEmpty(string_input) ? true : 'Required field.'
diff --git a/core/frontend/src/components/cloud/CloudTrayMenu.vue b/core/frontend/src/components/cloud/CloudTrayMenu.vue
index 97928fbf0b..9ab10ba314 100644
--- a/core/frontend/src/components/cloud/CloudTrayMenu.vue
+++ b/core/frontend/src/components/cloud/CloudTrayMenu.vue
@@ -448,7 +448,7 @@ export default Vue.extend({
try {
const receiver = await this.file_sync_session.get(topic, {
- target: QueryTarget.BestMatching,
+ target: QueryTarget.BEST_MATCHING,
})
if (!receiver) {
diff --git a/core/frontend/src/components/ethernet/InterfaceCard.vue b/core/frontend/src/components/ethernet/InterfaceCard.vue
index 4c4622da75..5778875556 100644
--- a/core/frontend/src/components/ethernet/InterfaceCard.vue
+++ b/core/frontend/src/components/ethernet/InterfaceCard.vue
@@ -336,7 +336,7 @@ export default Vue.extend({
this.loading_leases = true
try {
const response = await ethernet.getDHCPServerDetails(this.adapter.name)
- this.dhcp_server_details = response.data[this.adapter.name] as DHCPServerDetails
+ this.dhcp_server_details = response[this.adapter.name]
this.dhcp_server_details.leases = this.dhcp_server_details?.leases.map((lease: DHCPServerLease) => ({
...lease,
expires_at: lease.expires_at ? new Date(lease.expires_at) : undefined,
diff --git a/core/frontend/src/components/health/GpsTrayMenu.vue b/core/frontend/src/components/health/GpsTrayMenu.vue
index 447a289929..b7b1b0efdf 100644
--- a/core/frontend/src/components/health/GpsTrayMenu.vue
+++ b/core/frontend/src/components/health/GpsTrayMenu.vue
@@ -82,12 +82,9 @@ import Vue, { markRaw } from 'vue'
import mavlink2rest from '@/libs/MAVLink2Rest'
import Listener from '@/libs/MAVLink2Rest/Listener'
+import { Type } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest'
import { GpsFixType } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-enum'
-import {
- GlobalPositionInt,
- Gps2Raw,
- GpsRawInt,
-} from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-message'
+import { Message } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-message'
import autopilot_data from '@/store/autopilot'
export default Vue.extend({
@@ -104,12 +101,17 @@ export default Vue.extend({
time_limit_message: 20000,
last_message_date: undefined as undefined | Date,
gps_detected: false,
- global_position_int: undefined as undefined | GlobalPositionInt,
- gps_raw_int: undefined as undefined | GpsRawInt,
+ global_position_int: undefined as undefined | Message.GlobalPositionInt,
+ gps_raw_int: undefined as undefined | Message.GpsRawInt | Message.Gps2Raw,
listeners: [] as Listener[],
}
},
computed: {
+ fix_type(): GpsFixType | undefined {
+ // mavlink2rest wraps enum fields as { type: } at runtime.
+ const fix_type = this.gps_raw_int?.fix_type as Type | undefined
+ return fix_type?.type
+ },
values():
Array<
{
@@ -211,7 +213,7 @@ export default Vue.extend({
return this.gps_detected
},
connection_description(): string {
- switch (this.gps_raw_int?.fix_type?.type) {
+ switch (this.fix_type) {
case GpsFixType.GPS_FIX_TYPE_NO_GPS:
return 'No GPS connection'
case GpsFixType.GPS_FIX_TYPE_NO_FIX:
@@ -235,7 +237,7 @@ export default Vue.extend({
}
},
number_color(): string {
- switch (this.gps_raw_int?.fix_type?.type) {
+ switch (this.fix_type) {
case GpsFixType.GPS_FIX_TYPE_NO_FIX:
return 'warning'
case GpsFixType.GPS_FIX_TYPE_2D_FIX:
@@ -276,7 +278,7 @@ export default Vue.extend({
}
this.last_message_date = new Date()
- this.global_position_int = message?.message as GlobalPositionInt
+ this.global_position_int = message?.message as Message.GlobalPositionInt
}).setFrequency(0)),
)
@@ -288,8 +290,8 @@ export default Vue.extend({
}
this.last_message_date = new Date()
- this.gps_raw_int = message?.message as GpsRawInt | Gps2Raw
- this.gps_detected = this.gps_raw_int?.fix_type?.type !== GpsFixType.GPS_FIX_TYPE_NO_GPS
+ this.gps_raw_int = message?.message as Message.GpsRawInt | Message.Gps2Raw
+ this.gps_detected = this.fix_type !== GpsFixType.GPS_FIX_TYPE_NO_GPS
}).setFrequency(0)),
)
},
diff --git a/core/frontend/src/components/kraken/BackAlleyTab.vue b/core/frontend/src/components/kraken/BackAlleyTab.vue
index ccadabb9f6..f21b2ecd85 100644
--- a/core/frontend/src/components/kraken/BackAlleyTab.vue
+++ b/core/frontend/src/components/kraken/BackAlleyTab.vue
@@ -69,10 +69,11 @@
style="height: 30px !important;"
>
@@ -85,10 +86,11 @@
@@ -113,10 +115,11 @@
style="height: 30px !important;"
>
@@ -129,10 +132,11 @@
diff --git a/core/frontend/src/components/kraken/KrakenManager.ts b/core/frontend/src/components/kraken/KrakenManager.ts
index 0d136115de..77fe01c110 100644
--- a/core/frontend/src/components/kraken/KrakenManager.ts
+++ b/core/frontend/src/components/kraken/KrakenManager.ts
@@ -396,7 +396,7 @@ export async function finalizeExtension(
*/
export async function getHistoricalLogsForExtension(identifier: string, timeout: number): Promise {
const queryKey = `kraken/extension/logs/request?extension_name=${identifier}`
- return await zenoh.query(queryKey, QueryTarget.BestMatching, timeout)
+ return await zenoh.query(queryKey, QueryTarget.BEST_MATCHING, timeout)
}
/**
diff --git a/core/frontend/src/components/kraken/cards/InstalledExtensionCard.vue b/core/frontend/src/components/kraken/cards/InstalledExtensionCard.vue
index b45290b775..43a2000bf3 100644
--- a/core/frontend/src/components/kraken/cards/InstalledExtensionCard.vue
+++ b/core/frontend/src/components/kraken/cards/InstalledExtensionCard.vue
@@ -104,9 +104,8 @@
v-if="loading || extension.enabled && !container"
size="20px"
/>
-
- {{ prettifySize(getMemoryUsage() * getMemoryLimit() * 100) }} /
- {{ prettifySize(getMemoryLimit() * total_memory * 0.01) }}
+
+ {{ memory_usage_text }}
N/A
@@ -129,9 +128,8 @@
v-if="loading || extension.enabled && !container"
size="20px"
/>
-
- {{ prettifySize(getDiskUsage() * main_disk_size * 0.01) }} /
- {{ prettifySize(main_disk_size) }}
+
+ {{ disk_usage_text }}
N/A
@@ -260,7 +258,7 @@ export default Vue.extend({
default: false,
},
metrics: {
- type: Object as PropType<{cpu: number, memory: string}>,
+ type: Object as PropType<{ cpu: number, memory: number | string, disk: number | string }>,
required: true,
},
container: {
@@ -296,6 +294,21 @@ export default Vue.extend({
const value = this.main_disk?.total_space_B ?? 0
return value / 1024 // Move to kB
},
+ memory_usage_text(): string | null {
+ const usage = this.getMemoryUsage()
+ const limit = this.getMemoryLimit()
+ if (typeof usage !== 'number' || limit === undefined || this.total_memory === undefined) {
+ return null
+ }
+ return `${this.prettifySize(usage * limit * 100)} / ${this.prettifySize(limit * this.total_memory * 0.01)}`
+ },
+ disk_usage_text(): string | null {
+ const usage = this.getDiskUsage()
+ if (typeof usage !== 'number') {
+ return null
+ }
+ return `${this.prettifySize(usage * this.main_disk_size * 0.01)} / ${this.prettifySize(this.main_disk_size)}`
+ },
buttonBgColor() {
return settings.is_dark_theme ? '#20455e' : '#BDE0F0'
},
@@ -343,10 +356,10 @@ export default Vue.extend({
getCpuUsage(): number {
return this.metrics?.cpu
},
- getMemoryUsage(): string {
+ getMemoryUsage(): number | string {
return this.metrics?.memory
},
- getDiskUsage(): string {
+ getDiskUsage(): number | string {
return this.metrics?.disk
},
getMemoryLimit(): number | undefined {
diff --git a/core/frontend/src/components/kraken/modals/ExtensionSettingsModal.vue b/core/frontend/src/components/kraken/modals/ExtensionSettingsModal.vue
index dfb382a6f9..1c0a2c9285 100644
--- a/core/frontend/src/components/kraken/modals/ExtensionSettingsModal.vue
+++ b/core/frontend/src/components/kraken/modals/ExtensionSettingsModal.vue
@@ -324,7 +324,8 @@ export default Vue.extend({
this.fetchManifestsSources()
} catch (error) {
- if (error.response?.status === 502) {
+ const axios_error = error as { response?: { status?: number } }
+ if (axios_error.response?.status === 502) {
this.is_operation_url_invalid = true
return
}
@@ -356,7 +357,8 @@ export default Vue.extend({
this.fetchManifestsSources()
} catch (error) {
- if (error.response?.status === 502) {
+ const axios_error = error as { response?: { status?: number } }
+ if (axios_error.response?.status === 502) {
this.is_operation_url_invalid = true
return
}
diff --git a/core/frontend/src/components/parameter-editor/InlineParameterEditor.vue b/core/frontend/src/components/parameter-editor/InlineParameterEditor.vue
index 882f5ffff4..687fc470ce 100644
--- a/core/frontend/src/components/parameter-editor/InlineParameterEditor.vue
+++ b/core/frontend/src/components/parameter-editor/InlineParameterEditor.vue
@@ -11,13 +11,14 @@
diff --git a/core/frontend/src/components/parameter-editor/ParameterEditor.vue b/core/frontend/src/components/parameter-editor/ParameterEditor.vue
index b6b5d2649c..3cc3c79fc5 100644
--- a/core/frontend/src/components/parameter-editor/ParameterEditor.vue
+++ b/core/frontend/src/components/parameter-editor/ParameterEditor.vue
@@ -17,8 +17,8 @@
:sort-by="'name'"
disable-sort
:custom-filter="() => true"
- :item-class="(value) => value.item?.readonly ? undefined : 'hand-cursor'"
- @click:row="(value) => editParam(value.item)"
+ :item-class="rowClass"
+ @click:row="onRowClick"
>
>, key: string): string {
const name = item.item[key]
const indices_array = item?.matches?.find((i: Fuse.FuseResultMatch) => i.key === key)?.indices ?? []
diff --git a/core/frontend/src/components/parameter-editor/ParameterLoader.vue b/core/frontend/src/components/parameter-editor/ParameterLoader.vue
index b62cba6d2a..f2c2bc0e1c 100755
--- a/core/frontend/src/components/parameter-editor/ParameterLoader.vue
+++ b/core/frontend/src/components/parameter-editor/ParameterLoader.vue
@@ -159,12 +159,12 @@