feat(ui): add a desktop panel rail to each sidebar

Each side stack hosts a Vue rail listing its panels; selecting one opens it
through PanelChrome. The shell owns one Vue runtime and Pinia instance, and a
panel store mirrors each side's panels from the DOM. The rail hides with its
stack, in Cockpit, clean view and recording, and on phones. Panels without a
catalog entry get a generic item, and Data Layers leaves the rail while the
f shortcut hides it.
This commit is contained in:
Sameh Khamis committed 2026-10-30 16:41:29 -07:00
1 parent eed7657516
commit 3d5d3ef014
29 files changed
+627 -32

No files matched your search

+9 -3
View File
@@ -1,6 +1,7 @@
import { readFile, realpath } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import vue from '@vitejs/plugin-vue';
import { build, normalizePath } from 'vite';
/** Build each browser or Node export group and reject imports outside its declared ownership. */
@@ -99,15 +100,20 @@ export async function checkPackageBoundaries(root) {
ssr: node ? { noExternal: true } : undefined,
logLevel: 'silent',
plugins: [
vue(),
{
name: 'check-package-ownership',
moduleParsed(info) {
if (!allowed.has(info.id)) {
// Plugin helpers are virtual; a single-file component's style and
// template blocks belong to the component file itself.
if (info.id.startsWith('\0')) return;
const id = info.id.split('?')[0];
if (!allowed.has(id)) {
throw new Error(
`Package boundary ${name} imports an unowned module: ${path.relative(root, info.id)}`,
`Package boundary ${name} imports an unowned module: ${path.relative(root, id)}`,
);
}
seen.add(info.id);
seen.add(id);
},
},
],
+3 -1
View File
@@ -1122,5 +1122,7 @@
"src/ui/kit/UiRail.test.mjs",
"src/testSupport/vueDom.mjs",
"src/testSupport/vueLoader.mjs",
"src/testSupport/registerVue.mjs"
"src/testSupport/registerVue.mjs",
"src/ui/panelNavigation.test.mjs",
"src/ui/stores/panels.test.mjs"
]
+1
View File
@@ -433,6 +433,7 @@ function sourceFiles() {
'src/*.mjs',
'src/**/*.js',
'src/**/*.mjs',
'src/**/*.vue',
).filter(
(file) =>
!file.startsWith('src/i18n/') &&
+23 -2
View File
@@ -876,9 +876,18 @@
"src/ui/statusBadge.js",
"src/scopeMaskPolicy.js",
"src/visualStylePolicy.js",
"src/ui/stores/panels.js",
"src/ui/panelRailCatalog.js",
"src/ui/vueRuntime.js",
"src/ui/kit/UiIcon.vue",
"src/ui/kit/rail.js",
"src/ui/kit/UiTooltip.vue",
"src/ui/kit/UiRail.vue",
"src/ui/PanelRailView.vue",
"src/ui/panelNavigation.js",
"src/ui/panelAccordion.js"
],
"external": ["cesium"]
"external": ["cesium", "vue", "pinia"]
},
"ui-styles": {
"exports": ["./ui/styles"],
@@ -2813,6 +2822,15 @@
"src/sceneCommandRelease.js",
"src/scopeMaskPolicy.js",
"src/visualStylePolicy.js",
"src/ui/stores/panels.js",
"src/ui/panelRailCatalog.js",
"src/ui/vueRuntime.js",
"src/ui/kit/UiIcon.vue",
"src/ui/kit/UiTooltip.vue",
"src/ui/kit/rail.js",
"src/ui/kit/UiRail.vue",
"src/ui/PanelRailView.vue",
"src/ui/panelNavigation.js",
"src/ui/panelAccordion.js"
],
"external": [
@@ -2824,7 +2842,9 @@
"pbf",
"satellite.js",
"mapillary-js",
"@jtarrio/webrtlsdr"
"@jtarrio/webrtlsdr",
"vue",
"pinia"
]
},
"application-catalog": {
@@ -3607,6 +3627,7 @@
"src/i18n/locales/uk.json",
"src/i18n/locales/zh-CN.json",
"src/i18n/locales/zh-Hant.json",
"src/ui/panelRailCatalog.js",
"src/ui/panelAccordion.js"
],
"external": []