Files
alpenwerk-hr/app/(app)/orgchart/page.tsx
Andrei Laas ab50c21b8a
All checks were successful
CI / Lint, Typen, Tests, Build (push) Successful in 11m56s
CI / Migrationen auf leerer Datenbank (push) Successful in 10m7s
Klick auf eine Einheit zeigt ihre Angaben
Die naheliegendste Geste in dieser Ansicht war ohne Wirkung: eine Karte im
Organigramm liess sich anklicken und antwortete nicht. Jetzt oeffnet sie eine
Leiste mit dem, was an der Einheit steht -- Orgnummer, Art, die Kette nach
oben, Gueltigkeit, Leitung, Belegschaft, unbesetzte Planstellen, die direkt
untergeordneten Einheiten und die Zahl der Personen im ganzen Teilbaum. Dazu
dieselben zwei Handlungen wie auf der Karte, nur beschriftet statt als Symbol.

Alles daraus stammt aus den Daten, die die Struktursicht ohnehin geladen hat.
Kein zusaetzlicher Gang zur Datenbank und damit auch keine zweite Wahrheit --
was die Leiste zeigt, ist dasselbe, woraus der Baum daneben gezeichnet ist.

Die Liste klickt sich genauso: beide Ansichten kommen aus einem Baum, und eine
Handlung, die es nur in einer von beiden gibt, findet man in der anderen nie.

org_units liefert dafuer zusaetzlich valid_from und valid_to, aber nur an die
Struktursicht. Der Druck kommt ohne sie aus; auf OrgUnitNode stehen sie deshalb
als optionale Felder und nicht als zwei weitere Spalten, die ueberall
mitgeschleppt werden.
2026-09-28 21:27:36 +02:00

51 lines
1.8 KiB
TypeScript

import { Suspense } from "react";
import { OrgChartClient } from "@/components/orgchart/OrgChartClient";
import type { OrgUnitNode } from "@/components/orgchart/types";
import { todayIso } from "@/lib/format";
import { loadOrgAsOf } from "@/lib/orgchart-data";
import { parseIsoDateParam } from "@/lib/reports";
import { currentUserId } from "@/lib/auth/session";
import { withUser } from "@/lib/db";
type SearchParams = { asOf?: string; focus?: string };
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
export default async function OrgChartPage({ searchParams }: { searchParams: Promise<SearchParams> }) {
const params = await searchParams;
const today = todayIso();
const asOf = parseIsoDateParam(params.asOf) ?? today;
// Only ever used to match against ids already on the page, but validated
// so a junk value can't reach the client as an arbitrary string.
const focusId = params.focus && UUID.test(params.focus) ? params.focus : null;
const { org, units } = await withUser(await currentUserId(), async (tx) => {
const [org, units] = await Promise.all([
loadOrgAsOf(tx, asOf),
tx
.selectFrom("org_units")
// valid_from/valid_to nur hier: die Angaben zur Einheit zeigen sie,
// der Druck braucht sie nicht.
.select(["id", "org_number", "name", "parent_id", "unit_type", "valid_from", "valid_to"])
.orderBy("org_number")
.execute(),
]);
return { org, units };
});
return (
<Suspense>
<OrgChartClient
employees={org.employees}
units={units as OrgUnitNode[]}
vacancies={org.vacancies}
asOf={asOf}
today={today}
projectedCount={org.projectedCount}
historyStartsAt={org.historyStartsAt}
focusId={focusId}
/>
</Suspense>
);
}