diff --git a/webui/src/features/organizations/OrganizationsPage.tsx b/webui/src/features/organizations/OrganizationsPage.tsx index da2e607..310217c 100644 --- a/webui/src/features/organizations/OrganizationsPage.tsx +++ b/webui/src/features/organizations/OrganizationsPage.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState, type FormEvent } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react"; import { Edit3, Plus, RefreshCw, Save, XCircle } from "lucide-react"; import { ApiError, @@ -118,6 +118,26 @@ type ActiveItem = { is_active: boolean; }; +type OrganizationsInitialQuery = { + section: OrganizationSection | ""; + unitId: string; + functionId: string; +}; + +function organizationSectionFromQuery(value: string | null): OrganizationSection | "" { + return value === "model" || value === "units" || value === "relations" || value === "functions" ? value : ""; +} + +function organizationsInitialQuery(): OrganizationsInitialQuery { + if (typeof window === "undefined") return { section: "", unitId: "", functionId: "" }; + const params = new URLSearchParams(window.location.search); + return { + section: organizationSectionFromQuery(params.get("section")), + unitId: params.get("unit_id") || "", + functionId: params.get("function_id") || "" + }; +} + const EMPTY_MODEL: OrganizationModel = { unit_types: [], structures: [], @@ -345,7 +365,10 @@ export default function OrganizationsPage({ }: OrganizationsPageProps) { const sectionSet = useMemo(() => new Set(availableSections.length ? availableSections : ALL_SECTIONS), [availableSections]); const firstAvailableSection = availableSections.find((section) => sectionSet.has(section)) ?? "model"; - const [active, setActive] = useState(sectionSet.has(initialSection) ? initialSection : firstAvailableSection); + const initialQuery = useMemo(() => organizationsInitialQuery(), []); + const requestedInitialSection = initialQuery.section && sectionSet.has(initialQuery.section) ? initialQuery.section : initialSection; + const [active, setActive] = useState(sectionSet.has(requestedInitialSection) ? requestedInitialSection : firstAvailableSection); + const appliedInitialQueryRef = useRef(false); const visibleSectionGroups = useMemo(() => sectionGroupsFor(sectionSet), [sectionSet]); const [model, setModel] = useState(EMPTY_MODEL); const [loading, setLoading] = useState(true); @@ -784,6 +807,30 @@ export default function OrganizationsPage({ setActive("functions"); }, []); + useEffect(() => { + if (appliedInitialQueryRef.current || loading) return; + if (initialQuery.functionId) { + const item = functionById.get(initialQuery.functionId); + if (item) { + appliedInitialQueryRef.current = true; + editFunction(item); + return; + } + } + if (initialQuery.unitId) { + const item = unitById.get(initialQuery.unitId); + if (item) { + appliedInitialQueryRef.current = true; + editUnit(item); + return; + } + } + if (initialQuery.section && sectionSet.has(initialQuery.section)) { + appliedInitialQueryRef.current = true; + setActive(initialQuery.section); + } + }, [editFunction, editUnit, functionById, initialQuery, loading, sectionSet, unitById]); + const unitTypeColumns: DataGridColumn[] = [ { id: "name", header: "i18n:govoplan-organizations.name.709a2322", minWidth: 180, sortable: true, filterable: true, value: (row) => row.name }, { id: "slug", header: "i18n:govoplan-organizations.slug.094da9b9", width: 160, sortable: true, filterable: true, value: (row) => row.slug },