Skip to content

Commit f8bc531

Browse files
authored
Merge pull request #166 from NASA-IMPACT/feat/dynamic-panel-mounting
feat: Dynamic plugin load/unload and hide/unhide
2 parents 9e78669 + 8e1f889 commit f8bc531

15 files changed

Lines changed: 714 additions & 60 deletions

File tree

configure/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "configure",
3-
"version": "4.2.13-20260701",
3+
"version": "4.2.12-20260702",
44
"homepage": "./configure/build",
55
"private": true,
66
"dependencies": {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mmgis",
3-
"version": "4.2.13-20260701",
3+
"version": "4.2.12-20260702",
44
"description": "A web-based mapping and localization solution for science operation on planetary missions.",
55
"homepage": "build",
66
"repository": {

src/essence/Basics/PanelManager_/PanelManager_.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ import { PanelPosition, PanelState, PanelLayoutType, PANEL_STATE, FLOAT_POSITION
33
import { PanelConfig, PanelStateObject, PanelManager as PanelManagerInterface } from './types/panel';
44
import { mmgisAPI } from '../../mmgisAPI/mmgisAPI';
55

6+
/**
7+
* Float panels don't require a priority (they don't compete for edge viewport
8+
* space), so `config.priority` may be undefined. Treat missing priority as
9+
* lowest priority (sorts last) instead of letting `undefined - undefined`
10+
* produce NaN, which Array.prototype.sort treats as "leave order unchanged"
11+
* and yields insertion-order-dependent, effectively unsorted results.
12+
*/
13+
function normalizePriority(priority: number | undefined): number {
14+
return priority === undefined ? Infinity : priority;
15+
}
16+
617
class PanelManager implements PanelManagerInterface {
718
private panels: Map<string, PanelStateObject> = new Map();
819

@@ -271,7 +282,7 @@ class PanelManager implements PanelManagerInterface {
271282
getPanelsAtPosition(position: PanelPosition): PanelStateObject[] {
272283
return Array.from(this.panels.values())
273284
.filter(p => p.config.position === position)
274-
.sort((a, b) => a.config.priority - b.config.priority);
285+
.sort((a, b) => normalizePriority(a.config.priority) - normalizePriority(b.config.priority));
275286
}
276287

277288
/**
@@ -282,7 +293,7 @@ class PanelManager implements PanelManagerInterface {
282293
*/
283294
getAllPanelsByPriority(): PanelStateObject[] {
284295
return Array.from(this.panels.values())
285-
.sort((a, b) => a.config.priority - b.config.priority);
296+
.sort((a, b) => normalizePriority(a.config.priority) - normalizePriority(b.config.priority));
286297
}
287298

288299
/**

src/essence/Basics/PanelManager_/types/layout.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,40 @@
11
/**
2-
* Supported panel positions (regions where panels can be placed).
2+
* Positions for edge panels (top/left/right/bottom), which claim viewport
3+
* space and therefore require a `priority` + `layoutType`.
34
*/
4-
export const PANEL_POSITION = {
5+
const EDGE_POSITION = {
56
TOP: 'top',
67
LEFT: 'left',
78
RIGHT: 'right',
89
BOTTOM: 'bottom',
10+
} as const
11+
export type EdgePanelPosition = (typeof EDGE_POSITION)[keyof typeof EDGE_POSITION]
12+
13+
/**
14+
* Positions for floating panels, which render as overlays inside the center
15+
* map area and don't compete for edge viewport space.
16+
*/
17+
const FLOAT_POSITION = {
918
FLOAT_TOP_LEFT: 'float-top-left',
1019
FLOAT_TOP_CENTER: 'float-top-center',
1120
FLOAT_TOP_RIGHT: 'float-top-right',
1221
FLOAT_BOTTOM_LEFT: 'float-bottom-left',
1322
FLOAT_BOTTOM_CENTER: 'float-bottom-center',
1423
FLOAT_BOTTOM_RIGHT: 'float-bottom-right',
1524
} as const
16-
export type PanelPosition = (typeof PANEL_POSITION)[keyof typeof PANEL_POSITION]
25+
export type FloatPanelPosition = (typeof FLOAT_POSITION)[keyof typeof FLOAT_POSITION]
26+
27+
/**
28+
* Supported panel positions (regions where panels can be placed).
29+
*/
30+
export const PANEL_POSITION = { ...EDGE_POSITION, ...FLOAT_POSITION } as const
31+
export type PanelPosition = EdgePanelPosition | FloatPanelPosition
1732

1833
/**
1934
* Set of all float positions for quick membership checks.
2035
* Float panels render inside the center map area as overlays.
2136
*/
22-
export const FLOAT_POSITIONS = new Set([
23-
PANEL_POSITION.FLOAT_TOP_LEFT,
24-
PANEL_POSITION.FLOAT_TOP_CENTER,
25-
PANEL_POSITION.FLOAT_TOP_RIGHT,
26-
PANEL_POSITION.FLOAT_BOTTOM_LEFT,
27-
PANEL_POSITION.FLOAT_BOTTOM_CENTER,
28-
PANEL_POSITION.FLOAT_BOTTOM_RIGHT,
29-
] as const)
37+
export const FLOAT_POSITIONS = new Set(Object.values(FLOAT_POSITION))
3038

3139
/**
3240
* Visual states of a panel:

src/essence/Basics/PanelManager_/types/panel.ts

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { ToolOrientation, ToolMetadata } from '../../ToolController_/types/tool';
2-
import { PanelPosition, PanelState, PanelLayoutType } from './layout';
2+
import {
3+
PanelPosition,
4+
EdgePanelPosition,
5+
FloatPanelPosition,
6+
PanelState,
7+
PanelLayoutType,
8+
} from './layout';
39

410
/**
511
* Panel size configuration.
@@ -98,7 +104,8 @@ export interface PanelCapabilities {
98104

99105
/**
100106
* Whether this panel can be resized by the user via drag handles.
101-
* Default: false
107+
* Default: false. Not supported on floating panels — dragging happens
108+
* via move handles instead, so this must be false/omitted there.
102109
*/
103110
resizable?: boolean;
104111

@@ -116,29 +123,16 @@ export interface PanelCapabilities {
116123
}
117124

118125
/**
119-
* Complete configuration for a panel region.
120-
* Defines behavior, constraints, and appearance.
126+
* Fields shared by every panel, regardless of whether it's an edge or
127+
* floating panel.
121128
*/
122-
export interface PanelConfig {
129+
interface BasePanelConfig {
123130
/** Unique identifier for this panel */
124131
id: string;
125132

126133
/** Display title for the panel */
127134
title?: string;
128135

129-
/** Which region this panel occupies */
130-
position: PanelPosition;
131-
132-
/**
133-
* Layout priority for space allocation.
134-
* Lower numbers claim viewport space first.
135-
* Example: top=0, right=1, bottom=2, left=3
136-
*/
137-
priority: PanelPriority;
138-
139-
/** How tools are laid out when panel is in 'expanded' state */
140-
layoutType: PanelLayoutType;
141-
142136
/** Which states are allowed and what the default state is */
143137
stateConstraints: PanelStateConstraints;
144138

@@ -168,6 +162,56 @@ export interface PanelConfig {
168162
panelTools?: string[];
169163
}
170164

165+
/**
166+
* Configuration for an edge panel (top/left/right/bottom).
167+
* Edge panels compete for viewport space, so `priority` (stacking/allocation
168+
* order) and `layoutType` (how multiple tools are arranged) are required.
169+
*/
170+
export interface EdgePanelConfig extends BasePanelConfig {
171+
/** Which edge region this panel occupies */
172+
position: EdgePanelPosition;
173+
174+
/**
175+
* Layout priority for space allocation.
176+
* Lower numbers claim viewport space first.
177+
* Example: top=0, right=1, bottom=2, left=3
178+
*/
179+
priority: PanelPriority;
180+
181+
/** How tools are laid out when panel is in 'expanded' state */
182+
layoutType: PanelLayoutType;
183+
}
184+
185+
/**
186+
* Configuration for a floating panel, rendered as an overlay inside the
187+
* center map area. Floats don't compete for edge viewport space, so
188+
* `priority` and `layoutType` are optional, and drag-resize isn't supported.
189+
*/
190+
export interface FloatPanelConfig extends BasePanelConfig {
191+
/** Which float zone this panel occupies */
192+
position: FloatPanelPosition;
193+
194+
/**
195+
* Not used for float layout/rendering, but still affects fallback tool
196+
* assignment: ToolControllerModern_._findPanel picks the first compatible
197+
* panel from the combined edge+float priority order, so a low priority
198+
* here can out-rank an edge panel for an unassigned tool.
199+
*/
200+
priority?: PanelPriority;
201+
202+
/** Accepted but inert for floats — _renderFloatRegions always stacks tools regardless of this value */
203+
layoutType?: PanelLayoutType;
204+
205+
/** Floats can't be drag-resized; `resizable` must be false/omitted */
206+
capabilities?: Omit<PanelCapabilities, 'resizable'> & { resizable?: false };
207+
}
208+
209+
/**
210+
* Complete configuration for a panel region.
211+
* Defines behavior, constraints, and appearance.
212+
*/
213+
export type PanelConfig = EdgePanelConfig | FloatPanelConfig;
214+
171215
/**
172216
* Runtime state object for an active panel.
173217
* Tracks current state, configuration, and associated tools.

0 commit comments

Comments
 (0)