feat(foundry): refine map application controls
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { forwardRef, lazy, Suspense, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type PointerEvent } from "react";
|
||||
import { Button, Checker, ColorField, ControlRow, Dropdown, Icon, IconButton, Inspector, InspectorSelectField, RangeControl, SegmentedControl, WorkspaceWindow } from "@nodedc/ui-react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { ApplicationSidePanel, Button, Checker, ColorField, ControlRow, Dropdown, Icon, IconButton, Inspector, InspectorSelectField, RangeControl, SegmentedControl, WorkspaceWindow } from "@nodedc/ui-react";
|
||||
import type { SelectOption, WorkspaceWindowRect } from "@nodedc/ui-react";
|
||||
import type {
|
||||
CameraSpiralState,
|
||||
@@ -461,7 +462,7 @@ export type MapSubjectWindowState = {
|
||||
zIndex: number;
|
||||
};
|
||||
|
||||
type MapWorkspaceWindowId = "settings" | "layers" | "sector" | "subject-card" | `binding:${string}`;
|
||||
type MapWorkspaceWindowId = "sector" | "subject-card" | `binding:${string}`;
|
||||
|
||||
export type MapSubjectState = {
|
||||
bindingId: string;
|
||||
@@ -641,20 +642,6 @@ function defaultSubjectWindowState(index: number): MapSubjectWindowState {
|
||||
};
|
||||
}
|
||||
|
||||
const defaultLayersWindowRect: WorkspaceWindowRect = {
|
||||
x: 24,
|
||||
y: 72,
|
||||
width: 336,
|
||||
height: 500,
|
||||
};
|
||||
|
||||
const defaultSettingsWindowRect: WorkspaceWindowRect = {
|
||||
x: 930,
|
||||
y: 72,
|
||||
width: 420,
|
||||
height: 530,
|
||||
};
|
||||
|
||||
const defaultSectorWindowRect: WorkspaceWindowRect = {
|
||||
x: 24,
|
||||
y: 72,
|
||||
@@ -718,7 +705,10 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
initialLayout?: MapPageLayout | null;
|
||||
applicationId?: string;
|
||||
pageId?: string;
|
||||
}>(function MapFixturePreview({ features = { inspector: true, toolbar: true, assistant: false }, expanded = false, initialLayout = null, applicationId, pageId }, ref) {
|
||||
settingsPanelHost?: HTMLElement | null;
|
||||
headerActionsHost?: HTMLElement | null;
|
||||
onSettingsPanelOpenChange?: (open: boolean) => void;
|
||||
}>(function MapFixturePreview({ features = { inspector: true, toolbar: true, assistant: false }, expanded = false, initialLayout = null, applicationId, pageId, settingsPanelHost, headerActionsHost, onSettingsPanelOpenChange }, ref) {
|
||||
const workspaceRef = useRef<HTMLDivElement>(null);
|
||||
const [selectedId, setSelectedId] = useState<string>();
|
||||
const [selectedGridSector, setSelectedGridSector] = useState<GridSectorSelection | null>(null);
|
||||
@@ -730,16 +720,10 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
const [subjectCardTabId, setSubjectCardTabId] = useState("overview");
|
||||
const [expandedFacetRows, setExpandedFacetRows] = useState<Record<string, boolean>>({});
|
||||
const [inspectorOpen, setInspectorOpen] = useState(false);
|
||||
const [settingsWindowRect, setSettingsWindowRect] = useState<WorkspaceWindowRect>(defaultSettingsWindowRect);
|
||||
const [settingsWindowMaximized, setSettingsWindowMaximized] = useState(false);
|
||||
const [settingsWindowZIndex, setSettingsWindowZIndex] = useState(13);
|
||||
const [inspectorOpenSections, setInspectorOpenSections] = useState<string[]>(() => (
|
||||
initialLayout?.inspectorOpenSections ?? ["map-base"]
|
||||
));
|
||||
const [layersOpen, setLayersOpen] = useState(false);
|
||||
const [layersWindowRect, setLayersWindowRect] = useState<WorkspaceWindowRect>(defaultLayersWindowRect);
|
||||
const [layersWindowMaximized, setLayersWindowMaximized] = useState(false);
|
||||
const [layersWindowZIndex, setLayersWindowZIndex] = useState(12);
|
||||
const [sectorWindowRect, setSectorWindowRect] = useState<WorkspaceWindowRect>(defaultSectorWindowRect);
|
||||
const [sectorWindowMaximized, setSectorWindowMaximized] = useState(false);
|
||||
const [sectorWindowZIndex, setSectorWindowZIndex] = useState(142);
|
||||
@@ -1385,15 +1369,11 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
if (activeWorkspaceWindowId === windowId) return;
|
||||
const nextZIndex = Math.max(
|
||||
20,
|
||||
settingsWindowZIndex,
|
||||
layersWindowZIndex,
|
||||
sectorWindowZIndex,
|
||||
subjectCardZIndex,
|
||||
...Object.values(subjectStates).map((state) => state.window.zIndex),
|
||||
) + 1;
|
||||
if (windowId === "settings") setSettingsWindowZIndex(nextZIndex);
|
||||
else if (windowId === "layers") setLayersWindowZIndex(nextZIndex);
|
||||
else if (windowId === "sector") setSectorWindowZIndex(nextZIndex);
|
||||
if (windowId === "sector") setSectorWindowZIndex(nextZIndex);
|
||||
else if (windowId === "subject-card") setSubjectCardZIndex(nextZIndex);
|
||||
else if (windowId.startsWith("binding:")) {
|
||||
const bindingId = windowId.slice("binding:".length);
|
||||
@@ -1403,7 +1383,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
}));
|
||||
}
|
||||
setActiveWorkspaceWindowId(windowId);
|
||||
}, [activeWorkspaceWindowId, layersWindowZIndex, sectorWindowZIndex, settingsWindowZIndex, subjectCardZIndex, subjectStates, updateSubjectState]);
|
||||
}, [activeWorkspaceWindowId, sectorWindowZIndex, subjectCardZIndex, subjectStates, updateSubjectState]);
|
||||
|
||||
const clearActiveWorkspaceWindow = (windowId: MapWorkspaceWindowId) => {
|
||||
setActiveWorkspaceWindowId((current) => current === windowId ? undefined : current);
|
||||
@@ -1422,24 +1402,15 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
clearActiveWorkspaceWindow(`binding:${bindingId}`);
|
||||
};
|
||||
|
||||
const activateLayersWindow = () => {
|
||||
activateWorkspaceWindow("layers");
|
||||
};
|
||||
const closeSettingsPanel = useCallback(() => setInspectorOpen(false), []);
|
||||
|
||||
const toggleLayersWindow = () => {
|
||||
if (layersOpen) {
|
||||
setLayersOpen(false);
|
||||
clearActiveWorkspaceWindow("layers");
|
||||
return;
|
||||
}
|
||||
setLayersOpen(true);
|
||||
activateLayersWindow();
|
||||
};
|
||||
const toggleSettingsPanel = () => setInspectorOpen((current) => !current);
|
||||
|
||||
const openSettingsWindow = () => {
|
||||
setInspectorOpen(true);
|
||||
activateWorkspaceWindow("settings");
|
||||
};
|
||||
useEffect(() => {
|
||||
onSettingsPanelOpenChange?.(inspectorOpen && Boolean(features.inspector));
|
||||
}, [features.inspector, inspectorOpen, onSettingsPanelOpenChange]);
|
||||
|
||||
useEffect(() => () => onSettingsPanelOpenChange?.(false), [onSettingsPanelOpenChange]);
|
||||
|
||||
const deactivateGridSector = () => {
|
||||
setSelectedGridSector(null);
|
||||
@@ -1718,6 +1689,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Подложка и terrain",
|
||||
description: "provider-neutral surface",
|
||||
group: "Карта",
|
||||
icon: <Icon name="globe" />,
|
||||
content: <>
|
||||
<ControlRow label="Подложка"><strong>Cesium World Imagery</strong></ControlRow>
|
||||
<small className="catalog-map-inspector__note">Текущий официальный provider. Другие provider-слои появятся только после отдельного asset-контракта Platform.</small>
|
||||
@@ -1743,6 +1715,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Атмосфера и освещение",
|
||||
description: "scene / color correction",
|
||||
group: "Карта",
|
||||
icon: <Icon name="activity" />,
|
||||
content: <>
|
||||
<Checker checked={mapSettings.atmosphereEnabled} label="Показывать атмосферу" onChange={(atmosphereEnabled) => updateMapSettings({ atmosphereEnabled })} />
|
||||
<RangeControl label="Атмосфера: оттенок" value={mapSettings.atmosphereHue} min={-100} max={100} formatValue={(value) => `${value}%`} onChange={(atmosphereHue) => updateMapSettings({ atmosphereHue })} />
|
||||
@@ -1761,6 +1734,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "3D здания",
|
||||
description: "3D Tiles / detail",
|
||||
group: "Карта",
|
||||
icon: <Icon name="building" />,
|
||||
content: <>
|
||||
<Checker checked={mapSettings.buildingsVisible} label="Показывать 3D здания" onChange={(buildingsVisible) => updateMapSettings({ buildingsVisible })} />
|
||||
<ControlRow label="Цвет"><ColorField label="Цвет зданий" value={mapSettings.buildingsColor} onChange={(buildingsColor) => updateMapSettings({ buildingsColor })} /></ControlRow>
|
||||
@@ -1777,6 +1751,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: referenceProfile ? profile.title : profile.target.variant === "surface-fill" ? "HGeoZone" : "Таргет",
|
||||
description: profile.target.variant === "surface-fill" ? `проекция · ${profile.title}` : profile.title,
|
||||
group: referenceProfile ? "Станции" : profile.target.variant === "surface-fill" ? "Слои" : "Таргеты",
|
||||
icon: <Icon name={referenceProfile ? "globe" : profile.target.variant === "surface-fill" ? "grid" : "target"} />,
|
||||
content: <>
|
||||
<small className="catalog-map-inspector__note">Профиль принадлежит этой странице Application и управляется тем же provider-neutral MCP-контрактом. Исходный API в настройках отсутствует.</small>
|
||||
{referenceLayer ? (
|
||||
@@ -1831,6 +1806,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Классы состояния",
|
||||
description: "нормализованные фасеты онтологии",
|
||||
group: "Таргеты",
|
||||
icon: <Icon name="sliders" />,
|
||||
content: <>
|
||||
<small className="catalog-map-inspector__note">Цвета назначены семантическим классам после нормализации данных. Здесь нет названий provider-статусов и привязки к транспорту.</small>
|
||||
{profile.styles.map((style) => {
|
||||
@@ -1850,6 +1826,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Сетка и LOD",
|
||||
description: "first adapter control",
|
||||
group: "Слои",
|
||||
icon: <Icon name="grid" />,
|
||||
content: <div className="catalog-map-grid-inspector">
|
||||
<small className="catalog-map-inspector__note">Фиксированная московская ENU-адресация задаёт неизменные сектора на LOD 1–3. LOD 4–5 используют глобальную WGS84-гратику́лу; камера выбирает только LOD и видимую область.</small>
|
||||
<Checker checked={mapSettings.gridVisible} label="Сетка" onChange={(gridVisible) => updateMapSettings({ gridVisible })} />
|
||||
@@ -2108,6 +2085,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Анимация камеры",
|
||||
description: "geodesic spiral survey",
|
||||
group: "Камера",
|
||||
icon: <Icon name="activity" />,
|
||||
content: <>
|
||||
<Checker checked={animationModeEnabled} label="Режим анимации" onChange={setAnimationMode} />
|
||||
{animationModeEnabled ? <>
|
||||
@@ -2186,6 +2164,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "TileCache",
|
||||
description: "Platform Map Gateway",
|
||||
group: "Хранение",
|
||||
icon: <Icon name="database" />,
|
||||
content: <>
|
||||
<small className="catalog-map-inspector__note">Общий persistent cache Platform: он не принадлежит приложению, странице или пользователю.</small>
|
||||
<Checker checked={mapSettings.cacheEnabled} label="Кэшировать live-данные" onChange={setCacheEnabled} />
|
||||
@@ -2211,6 +2190,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
label: "Выбранная сущность",
|
||||
description: "selection contract",
|
||||
group: "Данные",
|
||||
icon: <Icon name="target" />,
|
||||
content: <>
|
||||
<ControlRow label="Сущность"><strong>{selected?.title ?? "Нет выбора"}</strong></ControlRow>
|
||||
<ControlRow label="Тип"><span>{selected?.kind ?? "—"}{selected?.status ? ` · ${selected.status}` : ""}</span></ControlRow>
|
||||
@@ -2218,6 +2198,31 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
},
|
||||
];
|
||||
|
||||
const headerActions = (
|
||||
<div className="catalog-map-header-actions" aria-label="Действия карты">
|
||||
<IconButton className="catalog-map-header-action" label="Настройки карты" aria-pressed={inspectorOpen} data-active={inspectorOpen || undefined} onClick={toggleSettingsPanel}><Icon name="settings" /></IconButton>
|
||||
{features.toolbar ? <IconButton className="catalog-map-header-action" label="Toolbar" aria-pressed={toolbarOpen} data-active={toolbarOpen || undefined} onClick={() => setToolbarOpen((value) => !value)}><Icon name="panel" /></IconButton> : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
const settingsPanel = inspectorOpen && Boolean(features.inspector) ? (
|
||||
<ApplicationSidePanel
|
||||
eyebrow="MAP / SETTINGS"
|
||||
title="Настройки карты"
|
||||
description="Application-owned layout"
|
||||
onClose={closeSettingsPanel}
|
||||
aria-label="Настройки карты"
|
||||
>
|
||||
<Inspector
|
||||
variant="panel"
|
||||
sections={inspectorSections}
|
||||
openSections={inspectorOpenSections}
|
||||
singleOpen
|
||||
onOpenSectionsChange={setInspectorOpenSections}
|
||||
/>
|
||||
</ApplicationSidePanel>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={workspaceRef}
|
||||
@@ -2225,71 +2230,33 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
style={{ "--catalog-map-height": `${mapHeight}px` } as CSSProperties}
|
||||
aria-label="Map Page Cesium adapter"
|
||||
>
|
||||
<Suspense fallback={<div className="catalog-map-fixture__loading">Загрузка карты…</div>}>
|
||||
<CesiumMapRenderer
|
||||
key={rendererRevision}
|
||||
ref={mapRendererRef}
|
||||
onSelect={handleSelect}
|
||||
onGridSectorSelect={handleGridSectorSelect}
|
||||
selectedGridSector={selectedGridSector}
|
||||
onGatewayHealth={handleRendererGatewayHealth}
|
||||
onProviderStatus={setProviderStatus}
|
||||
onCameraChange={handleCameraChange}
|
||||
onCacheRefreshConsumed={handleCacheRefreshConsumed}
|
||||
onReadyChange={setMapRendererReady}
|
||||
onSpiralStateChange={handleSpiralStateChange}
|
||||
initialCamera={mapCamera ?? undefined}
|
||||
presentation={presentation}
|
||||
runtimeBindings={[...sectorScopedPrimaryRuntimeBindings, ...referenceRuntimeBindings]}
|
||||
presentationProfiles={presentationProfiles}
|
||||
presentationFilters={rendererPresentationFilters}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
<div className="catalog-map-fixture__actions">
|
||||
<IconButton label="Настройки карты" aria-pressed={inspectorOpen} data-active={inspectorOpen || undefined} onClick={openSettingsWindow}><Icon name="settings" /></IconButton>
|
||||
<IconButton label="Слои карты" aria-pressed={layersOpen} data-active={layersOpen || undefined} onClick={toggleLayersWindow}><Icon name="grid" /></IconButton>
|
||||
{features.toolbar ? <IconButton label="Toolbar" aria-pressed={toolbarOpen} data-active={toolbarOpen || undefined} onClick={() => setToolbarOpen((value) => !value)}><Icon name="panel" /></IconButton> : null}
|
||||
{features.assistant ? <IconButton label="Assistant" aria-pressed={assistantOpen} data-active={assistantOpen || undefined} onClick={() => setAssistantOpen((value) => !value)}><Icon name="apps" /></IconButton> : null}
|
||||
<div className="catalog-map-fixture__renderer">
|
||||
<Suspense fallback={<div className="catalog-map-fixture__loading">Загрузка карты…</div>}>
|
||||
<CesiumMapRenderer
|
||||
key={rendererRevision}
|
||||
ref={mapRendererRef}
|
||||
onSelect={handleSelect}
|
||||
onGridSectorSelect={handleGridSectorSelect}
|
||||
selectedGridSector={selectedGridSector}
|
||||
onGatewayHealth={handleRendererGatewayHealth}
|
||||
onProviderStatus={setProviderStatus}
|
||||
onCameraChange={handleCameraChange}
|
||||
onCacheRefreshConsumed={handleCacheRefreshConsumed}
|
||||
onReadyChange={setMapRendererReady}
|
||||
onSpiralStateChange={handleSpiralStateChange}
|
||||
initialCamera={mapCamera ?? undefined}
|
||||
presentation={presentation}
|
||||
runtimeBindings={[...sectorScopedPrimaryRuntimeBindings, ...referenceRuntimeBindings]}
|
||||
presentationProfiles={presentationProfiles}
|
||||
presentationFilters={rendererPresentationFilters}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{layersOpen ? (
|
||||
<WorkspaceWindow
|
||||
boundsRef={workspaceRef}
|
||||
rect={layersWindowRect}
|
||||
onRectChange={setLayersWindowRect}
|
||||
maximized={layersWindowMaximized}
|
||||
onMaximizedChange={setLayersWindowMaximized}
|
||||
onActivate={activateLayersWindow}
|
||||
onClose={() => {
|
||||
setLayersOpen(false);
|
||||
clearActiveWorkspaceWindow("layers");
|
||||
}}
|
||||
title="Слои карты"
|
||||
active={activeWorkspaceWindowId === "layers"}
|
||||
zIndex={layersWindowZIndex}
|
||||
minWidth={320}
|
||||
minHeight={360}
|
||||
className="catalog-map-fixture__layers catalog-map-fixture__map-glass-window"
|
||||
aria-label="Настройки слоёв карты"
|
||||
>
|
||||
<div className="catalog-map-fixture__layers-content">
|
||||
<div className="catalog-map-fixture__provider">
|
||||
<strong>Cesium World Imagery</strong>
|
||||
<small>официальный live provider · imagery: {providerStateLabel[providerStatus.imagery]} · terrain: {providerStateLabel[providerStatus.terrain]}</small>
|
||||
</div>
|
||||
{Object.entries(providerStatus.errors).map(([provider, error]) => <small key={provider} className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{provider}: {error}</small>)}
|
||||
<Checker checked={mapSettings.terrainEnabled} label="Terrain" onChange={(terrainEnabled) => updateMapSettings({ terrainEnabled })} />
|
||||
<Checker checked={mapSettings.buildingsVisible} label="3D здания" onChange={(buildingsVisible) => updateMapSettings({ buildingsVisible })} />
|
||||
<Checker checked={mapSettings.gridVisible} label="Планетарная сетка" onChange={(gridVisible) => updateMapSettings({ gridVisible })} />
|
||||
<small className="catalog-map-inspector__note">Live Cache: {liveCacheSummary}</small>
|
||||
{transportDiagnostic ? <small className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{transportDiagnostic}</small> : null}
|
||||
{gatewayHealthAge ? <small className="catalog-map-inspector__note">{gatewayHealthAge}</small> : null}
|
||||
{gatewayCheckState === "error" || gatewayCheckState === "stale" ? <small className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{gatewayCheckError}</small> : null}
|
||||
<Checker className="catalog-map-fixture__cache-toggle" checked={mapSettings.cacheEnabled} label="Кэшировать live-данные" onChange={setCacheEnabled} />
|
||||
<Checker className="catalog-map-fixture__cache-toggle" checked={mapSettings.cacheNoOverwrite} disabled={!mapSettings.cacheEnabled} label="Не перезаписывать cache" onChange={setCacheNoOverwrite} />
|
||||
</div>
|
||||
</WorkspaceWindow>
|
||||
{features.assistant ? (
|
||||
<div className="catalog-map-fixture__actions">
|
||||
<IconButton label="Assistant" aria-pressed={assistantOpen} data-active={assistantOpen || undefined} onClick={() => setAssistantOpen((value) => !value)}><Icon name="apps" /></IconButton>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{selectedGridSector ? (
|
||||
@@ -2497,6 +2464,39 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
</div>
|
||||
)}
|
||||
</Dropdown>
|
||||
<Dropdown
|
||||
placement="top-start"
|
||||
width={320}
|
||||
minWidth={240}
|
||||
offset={10}
|
||||
surfaceRole="dialog"
|
||||
surfaceClassName="catalog-map-fixture__objects-menu catalog-map-fixture__layers-menu nodedc-map-glass"
|
||||
onOpenChange={setLayersOpen}
|
||||
trigger={({ open, toggle, setTriggerRef, surfaceId }) => (
|
||||
<IconButton ref={setTriggerRef} label="Слои карты" aria-controls={surfaceId} aria-expanded={open} aria-pressed={open} data-active={open || undefined} onClick={toggle}><Icon name="grid" /></IconButton>
|
||||
)}
|
||||
>
|
||||
<div className="catalog-map-fixture__layers-content" aria-label="Настройки слоёв карты">
|
||||
<div className="catalog-map-fixture__objects-menu-head">
|
||||
<strong>Слои карты</strong>
|
||||
<small>Подложка, рельеф и визуальные слои</small>
|
||||
</div>
|
||||
<div className="catalog-map-fixture__provider">
|
||||
<strong>Cesium World Imagery</strong>
|
||||
<small>официальный live provider · imagery: {providerStateLabel[providerStatus.imagery]} · terrain: {providerStateLabel[providerStatus.terrain]}</small>
|
||||
</div>
|
||||
{Object.entries(providerStatus.errors).map(([provider, error]) => <small key={provider} className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{provider}: {error}</small>)}
|
||||
<Checker checked={mapSettings.terrainEnabled} label="Terrain" onChange={(terrainEnabled) => updateMapSettings({ terrainEnabled })} />
|
||||
<Checker checked={mapSettings.buildingsVisible} label="3D здания" onChange={(buildingsVisible) => updateMapSettings({ buildingsVisible })} />
|
||||
<Checker checked={mapSettings.gridVisible} label="Планетарная сетка" onChange={(gridVisible) => updateMapSettings({ gridVisible })} />
|
||||
<small className="catalog-map-inspector__note">Live Cache: {liveCacheSummary}</small>
|
||||
{transportDiagnostic ? <small className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{transportDiagnostic}</small> : null}
|
||||
{gatewayHealthAge ? <small className="catalog-map-inspector__note">{gatewayHealthAge}</small> : null}
|
||||
{gatewayCheckState === "error" || gatewayCheckState === "stale" ? <small className="catalog-map-inspector__note catalog-map-inspector__note--error" role="alert">{gatewayCheckError}</small> : null}
|
||||
<Checker className="catalog-map-fixture__cache-toggle" checked={mapSettings.cacheEnabled} label="Кэшировать live-данные" onChange={setCacheEnabled} />
|
||||
<Checker className="catalog-map-fixture__cache-toggle" checked={mapSettings.cacheNoOverwrite} disabled={!mapSettings.cacheEnabled} label="Не перезаписывать cache" onChange={setCacheNoOverwrite} />
|
||||
</div>
|
||||
</Dropdown>
|
||||
<IconButton label="Обзор объектов" onClick={() => mapRendererRef.current?.fitRuntimeEntities(visibleTargetEntityIds)}><Icon name="globe" /></IconButton>
|
||||
<IconButton
|
||||
label={searchOpen ? "Закрыть поиск" : "Поиск"}
|
||||
@@ -2741,35 +2741,12 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
{assistantOpen ? <div className="catalog-map-fixture__assistant"><strong>NODE.DC Assistant</strong><span>Контекст выбранной сущности готов к передаче.</span></div> : null}
|
||||
<button type="button" className="catalog-map-fixture__resize" aria-label="Изменить высоту карты" onPointerDown={startResize}><span /></button>
|
||||
|
||||
{inspectorOpen && Boolean(features.inspector) ? (
|
||||
<WorkspaceWindow
|
||||
boundsRef={workspaceRef}
|
||||
rect={settingsWindowRect}
|
||||
onRectChange={setSettingsWindowRect}
|
||||
maximized={settingsWindowMaximized}
|
||||
onMaximizedChange={setSettingsWindowMaximized}
|
||||
onActivate={() => activateWorkspaceWindow("settings")}
|
||||
onClose={() => {
|
||||
setInspectorOpen(false);
|
||||
clearActiveWorkspaceWindow("settings");
|
||||
}}
|
||||
title="Настройки карты"
|
||||
subtitle="MAP / inspector"
|
||||
active={activeWorkspaceWindowId === "settings"}
|
||||
zIndex={settingsWindowZIndex}
|
||||
minWidth={360}
|
||||
minHeight={380}
|
||||
className="catalog-map-fixture__map-settings-window catalog-map-fixture__map-glass-window"
|
||||
aria-label="Настройки карты"
|
||||
>
|
||||
<Inspector
|
||||
sections={inspectorSections}
|
||||
openSections={inspectorOpenSections}
|
||||
singleOpen
|
||||
onOpenSectionsChange={setInspectorOpenSections}
|
||||
/>
|
||||
</WorkspaceWindow>
|
||||
) : null}
|
||||
{settingsPanel
|
||||
? settingsPanelHost
|
||||
? createPortal(settingsPanel, settingsPanelHost)
|
||||
: <div className="catalog-map-fixture__settings-panel-fallback">{settingsPanel}</div>
|
||||
: null}
|
||||
{headerActionsHost ? createPortal(headerActions, headerActionsHost) : null}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user