fix(ui): scope spatial tools to scene
This commit is contained in:
@@ -46,7 +46,6 @@ import { useWorkspaceLayoutProfile } from "./core/observation/useWorkspaceLayout
|
||||
import {
|
||||
OBSERVATION_WORKSPACE_ID,
|
||||
OBSERVATION_WORKSPACE_LAYOUT_VERSION,
|
||||
type ObservationToolWindowId,
|
||||
type ObservationWorkspaceLayoutProfile,
|
||||
} from "./core/observation/workspaceLayout";
|
||||
import {
|
||||
@@ -67,9 +66,7 @@ import { DeviceWorkspace } from "./workspaces/DeviceWorkspace";
|
||||
import { WorkspaceRenderer } from "./workspaces/Workspaces";
|
||||
import "./styles/scene-windows.css";
|
||||
|
||||
type SceneToolWindowId = ObservationToolWindowId;
|
||||
|
||||
const sceneToolWindowIds: readonly SceneToolWindowId[] = ["sources", "display", "layers"];
|
||||
type SceneToolWindowId = "sources" | "display" | "layers";
|
||||
const viewerSettingsQuietPeriodMs = 750;
|
||||
|
||||
const colorModeOptions: Array<{ value: PointColorMode; label: string; description: string }> = [
|
||||
@@ -166,6 +163,9 @@ export default function App() {
|
||||
|
||||
const currentRoot = rootById(activeRoot);
|
||||
const activeDefinition = workspaceById(workspace.activeView);
|
||||
const spatialWorkspaceActive = Boolean(
|
||||
workspace.contentOpen && activeDefinition?.kind === "spatial",
|
||||
);
|
||||
const rootWorkspaces = workspacesForRoot(activeRoot);
|
||||
const activeSceneWindow = sceneWindowOrder[sceneWindowOrder.length - 1] ?? null;
|
||||
const automaticSourceUrl = runtime.state?.spatialSource?.url.trim() ?? "";
|
||||
@@ -292,17 +292,19 @@ export default function App() {
|
||||
confirmedSceneSettingsRef.current = profile.sceneSettings;
|
||||
setSceneSettings(profile.sceneSettings);
|
||||
setDisplayDraft(profile.sceneSettings);
|
||||
setSourceWindowOpen(profile.toolWindows.sourcesOpen);
|
||||
setDisplayWindowOpen(profile.toolWindows.displayOpen);
|
||||
setLayerInspectorOpen(profile.toolWindows.layersOpen);
|
||||
setSceneWindowOrder(profile.toolWindows.order.filter((windowId) => {
|
||||
if (windowId === "sources") return profile.toolWindows.sourcesOpen;
|
||||
if (windowId === "display") return profile.toolWindows.displayOpen;
|
||||
return profile.toolWindows.layersOpen;
|
||||
}));
|
||||
observationLayout.restore(profile);
|
||||
}, [observationLayout.restore, workspaceLayoutProfile.profile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (spatialWorkspaceActive) return;
|
||||
// Scene tools are transient children of the spatial workspace. They must
|
||||
// never survive a route/root/content close or appear over the landing page.
|
||||
setSourceWindowOpen(false);
|
||||
setDisplayWindowOpen(false);
|
||||
setLayerInspectorOpen(false);
|
||||
setSceneWindowOrder([]);
|
||||
}, [spatialWorkspaceActive]);
|
||||
|
||||
useEffect(() => {
|
||||
sceneSettingsCommitterActiveRef.current = true;
|
||||
return () => {
|
||||
@@ -355,7 +357,7 @@ export default function App() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeSceneWindow) return;
|
||||
if (!spatialWorkspaceActive || !activeSceneWindow) return;
|
||||
|
||||
const closeActiveWindow = (event: KeyboardEvent) => {
|
||||
if (event.key !== "Escape" || event.defaultPrevented) return;
|
||||
@@ -367,7 +369,7 @@ export default function App() {
|
||||
|
||||
document.addEventListener("keydown", closeActiveWindow);
|
||||
return () => document.removeEventListener("keydown", closeActiveWindow);
|
||||
}, [activeSceneWindow, closeSceneWindow]);
|
||||
}, [activeSceneWindow, closeSceneWindow, spatialWorkspaceActive]);
|
||||
|
||||
const selectRoot = (rootId: RootId) => {
|
||||
setActiveRoot(rootId);
|
||||
@@ -383,6 +385,7 @@ export default function App() {
|
||||
};
|
||||
|
||||
const openSource = () => {
|
||||
if (!spatialWorkspaceActive) return;
|
||||
setSourceDraft(sourceUrl);
|
||||
setSourceWindowOpen(true);
|
||||
activateSceneWindow("sources");
|
||||
@@ -423,11 +426,13 @@ export default function App() {
|
||||
}, [commitDisplaySettings]);
|
||||
|
||||
const openDisplay = () => {
|
||||
if (!spatialWorkspaceActive) return;
|
||||
setDisplayWindowOpen(true);
|
||||
activateSceneWindow("display");
|
||||
};
|
||||
|
||||
const openLayers = () => {
|
||||
if (!spatialWorkspaceActive) return;
|
||||
setLayerInspectorOpen(true);
|
||||
activateSceneWindow("layers");
|
||||
};
|
||||
@@ -494,37 +499,18 @@ export default function App() {
|
||||
setLayoutSaveNotice("Сцена ещё не измерила рабочую область.");
|
||||
return;
|
||||
}
|
||||
const openWindowOrder = sceneWindowOrder.filter((windowId) => {
|
||||
if (windowId === "sources") return sourceWindowOpen;
|
||||
if (windowId === "display") return displayWindowOpen;
|
||||
return layerInspectorOpen;
|
||||
});
|
||||
const completeWindowOrder = [
|
||||
...sceneToolWindowIds.filter((windowId) => !openWindowOrder.includes(windowId)),
|
||||
...openWindowOrder,
|
||||
];
|
||||
const draft: ObservationWorkspaceLayoutProfile = {
|
||||
version: OBSERVATION_WORKSPACE_LAYOUT_VERSION,
|
||||
revision: workspaceLayoutProfile.profile?.revision ?? 0,
|
||||
workspaceId: OBSERVATION_WORKSPACE_ID,
|
||||
sceneSettings: sceneSettingsRef.current,
|
||||
toolWindows: {
|
||||
sourcesOpen: sourceWindowOpen,
|
||||
displayOpen: displayWindowOpen,
|
||||
layersOpen: layerInspectorOpen,
|
||||
order: completeWindowOrder,
|
||||
},
|
||||
...layout,
|
||||
};
|
||||
const saved = await workspaceLayoutProfile.save(draft);
|
||||
setLayoutSaveNotice(saved ? "Компоновка сохранена" : workspaceLayoutProfile.error);
|
||||
}, [
|
||||
displayWindowOpen,
|
||||
flushDisplaySettings,
|
||||
layerInspectorOpen,
|
||||
observationLayout.snapshot,
|
||||
sceneWindowOrder,
|
||||
sourceWindowOpen,
|
||||
workspaceLayoutProfile,
|
||||
]);
|
||||
|
||||
@@ -555,9 +541,6 @@ export default function App() {
|
||||
disabled: workspaceLayoutProfile.state === "saving",
|
||||
onClick: () => void saveWorkspaceLayout(),
|
||||
},
|
||||
{ label: "Настроить визуальный движок", icon: "network", onClick: openSource },
|
||||
{ label: "Настроить отображение", icon: "sliders", onClick: openDisplay },
|
||||
{ label: "Открыть слои", icon: "list", onClick: openLayers },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -731,7 +714,7 @@ export default function App() {
|
||||
/>
|
||||
|
||||
<Window
|
||||
open={sourceWindowOpen}
|
||||
open={spatialWorkspaceActive && sourceWindowOpen}
|
||||
title="Визуальный движок"
|
||||
subtitle="Rerun gRPC и записи пространственной сцены"
|
||||
placement="end"
|
||||
@@ -857,7 +840,7 @@ export default function App() {
|
||||
</Window>
|
||||
|
||||
<Window
|
||||
open={displayWindowOpen}
|
||||
open={spatialWorkspaceActive && displayWindowOpen}
|
||||
title="Отображение"
|
||||
subtitle="Параметры пространственной сцены"
|
||||
placement="end"
|
||||
@@ -1002,7 +985,7 @@ export default function App() {
|
||||
</Window>
|
||||
|
||||
<Window
|
||||
open={layerInspectorOpen}
|
||||
open={spatialWorkspaceActive && layerInspectorOpen}
|
||||
title="Слои сцены"
|
||||
subtitle="Сущности пространственной сцены"
|
||||
placement="end"
|
||||
|
||||
Reference in New Issue
Block a user