Eine leere Organisationseinheit wieder entfernen
Der Papierkorb neben dem Plus, im Organigramm wie in der Liste, und nur dort, wo nichts darunter haengt. Ein Knopf, der beim Klick eine Absage erteilt, ist schlechter als kein Knopf -- die Datenbank prueft es trotzdem, denn sie sieht auch geschlossene Planstellen, die im Baum gar nicht gezeichnet sind. Abgewiesen wird mit Grund: untergeordnete Einheiten, Planstellen (geschlossene zaehlen mit), Kostenstellen, die darauf verweisen, und die Wurzel selbst. Geloescht und nicht geschlossen, und das ist eine bewusste Einschraenkung. delete_position macht seit dem OM-Umbau den Unterschied vor: besetzt gewesen → valid_to, nie besetzt gewesen → weg. Fuer Einheiten laesst sich davon heute nur die zweite Haelfte umsetzen, weil ein valid_to an einer Einheit zwar eingetragen, aber nirgends gelesen wuerde -- weder Organigramm noch orgMapsAbfragen, Berichte, Druck oder die Auswahl beim Anlegen einer Planstelle schraenken org_units auf den Stichtag ein. Die geschlossene Einheit staende ueberall weiter da, nur mit einem Datum, das niemand sieht. Das Schliessen zum Stichtag kommt, wenn org_units gegen den Stichtag gelesen wird -- dieselbe Arbeit, die auch das Verschieben braucht.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Handle, Position, type Node, type NodeProps } from "@xyflow/react";
|
||||
import { Building2, ChevronDown, Plus, UserRound } from "lucide-react";
|
||||
import { Building2, ChevronDown, Plus, Trash2, UserRound } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { memo } from "react";
|
||||
import { Avatar } from "@/components/ui/Avatar";
|
||||
@@ -16,6 +16,7 @@ export type OrgChartNodeData = {
|
||||
onToggle: (id: string) => void;
|
||||
/** Nur in der Struktursicht gesetzt — ohne sie bleibt die Karte unverändert. */
|
||||
onAddUnit?: (unitId: string) => void;
|
||||
onDeleteUnit?: (unitId: string) => void;
|
||||
};
|
||||
|
||||
export type OrgChartRFNode = Node<OrgChartNodeData, "orgNode">;
|
||||
@@ -44,7 +45,7 @@ const KIND_SHELL: Record<ChartNodeKind, string> = {
|
||||
// React Flow re-renders node components on every pan/zoom frame — memo is
|
||||
// required, not just tidy, to keep that smooth at a few hundred nodes.
|
||||
export const OrgChartNode = memo(function OrgChartNode({ id, data }: NodeProps<OrgChartRFNode>) {
|
||||
const { chartNode, expanded, hasChildren, childCount, onToggle, onAddUnit } = data;
|
||||
const { chartNode, expanded, hasChildren, childCount, onToggle, onAddUnit, onDeleteUnit } = data;
|
||||
const { kind, label, sublabel, avatar, href, vacant, totalReports, absent, coveredBy, coveringFor, unitId } = chartNode;
|
||||
const isMatch = chartNode.matched ?? false;
|
||||
const { width, height } = NODE_DIMENSIONS[kind];
|
||||
@@ -113,21 +114,44 @@ export const OrgChartNode = memo(function OrgChartNode({ id, data }: NodeProps<O
|
||||
achtzig ständig sichtbare Pluszeichen ein Muster und kein Angebot.
|
||||
Auf Geräten ohne Zeigegerät bleibt er stehen — dort gibt es kein
|
||||
Überfahren, und unsichtbar hiesse dann unerreichbar. */}
|
||||
{unitId && onAddUnit && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onAddUnit(unitId)}
|
||||
aria-label={`Einheit unter ${label} anlegen`}
|
||||
title="Untergeordnete Einheit anlegen"
|
||||
className="nodrag nopan absolute -right-2.5 -top-2.5 z-10 flex h-6 w-6 items-center justify-center rounded-full
|
||||
border border-border bg-white text-ink-muted shadow-sm transition-colors
|
||||
hover:border-brand-500 hover:bg-brand-500 hover:text-white
|
||||
focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-brand-500
|
||||
opacity-0 group-hover:opacity-100 focus-visible:opacity-100
|
||||
{unitId && (onAddUnit || onDeleteUnit) && (
|
||||
<span
|
||||
className="nodrag nopan absolute -right-2.5 -top-2.5 z-10 flex items-center gap-1
|
||||
opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100
|
||||
[@media(hover:none)]:opacity-100"
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
{/* Der Papierkorb nur am Blatt. Eine Einheit mit Kindern lässt sich
|
||||
ohnehin nicht entfernen — der Knopf wäre dort ein Angebot, das
|
||||
beim Klick eine Absage erteilt, und das ist schlechter als kein
|
||||
Knopf. Die Datenbank prüft es trotzdem: sie sieht auch
|
||||
geschlossene Planstellen, die hier gar nicht gezeichnet sind. */}
|
||||
{onDeleteUnit && !hasChildren && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDeleteUnit(unitId)}
|
||||
aria-label={`Einheit ${label} entfernen`}
|
||||
title="Einheit entfernen"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-full border border-border bg-white text-ink-muted shadow-sm
|
||||
transition-colors hover:border-danger-solid hover:bg-danger-solid hover:text-white
|
||||
focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-brand-500"
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
{onAddUnit && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onAddUnit(unitId)}
|
||||
aria-label={`Einheit unter ${label} anlegen`}
|
||||
title="Untergeordnete Einheit anlegen"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-full border border-border bg-white text-ink-muted shadow-sm
|
||||
transition-colors hover:border-brand-500 hover:bg-brand-500 hover:text-white
|
||||
focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-brand-500"
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Accent stripe, inset so it follows the card's rounded corner. */}
|
||||
|
||||
Reference in New Issue
Block a user