Merge main into the Utilities panel, rebuilt on the Vue panel rail

main moved the panels to Vue views and a one-open-panel rail, and removed
the two templates this branch edited. This merge carries the branch onto
that architecture; it adds no behaviour of its own beyond the port.

- The Utilities panel is a RailPanel in LayerPanelsView with its own rail
  item (handyman). LayerPanel renders the Directions rows into its list with
  LayerRows, and falls back to Data Layers without it.
- Draw leaves DisplayPanel for DrawControls, DrawMarkList and DrawSwatches,
  which render what the draw tool publishes to the display store and call
  its actions, as GeoImport does. drawMarks.js words the rows; the DOM-built
  drawMarkList.js is gone. A row's fly-to is an immediate navigation like
  Import's ('drawing' gets its Cockpit refusal), the name field keeps a
  draft through v-field-value, and the colours are one radio group with a
  single tab stop.
- UiSegmented draws an option's icon, named by its label, for the shape
  buttons.
- The catalogs take main's languages with this branch's strings, Arabic
  included, and the tests follow the views to their new homes.
This commit is contained in:
Said Turksever committed 2026-11-02 16:43:29 +00:00
commit 4ebb287d36
699 files changed
+46673 -20476

No files matched your search

+31 -22
View File
@@ -9,6 +9,8 @@ import { resolveDeicticArgs } from './deixis.js';
export { readLayerLifecycleSummary } from './layerSummary.js';
import { defaultGeospatial } from '../search/defaults.js';
import { msg } from '../i18n/index.js';
import { useProviderSettingsStore } from '../ui/stores/providerSettings.js';
import { applicationPinia } from '../ui/vueRuntime.js';
import * as Cesium from 'cesium';
import { CITY_POIS } from '../cityPois.js';
import { greatCircleKm } from '../geoDistance.js';
@@ -97,6 +99,7 @@ const PANEL_ALIASES = new Map([
['global context', 'global-context-panel'],
['right context', 'global-context-panel'],
['context right panel', 'global-context-panel'],
['authoring', 'scene-panel'],
['scenes', 'scene-panel'],
['scene', 'scene-panel'],
['post processing', 'pp-toggles'],
@@ -771,10 +774,9 @@ export function createGevActionRunner({
cancelled: true,
};
const doc = globalThis.document;
const panel = doc?.getElementById?.('key-setup');
const button = open
? doc?.getElementById?.('key-setup-chip')
: panel?.querySelector?.('[data-key-setup-close]');
// The setup owner (src/keySetup.js) publishes the dialog and takes
// its open and close requests.
const settings = useProviderSettingsStore(applicationPinia());
const concealed =
open &&
[
@@ -783,11 +785,7 @@ export function createGevActionRunner({
'cockpit-mode',
'scene-playback-mode',
].some((mode) => doc?.body?.classList?.contains(mode));
if (
concealed ||
panel?.dataset?.ready !== 'true' ||
typeof button?.click !== 'function'
) {
if (concealed || settings.view?.ready !== true || !settings.controls) {
const error = concealed
? 'Provider Settings is hidden in the current view. Leave that view before opening it.'
: 'Provider Settings is unavailable in this runtime.';
@@ -801,11 +799,11 @@ export function createGevActionRunner({
say: error,
};
}
button.click();
// Opening unhides immediately; closing removes visible before its fade ends.
const applied = open
? !panel.hidden
: !panel.classList.contains('visible');
if (open) settings.controls.open();
else settings.controls.close();
// Opening unhides at once; closing drops visible before its fade ends.
const dialog = settings.view.dialog;
const applied = open ? !dialog.hidden : !dialog.visible;
const say = applied
? `Provider Settings is ${open ? 'open' : 'closed'}.`
: 'Provider Settings did not change.';
@@ -814,12 +812,22 @@ export function createGevActionRunner({
action: name,
panelId,
applied,
open: applied ? open : !panel.hidden,
open: applied ? open : !dialog.hidden,
say,
...(!applied ? { error: say } : {}),
};
}
setPanelOpen(styleManager, panelId, open);
if (!setPanelOpen(styleManager, panelId, open)) {
const say = 'There is no panel to open here.';
return {
ok: false,
action: 'set_panel_open',
panelId,
open,
say,
error: say,
};
}
return { ok: true, action: 'set_panel_open', panelId, open };
}
@@ -3148,13 +3156,14 @@ function normalizeAircraftClassFilter(value) {
return raw.replace(/[\s-]+/g, '') === TR3B_CLASS ? TR3B_CLASS : raw;
}
/**
* @returns {boolean} Whether a shell took the change: its panel chrome owns
* panel state, so without one there is no panel to open.
*/
function setPanelOpen(styleManager, panelId, open) {
if (styleManager && typeof styleManager.setPanelCollapsed === 'function') {
styleManager.setPanelCollapsed(panelId, !open, { explicit: true });
} else {
const panel = document.getElementById(panelId);
if (panel) panel.classList.toggle('collapsed', !open);
}
if (typeof styleManager?.setPanelCollapsed !== 'function') return false;
styleManager.setPanelCollapsed(panelId, !open, { explicit: true });
return true;
}
function normalizeContextMode(value) {