import { GxState } from "./state.js" import { GxNotice } from "./notice.js" import { TroubleshootPage, TmuxPage } from "./diagnostic-tools.js" import { navigate } from "./router.js" import { SystemMonitor } from "./system-monitor.js" import { CrashReportsFeed } from "./crash-reports.js" import { storedSize } from "./record-deletion.js" import { StarPortLogsFeed, BUNDLE_URL, fileUrl, outcomeLabel } from "./starport-logs.js" import { MenuTile } from "./menu-tile.js" import { BluetoothNotice, bluetoothConnection } from "./bluetooth-notice.js" export const Logs = { name: "Logs", components: { GxState, GxNotice, BluetoothNotice, SystemMonitor, TroubleshootPage, TmuxPage, MenuTile }, props: { path: { type: String, required: true }, mode: { type: String, required: true }, unauthorized: { type: Function, required: true }, tools: { type: Array, required: true } }, data: () => ({ crashes: { reports: [], scanIncomplete: false, listLimited: false, status: "idle", error: "", selected: null, preview: null, previewStatus: "idle", deleting: false, storageBytes: 0, reportCount: 0 }, search: "", starportLogs: { sessions: [], others: [], status: "idle", error: "" }, bluetooth: bluetoothConnection() }), computed: { visibleReports() { return this.crashes.reports.filter((item) => item.name.toLowerCase().includes(this.search.toLowerCase())) }, }, created() { this.crashFeed = new CrashReportsFeed({ publish: (update) => Object.assign(this.crashes, update), unauthorized: this.unauthorized }) this.starportFeed = new StarPortLogsFeed({ publish: (update) => Object.assign(this.starportLogs, update), unauthorized: this.unauthorized }) }, mounted() { if (this.path === "/logs/crashes" && this.mode === "local") this.crashFeed.start() if (this.path === "/logs/starport" && this.mode === "local") this.starportFeed.start() }, beforeUnmount() { this.crashFeed.stop(); this.starportFeed.stop() }, watch: { path(next, previous) { if (next === "/logs/crashes" && this.mode === "local") this.crashFeed.start() else if (previous === "/logs/crashes") { this.crashFeed.stop(); this.search = "" } if (next === "/logs/starport" && this.mode === "local") this.starportFeed.start() else if (previous === "/logs/starport") this.starportFeed.stop() }, }, methods: { storedSize, go: navigate, bundleUrl: () => BUNDLE_URL, fileUrl, outcomeLabel, reportDate(seconds) { return new Date(seconds * 1000).toLocaleString() }, reportSize(bytes) { return `${(bytes / 1024).toFixed(1)} KiB` }, async copyPreview() { if (!this.crashes.preview) return try { await navigator.clipboard.writeText(this.crashes.preview.text) } catch { this.crashes.error = "Copy is unavailable in this browser." } }, }, template: `

Logs & Diagnostics

Logs, diagnostics, drive state, and help.

Help & Community

Guides and help from the community.

Wiki

Find setup guides, feature explanations, and troubleshooting steps for StarPilot and Android Auto.

Open the Wiki
Discord

Ask the community for help, share what you have tried, and follow StarPilot announcements.

Join Discord

StarPort Logs

The last 20 connection sessions, newest first. The archive includes every session, a readable report for each, StarPort settings, the car view's renderer logs, and a snapshot of the device (Wi-Fi, Bluetooth and kernel logs, build, CPU load). Hardware addresses are masked.

Log summaries remain available. Loading StarPort logs… {{ starportLogs.error || 'StarPort logs are unavailable.' }} No StarPort sessions have been logged yet.
{{ outcomeLabel(log.outcome) }}{{ log.car || 'Car not identified' }}{{ log.transport ? ' · ' + log.transport : '' }}{{ log.trigger ? ' · ' + log.trigger : '' }}{{ reportDate(log.modifiedAt) }} · {{ reportSize(log.size) }}
This Logs & Diagnostics page is unavailable in the offline preview.
`, }