Neuer Knopf auf Plan-Ebene: Liste plus Wizard in zwei Schritten. Ein
Ist-Satz haengt am PLAN, nicht am Szenario -- die Zuordnung laeuft ueber
die Herkunfts-Kette sourceElementId.
computePlan nimmt neu { actuals }: Die Werte schnappen in jedem erfassten
Jahr auf die Realitaet und laufen von dort planmaessig weiter. Luecken
fallen auf die Plandaten zurueck. Ohne die Option unveraendert -- die 43
Golden Tests laufen durch.
Der Sprung ist keine Rendite: eigene Brueckenposition actualsCorrection
in Vermoegens- und Cash-Bruecke, sonst ginge die Zerlegung nicht auf.
Matrix: Umschalter Plan/Effektiv, im Ist-Modus mit farbiger Abweichung
statt acht Zahlen je Zelle. Zeitachse: Marker je Jahr, juengster farbig.
Vier Analysewerkzeuge mit einheitlicher Leiste (nominal/real als
Einfachauswahl, Plan/Effektiv). MC: Zielbetrag dreht mit, Startjahr
abgeleitet statt eingebbar.
Neue Tabelle ActualsSet (gegen echtes Postgres verifiziert), Module
actuals.ts und dataview.ts. Spezifikation 0.21, 27 Tests (181 -> 208).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
Dices,
|
||||
FileText,
|
||||
FolderKanban,
|
||||
CalendarClock,
|
||||
GitBranch,
|
||||
History,
|
||||
LayoutDashboard,
|
||||
@@ -26,6 +27,9 @@ import { Dashboard } from "@/components/Dashboard";
|
||||
import { MonteCarloDialog } from "@/components/MonteCarloDialog";
|
||||
import { SensitivityDialog } from "@/components/SensitivityDialog";
|
||||
import { LiveSimDialog } from "@/components/LiveSimDialog";
|
||||
import { ActualsDialog } from "@/components/ActualsDialog";
|
||||
import { buildViews } from "@/lib/dataview";
|
||||
import type { ActualsSetInput, ElementOrigin } from "@/lib/actuals";
|
||||
import { VersionHistoryDialog } from "@/components/VersionHistoryDialog";
|
||||
import { SpecView } from "@/components/SpecView";
|
||||
import { SystemParametersView } from "@/components/SystemParametersView";
|
||||
@@ -56,6 +60,10 @@ interface ScenarioDetail {
|
||||
computed: PlanComputed;
|
||||
base: PlanInput | null; // Eltern-Szenario als Vergleichsbasis
|
||||
meta: ScenarioMeta & { planName: string };
|
||||
// Effektive Werte des PLANS plus die Element-Herkunft aller Szenarien -- daraus entsteht
|
||||
// im Browser der zweite Rechenlauf (siehe lib/dataview.ts).
|
||||
actuals: ActualsSetInput[];
|
||||
elementOrigins: ElementOrigin[];
|
||||
}
|
||||
|
||||
// Die Provider (Toast, Bestätigung) müssen UM die Shell liegen, damit deren Hooks
|
||||
@@ -90,6 +98,7 @@ function AppShellInner({ username }: { username: string }) {
|
||||
const [showSensitivity, setShowSensitivity] = useState(false);
|
||||
const [showLiveSim, setShowLiveSim] = useState(false);
|
||||
const [showHistory, setShowHistory] = useState(false);
|
||||
const [showActuals, setShowActuals] = useState(false);
|
||||
const [showSystemParams, setShowSystemParams] = useState(false);
|
||||
const [showPlanTraces, setShowPlanTraces] = useState(false);
|
||||
const [showPalette, setShowPalette] = useState(false);
|
||||
@@ -210,6 +219,14 @@ function AppShellInner({ username }: { username: string }) {
|
||||
|
||||
const activePlan = plans.find((p) => p.scenarios.some((s) => s.id === selectedScenarioId)) ?? null;
|
||||
|
||||
// Plan-Sicht und Ist-Sicht in einem Zug. Ohne erfasste Ist-Werte bleibt `actual` null und
|
||||
// die Oberflaeche verhaelt sich exakt wie bisher.
|
||||
const views = useMemo(
|
||||
() =>
|
||||
detail ? buildViews(detail.plan, detail.actuals ?? [], detail.elementOrigins ?? []) : null,
|
||||
[detail]
|
||||
);
|
||||
|
||||
// Aktionen der Befehls-Palette -- kontextabhängig (Analysen nur bei offenem Szenario).
|
||||
const paletteActions = useMemo<PaletteAction[]>(() => {
|
||||
const base: PaletteAction[] = [
|
||||
@@ -426,6 +443,10 @@ function AppShellInner({ username }: { username: string }) {
|
||||
<BarChart3 className="h-4 w-4" />
|
||||
Grafiken
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => setShowActuals(true)}>
|
||||
<CalendarClock className="h-4 w-4" />
|
||||
Effektive Werte
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => setShowHistory(true)}>
|
||||
<History className="h-4 w-4" />
|
||||
Änderungshistorie
|
||||
@@ -465,6 +486,8 @@ function AppShellInner({ username }: { username: string }) {
|
||||
<PlanView
|
||||
plan={detail.plan}
|
||||
computed={detail.computed}
|
||||
actualComputed={views?.actual ?? null}
|
||||
actualYears={views?.actualYears ?? []}
|
||||
diff={diff}
|
||||
onChanged={refreshCurrent}
|
||||
onOpenSpec={openSpecAt}
|
||||
@@ -525,6 +548,8 @@ function AppShellInner({ username }: { username: string }) {
|
||||
plan={detail.plan}
|
||||
computed={detail.computed}
|
||||
siblings={(activePlan?.scenarios ?? []).filter((s) => s.id !== detail.meta.id)}
|
||||
actuals={detail.actuals ?? []}
|
||||
origins={detail.elementOrigins ?? []}
|
||||
/>
|
||||
</ChartsDialog>
|
||||
)}
|
||||
@@ -535,16 +560,39 @@ function AppShellInner({ username }: { username: string }) {
|
||||
computed={detail.computed}
|
||||
meta={detail.meta}
|
||||
scenarios={activePlan?.scenarios ?? [detail.meta]}
|
||||
actuals={detail.actuals ?? []}
|
||||
origins={detail.elementOrigins ?? []}
|
||||
onClose={() => setShowMonteCarlo(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showSensitivity && detail && (
|
||||
<SensitivityDialog plan={detail.plan} onClose={() => setShowSensitivity(false)} />
|
||||
<SensitivityDialog
|
||||
plan={detail.plan}
|
||||
actuals={detail.actuals ?? []}
|
||||
origins={detail.elementOrigins ?? []}
|
||||
onClose={() => setShowSensitivity(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showLiveSim && detail && (
|
||||
<LiveSimDialog plan={detail.plan} onClose={() => setShowLiveSim(false)} />
|
||||
<LiveSimDialog
|
||||
plan={detail.plan}
|
||||
actuals={detail.actuals ?? []}
|
||||
origins={detail.elementOrigins ?? []}
|
||||
onClose={() => setShowLiveSim(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showActuals && detail && activePlan && (
|
||||
<ActualsDialog
|
||||
planId={detail.meta.planId}
|
||||
planName={detail.meta.planName}
|
||||
scenarioMetas={activePlan.scenarios}
|
||||
initial={{ id: detail.meta.id, name: detail.meta.name, isBase: detail.meta.isBase, plan: detail.plan }}
|
||||
onClose={() => setShowActuals(false)}
|
||||
onChanged={refreshCurrent}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showHistory && detail && (
|
||||
|
||||
Reference in New Issue
Block a user