Files
next-tjwater-frontend/src/features/workbench/hooks/use-workbench-map-controller.ts
T
jiang 2d8506fea0
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s
feat: add project-aware agent workspace
2026-10-22 18:52:18 +08:00

78 lines
2.4 KiB
TypeScript

import type { FeatureCollection, Point } from "geojson";
import type { Map as MapLibreMap } from "maplibre-gl";
import type { ScadaDevice } from "../api/scada-client";
import { useEffect, useRef, useSyncExternalStore, type RefObject } from "react";
import { getResponsiveWorkbenchPadding } from "../map/camera";
import type { WaterNetworkSourceId } from "../map/sources";
import { WorkbenchMapController } from "../map/workbench-map-controller";
export function useWorkbenchMapController({
mapRef,
geoserverWorkspace,
mapReady,
leftPanelOpen,
rightPanelOpen,
conditionPanelExpanded = false,
agentPanelWidth,
getScadaFeatures,
availableSourceIds
}: {
geoserverWorkspace?: string;
mapRef: RefObject<MapLibreMap | null>;
mapReady: boolean;
leftPanelOpen: boolean;
rightPanelOpen: boolean;
conditionPanelExpanded?: boolean;
agentPanelWidth?: number;
getScadaFeatures?: (deviceIds?: string[], signal?: AbortSignal) => Promise<FeatureCollection<Point, ScadaDevice>>;
availableSourceIds?: readonly WaterNetworkSourceId[];
}) {
const valuesRef = useRef({
mapReady,
leftPanelOpen,
rightPanelOpen,
conditionPanelExpanded,
agentPanelWidth
});
valuesRef.current = {
mapReady,
leftPanelOpen,
rightPanelOpen,
conditionPanelExpanded,
agentPanelWidth
};
const controllerRef = useRef<WorkbenchMapController | null>(null);
if (!controllerRef.current) {
controllerRef.current = new WorkbenchMapController({
geoserverWorkspace,
getMap: () => mapRef.current,
isReady: () => valuesRef.current.mapReady,
getPadding: () => {
const map = mapRef.current;
return map
? getResponsiveWorkbenchPadding(
map,
valuesRef.current.leftPanelOpen,
valuesRef.current.rightPanelOpen,
valuesRef.current.conditionPanelExpanded,
valuesRef.current.agentPanelWidth
)
: { top: 48, right: 48, bottom: 48, left: 48 };
},
getScadaFeatures
});
}
const controller = controllerRef.current;
const state = useSyncExternalStore(
controller.subscribe,
controller.getSnapshot,
controller.getSnapshot
);
useEffect(() => {
if (availableSourceIds) controller.syncAvailableSources(availableSourceIds);
}, [availableSourceIds, controller]);
useEffect(() => () => controller.destroy(), [controller]);
return { controller, state };
}