@sybilion/uilib 1.3.23 → 1.3.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/ui/TextWithDeferTooltip/TextWithDeferTooltip.js +1 -25
- package/dist/esm/components/ui/Tooltip/Tooltip.js +92 -7
- package/dist/esm/components/ui/Tooltip/Tooltip.styl.js +2 -2
- package/dist/esm/components/widgets/DriversComparisonChart/DriversComparisonChart.js +1 -2
- package/dist/esm/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.js +34 -0
- package/dist/esm/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl.js +7 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.constants.js +17 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.js +807 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceChart.styl.js +7 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceTable.js +130 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.js +20 -0
- package/dist/esm/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl.js +7 -0
- package/dist/esm/components/widgets/PerformanceChart/performanceChart.helpers.js +591 -0
- package/dist/esm/components/widgets/PerformanceChart/performanceChartUserSeries.js +109 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/types/src/components/ui/Tooltip/Tooltip.d.ts +3 -3
- package/dist/esm/types/src/components/ui/Tooltip/Tooltip.types.d.ts +1 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.d.ts +7 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceChart.constants.d.ts +3 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceChart.d.ts +54 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceTable.d.ts +31 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.d.ts +20 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/index.d.ts +4 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/performanceChart.helpers.d.ts +212 -0
- package/dist/esm/types/src/components/widgets/PerformanceChart/performanceChartUserSeries.d.ts +20 -0
- package/dist/esm/types/src/docs/pages/PerformanceChartPage.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/ui/TextWithDeferTooltip/TextWithDeferTooltip.tsx +5 -37
- package/src/components/ui/Tooltip/Tooltip.styl +12 -0
- package/src/components/ui/Tooltip/Tooltip.styl.d.ts +1 -0
- package/src/components/ui/Tooltip/Tooltip.tsx +156 -8
- package/src/components/ui/Tooltip/Tooltip.types.ts +1 -0
- package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl +25 -0
- package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.styl.d.ts +11 -0
- package/src/components/widgets/PerformanceChart/HorizonsSelector/HorizonsSelector.tsx +67 -0
- package/src/components/widgets/PerformanceChart/PerformanceChart.constants.ts +17 -0
- package/src/components/widgets/PerformanceChart/PerformanceChart.styl +194 -0
- package/src/components/widgets/PerformanceChart/PerformanceChart.styl.d.ts +30 -0
- package/src/components/widgets/PerformanceChart/PerformanceChart.tsx +1251 -0
- package/src/components/widgets/PerformanceChart/PerformanceTable.tsx +381 -0
- package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl +49 -0
- package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.styl.d.ts +12 -0
- package/src/components/widgets/PerformanceChart/PerformanceUnderChartLegend/PerformanceUnderChartLegend.tsx +83 -0
- package/src/components/widgets/PerformanceChart/index.ts +28 -0
- package/src/components/widgets/PerformanceChart/performanceChart.helpers.ts +790 -0
- package/src/components/widgets/PerformanceChart/performanceChartUserSeries.ts +149 -0
- package/src/docs/pages/PerformanceChartPage.tsx +211 -0
- package/src/docs/pages/TextWithDeferTooltipPage.tsx +26 -10
- package/src/docs/pages/TooltipPage.tsx +30 -0
- package/src/docs/registry.ts +6 -0
- package/src/index.ts +1 -0
package/dist/esm/index.js
CHANGED
|
@@ -106,6 +106,10 @@ export { getDriverImportance, getHighestImportanceDriver } from './components/wi
|
|
|
106
106
|
export { geographicCoordinates, geographicToSVG, getContinentFromRegion, getPreciseCoordinates, getResponsiveCoordinates, svgToPercentage } from './components/widgets/DriverMap/driverMapGeography.js';
|
|
107
107
|
export { DriversComparisonChart } from './components/widgets/DriversComparisonChart/DriversComparisonChart.js';
|
|
108
108
|
export { DRIVER_COMPARISON_CHART_LEAD_MONTHS, DRIVER_FORECAST_ID_BASE, INITIAL_VISIBLE_SERIES_COUNT, buildDriversComparisonChartData, formatSeriesImportance, mergeBacktestsChartData, mergeDatasetHistoricalWithBacktestsChartData } from './components/widgets/DriversComparisonChart/driversComparisonChart.helpers.js';
|
|
109
|
+
export { PerformanceChart } from './components/widgets/PerformanceChart/PerformanceChart.js';
|
|
110
|
+
export { PerformanceTable } from './components/widgets/PerformanceChart/PerformanceTable.js';
|
|
111
|
+
export { SPAGHETTI_DRIFT_PER_HORIZON_ID_BASE, SPAGHETTI_MODEL_PER_HORIZON_ID_BASE, averageForecastErrorsVsHistoricalForMatrixColumn, buildDriftSpaghettiMatrixForCustomDialog, buildPerHorizonSpaghettiEntries, buildSpaghettiMergedChartData, calculateYRangeFromChartData, getForecastModelDisplayName, spaghettiGridFromHistoricalPreviousMonth } from './components/widgets/PerformanceChart/performanceChart.helpers.js';
|
|
112
|
+
export { SPAGHETTI_LOCAL_LS_USER_SERIES_ROW_ID, SPAGHETTI_TIME_SERIES_MATRIX_V, tryParseSpaghettiPerformanceMatrix } from './components/widgets/PerformanceChart/performanceChartUserSeries.js';
|
|
109
113
|
export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
|
|
110
114
|
export { SybilionAuthLayout } from './components/widgets/SybilionAuthLayout/SybilionAuthLayout.js';
|
|
111
115
|
export { SybilionAuthHeadline } from './components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TooltipContentProps, TooltipProps, TooltipProviderProps, TooltipTriggerProps } from './Tooltip.types';
|
|
2
2
|
declare function TooltipProvider({ delayDuration, ...props }: TooltipProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
declare function Tooltip(props: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
declare function TooltipTrigger({ ...props }: TooltipTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
declare function TooltipContent({ className, sideOffset, children, maxWidth, ...props }: TooltipContentProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
declare function Tooltip({ children, ...props }: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function TooltipTrigger({ ref, ...props }: TooltipTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function TooltipContent({ className, sideOffset, children, maxWidth, overTrigger, align, side, avoidCollisions, style: styleProp, ...props }: TooltipContentProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface HorizonsSelectorProps {
|
|
2
|
+
selectedHorizon: string;
|
|
3
|
+
onHorizonChange: (horizon: string) => void;
|
|
4
|
+
availableHorizons: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function HorizonsSelector({ selectedHorizon, onHorizonChange, availableHorizons, }: HorizonsSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
|
|
3
|
+
import type { ForecastData } from '#uilib/types/forecast-data';
|
|
4
|
+
import { type SpaghettiPerformanceMatrixPayload } from './performanceChartUserSeries';
|
|
5
|
+
export type PerformanceViewTab = 'perHorizon' | 'spaghetti';
|
|
6
|
+
export type PerformanceChartPayload = Record<string, {
|
|
7
|
+
forecasts?: Record<string, Record<string, number>>;
|
|
8
|
+
metrics_history?: Record<string, {
|
|
9
|
+
mae?: Record<string, number>;
|
|
10
|
+
mape?: Record<string, number>;
|
|
11
|
+
}>;
|
|
12
|
+
}>;
|
|
13
|
+
export type PerformanceChartProps = {
|
|
14
|
+
performanceData: PerformanceChartPayload | null;
|
|
15
|
+
historicalData?: ChartDataPoint[];
|
|
16
|
+
combinedData?: ChartDataPoint[];
|
|
17
|
+
forecastData?: Record<string, ForecastData>;
|
|
18
|
+
userSeries?: {
|
|
19
|
+
id: number;
|
|
20
|
+
name?: string;
|
|
21
|
+
}[];
|
|
22
|
+
spaghettiUserSeries?: {
|
|
23
|
+
id: number;
|
|
24
|
+
name?: string;
|
|
25
|
+
}[];
|
|
26
|
+
customPerformanceMatrix?: SpaghettiPerformanceMatrixPayload | null;
|
|
27
|
+
customPerformanceLabel?: string | null;
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
chartLoading?: boolean;
|
|
30
|
+
performanceSectionPending?: boolean;
|
|
31
|
+
isEmpty?: boolean;
|
|
32
|
+
perfFetchSettled?: boolean;
|
|
33
|
+
performanceDataLoading?: boolean;
|
|
34
|
+
performanceAnalysisId?: number | null;
|
|
35
|
+
statusHint?: string | null;
|
|
36
|
+
statusTone?: 'destructive' | 'muted';
|
|
37
|
+
runAnalysisHint?: boolean;
|
|
38
|
+
timeRange?: string;
|
|
39
|
+
onTimeRangeChange?: (range: string, meta?: {
|
|
40
|
+
viewTab: PerformanceViewTab;
|
|
41
|
+
}) => void;
|
|
42
|
+
isDarkTheme?: boolean;
|
|
43
|
+
className?: string;
|
|
44
|
+
seriesInitKey?: string;
|
|
45
|
+
toolbarStart?: ReactNode;
|
|
46
|
+
onEditCustomPerformance?: () => void;
|
|
47
|
+
showAddEditCustomDataButton?: boolean;
|
|
48
|
+
addEditCustomDataDisabled?: boolean;
|
|
49
|
+
hiddenSeries?: Set<string>;
|
|
50
|
+
onToggleLegendSeries?: (key: string) => void;
|
|
51
|
+
onEnsureSeriesVisible?: (key: string) => void;
|
|
52
|
+
onHiddenSeriesChange?: (update: Set<string> | ((prev: Set<string>) => Set<string>)) => void;
|
|
53
|
+
};
|
|
54
|
+
export declare function PerformanceChart({ performanceData, historicalData, combinedData, forecastData, userSeries, spaghettiUserSeries, customPerformanceMatrix, customPerformanceLabel, loading, chartLoading, performanceSectionPending, isEmpty, perfFetchSettled, performanceDataLoading, performanceAnalysisId, statusHint, statusTone, runAnalysisHint, timeRange: timeRangeProp, onTimeRangeChange, isDarkTheme, className, seriesInitKey, toolbarStart, onEditCustomPerformance, showAddEditCustomDataButton, addEditCustomDataDisabled, hiddenSeries: hiddenSeriesProp, onToggleLegendSeries, onEnsureSeriesVisible, onHiddenSeriesChange, }: PerformanceChartProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ForecastModelData {
|
|
2
|
+
key: string;
|
|
3
|
+
mae: number;
|
|
4
|
+
mape: number;
|
|
5
|
+
}
|
|
6
|
+
export interface AdjustParameters {
|
|
7
|
+
procurementVolume: number;
|
|
8
|
+
variableRawMaterialCostShare: number;
|
|
9
|
+
controllableCosts: number;
|
|
10
|
+
currentForecastAccuracy: number;
|
|
11
|
+
expectedImprovement: number;
|
|
12
|
+
analystHourlyRate: number;
|
|
13
|
+
}
|
|
14
|
+
interface PerformanceTableProps {
|
|
15
|
+
forecastModels: ForecastModelData[];
|
|
16
|
+
adjustParameters: AdjustParameters;
|
|
17
|
+
onAdjustParametersChange: (params: AdjustParameters) => void;
|
|
18
|
+
/** Shown when custom spaghetti matrix is saved (localStorage). Metrics vs historical for selected horizon. */
|
|
19
|
+
customPerformance?: {
|
|
20
|
+
label: string;
|
|
21
|
+
mae: number;
|
|
22
|
+
mape: number;
|
|
23
|
+
} | null;
|
|
24
|
+
/** Opens custom performance dialog; used by the custom row edit control. */
|
|
25
|
+
onEditCustomPerformance?: () => void;
|
|
26
|
+
/** Last row with Add custom data (hidden when custom row already present); per-horizon + spaghetti. */
|
|
27
|
+
showAddEditCustomDataButton?: boolean;
|
|
28
|
+
addEditCustomDataDisabled?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare function PerformanceTable({ forecastModels, adjustParameters, onAdjustParametersChange, customPerformance, onEditCustomPerformance, showAddEditCustomDataButton, addEditCustomDataDisabled, }: PerformanceTableProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type PerformanceUnderChartLegendRowProps = {
|
|
2
|
+
label: React.ReactNode;
|
|
3
|
+
/** Line color (CSS color string). */
|
|
4
|
+
lineColor: string;
|
|
5
|
+
/** Historical uses solid bar; forecast lines use dashed preview. */
|
|
6
|
+
lineStyle?: 'solid' | 'dashed';
|
|
7
|
+
hidden: boolean;
|
|
8
|
+
onToggle?: () => void;
|
|
9
|
+
};
|
|
10
|
+
export type PerformanceUnderChartLegendItemConfig = PerformanceUnderChartLegendRowProps & {
|
|
11
|
+
id: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function PerformanceUnderChartLegendRow({ label, lineColor, lineStyle, hidden, onToggle, }: PerformanceUnderChartLegendRowProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
/** Renders rows from tab-agnostic config (labels + toggles supplied by parent). */
|
|
15
|
+
export declare function PerformanceUnderChartLegendFromItems({ items, }: {
|
|
16
|
+
items: PerformanceUnderChartLegendItemConfig[];
|
|
17
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function PerformanceUnderChartLegend({ children, }: {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { PerformanceChart, type PerformanceChartPayload, type PerformanceChartProps, type PerformanceViewTab, } from './PerformanceChart';
|
|
2
|
+
export { type AdjustParameters, type ForecastModelData, PerformanceTable, } from './PerformanceTable';
|
|
3
|
+
export { SPAGHETTI_DRIFT_PER_HORIZON_ID_BASE, SPAGHETTI_MODEL_PER_HORIZON_ID_BASE, averageForecastErrorsVsHistoricalForMatrixColumn, buildDriftSpaghettiMatrixForCustomDialog, buildPerHorizonSpaghettiEntries, buildSpaghettiMergedChartData, calculateYRangeFromChartData, getForecastModelDisplayName, spaghettiGridFromHistoricalPreviousMonth, } from './performanceChart.helpers';
|
|
4
|
+
export { SPAGHETTI_LOCAL_LS_USER_SERIES_ROW_ID, SPAGHETTI_TIME_SERIES_MATRIX_V, tryParseSpaghettiPerformanceMatrix, type SpaghettiPerformanceMatrixPayload, } from './performanceChartUserSeries';
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for Performance Tab calculations
|
|
3
|
+
* Note: ROI/calculatons.ts is only for reference/example
|
|
4
|
+
*/
|
|
5
|
+
import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
|
|
6
|
+
import type { ForecastData } from '#uilib/types/forecast-data';
|
|
7
|
+
import type { SpaghettiPerformanceMatrixPayload } from './performanceChartUserSeries';
|
|
8
|
+
export type RealBacktestsEntry = {
|
|
9
|
+
forecast_start: string;
|
|
10
|
+
forecast_end: string;
|
|
11
|
+
forecast_series: Record<string, number>;
|
|
12
|
+
};
|
|
13
|
+
/** Legacy: API backtest spaghetti lines used `SPAGHETTI_FORECAST_ID_BASE + i` (spaghetti view now uses drift per-horizon instead). */
|
|
14
|
+
export declare const SPAGHETTI_FORECAST_ID_BASE = 6000;
|
|
15
|
+
/** Model PER_HORIZON_TO_SPAGHETTI lines use `SPAGHETTI_MODEL_PER_HORIZON_ID_BASE + i`. */
|
|
16
|
+
export declare const SPAGHETTI_MODEL_PER_HORIZON_ID_BASE = 7000;
|
|
17
|
+
/** Drift PER_HORIZON_TO_SPAGHETTI lines use `SPAGHETTI_DRIFT_PER_HORIZON_ID_BASE + i`. */
|
|
18
|
+
export declare const SPAGHETTI_DRIFT_PER_HORIZON_ID_BASE = 8000;
|
|
19
|
+
export declare function isSpaghettiModelPerHorizonLineId(id: number): boolean;
|
|
20
|
+
export declare function isSpaghettiDriftPerHorizonLineId(id: number): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Converts `performance.model` / `performance.drift` per-horizon forecasts into synthetic
|
|
23
|
+
* backtest-shaped entries: each line is [horizon_1[i], …, horizon_n[i]] as date→value points
|
|
24
|
+
* (aligned by sorted key index per horizon).
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildPerHorizonSpaghettiEntries(forecastRoot: {
|
|
27
|
+
forecasts?: Record<string, Record<string, number>>;
|
|
28
|
+
} | null | undefined, horizonKeys: string[]): RealBacktestsEntry[];
|
|
29
|
+
/**
|
|
30
|
+
* Same row alignment as {@link buildPerHorizonSpaghettiEntries}: row `i` uses each horizon's
|
|
31
|
+
* i-th sorted forecast month; `dates[i]` is horizon_1's month at that row (Date column).
|
|
32
|
+
* Use this for custom dialog seed + “copy statistical baseline (drift)” prefill.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildDriftSpaghettiMatrixForCustomDialog(driftRoot: {
|
|
35
|
+
forecasts?: Record<string, Record<string, number>>;
|
|
36
|
+
} | null | undefined, horizonKeys: string[]): {
|
|
37
|
+
dates: string[];
|
|
38
|
+
grid: number[][];
|
|
39
|
+
perHorizonDates: string[][];
|
|
40
|
+
} | null;
|
|
41
|
+
/**
|
|
42
|
+
* Prefill for custom performance when copying drift layout: each spaghetti row is flat at the
|
|
43
|
+
* historical value for the month before the earliest forecast month in that row (same anchor as
|
|
44
|
+
* chart connection-point logic).
|
|
45
|
+
*/
|
|
46
|
+
export declare function spaghettiGridFromHistoricalPreviousMonth(perHorizonDates: string[][], horizonCount: number, historicalByDate: Map<string, number>): number[][];
|
|
47
|
+
/** Mean absolute error / MAPE vs historical for one horizon column of a spaghetti matrix (aligned by month). */
|
|
48
|
+
export declare function averageForecastErrorsVsHistoricalForMatrixColumn(matrix: SpaghettiPerformanceMatrixPayload, horizonColumnIndex: number, historicalByDate: Map<string, number>): {
|
|
49
|
+
mae: number;
|
|
50
|
+
mape: number;
|
|
51
|
+
} | null;
|
|
52
|
+
/** @deprecated Use {@link buildPerHorizonSpaghettiEntries} (same implementation). */
|
|
53
|
+
export declare const buildModelPerHorizonSpaghettiEntries: typeof buildPerHorizonSpaghettiEntries;
|
|
54
|
+
export declare function mergeSpaghettiMergedBases(a: {
|
|
55
|
+
mergedData: ChartDataPoint[];
|
|
56
|
+
seriesMeta: {
|
|
57
|
+
id: number;
|
|
58
|
+
label: string;
|
|
59
|
+
}[];
|
|
60
|
+
}, b: {
|
|
61
|
+
mergedData: ChartDataPoint[];
|
|
62
|
+
seriesMeta: {
|
|
63
|
+
id: number;
|
|
64
|
+
label: string;
|
|
65
|
+
}[];
|
|
66
|
+
}): {
|
|
67
|
+
mergedData: ChartDataPoint[];
|
|
68
|
+
seriesMeta: {
|
|
69
|
+
id: number;
|
|
70
|
+
label: string;
|
|
71
|
+
}[];
|
|
72
|
+
};
|
|
73
|
+
export declare function buildSpaghettiMergedChartData(entries: RealBacktestsEntry[], historicalChartData: ChartDataPoint[], idBase?: number): {
|
|
74
|
+
mergedData: ChartDataPoint[];
|
|
75
|
+
seriesMeta: {
|
|
76
|
+
id: number;
|
|
77
|
+
label: string;
|
|
78
|
+
}[];
|
|
79
|
+
};
|
|
80
|
+
/** Appends forecast-backed user series (from dataset context) onto spaghetti backtest lines. */
|
|
81
|
+
export declare function mergeSpaghettiUserSeriesFromForecastData(base: {
|
|
82
|
+
mergedData: ChartDataPoint[];
|
|
83
|
+
seriesMeta: {
|
|
84
|
+
id: number;
|
|
85
|
+
label: string;
|
|
86
|
+
}[];
|
|
87
|
+
}, userSeries: {
|
|
88
|
+
id: number;
|
|
89
|
+
name?: string;
|
|
90
|
+
}[], forecastData: Record<string, ForecastData>): {
|
|
91
|
+
mergedData: ChartDataPoint[];
|
|
92
|
+
seriesMeta: {
|
|
93
|
+
id: number;
|
|
94
|
+
label: string;
|
|
95
|
+
}[];
|
|
96
|
+
};
|
|
97
|
+
export declare function filterChartDataLast24Months(data: ChartDataPoint[], months: number): ChartDataPoint[];
|
|
98
|
+
/**
|
|
99
|
+
* Spaghetti chart x-range: from two months before the earliest forecast_start
|
|
100
|
+
* (per-horizon synthetic entries + mergeable user forecast series), inclusive.
|
|
101
|
+
* Falls back to last N months when no forecast candidates exist.
|
|
102
|
+
*
|
|
103
|
+
* When `historicalWindowFloor` is set (e.g. first month of per-horizon `filtered24mData`),
|
|
104
|
+
* the range start is floored to that month so the historical line matches the per-horizon tab.
|
|
105
|
+
*
|
|
106
|
+
* When `historicalWindowCeiling` is set (e.g. last month of `filtered24mData`), drops points after
|
|
107
|
+
* that month so spaghetti X matches per-horizon (per-horizon chart trims forecasts past last historical).
|
|
108
|
+
*/
|
|
109
|
+
export declare function filterSpaghettiDataFromEarliestForecastStart(mergedData: ChartDataPoint[], entries: RealBacktestsEntry[], userSeries: {
|
|
110
|
+
id: number;
|
|
111
|
+
name?: string;
|
|
112
|
+
}[], forecastData: Record<string, ForecastData>,
|
|
113
|
+
/** Series meta from the first merged batch (e.g. drift) — used to skip duplicate user-series ids. */
|
|
114
|
+
firstBatchSeriesMeta: {
|
|
115
|
+
id: number;
|
|
116
|
+
label: string;
|
|
117
|
+
}[], fallbackMonths: number, extraForecastCandidates?: RealBacktestsEntry[], historicalWindowFloor?: string | null, historicalWindowCeiling?: string | null): ChartDataPoint[];
|
|
118
|
+
/**
|
|
119
|
+
* Ensure each spaghetti row has `historical` from {@link historicalChartData} when that month
|
|
120
|
+
* falls in the filtered window — matches per-horizon chart (actuals line), and fills months that
|
|
121
|
+
* exist in history but were missing after merge/filter.
|
|
122
|
+
*/
|
|
123
|
+
export declare function mergeHistoricalIntoSpaghettiChartData(filteredRows: ChartDataPoint[], historicalChartData: ChartDataPoint[]): ChartDataPoint[];
|
|
124
|
+
/**
|
|
125
|
+
* Calculate Accuracy: 100% - MAPE
|
|
126
|
+
* @param mape - MAPE value as decimal (e.g., 0.0436 for 4.36%)
|
|
127
|
+
* @returns Accuracy percentage
|
|
128
|
+
*/
|
|
129
|
+
export declare function calculateAccuracy(mape: number): number;
|
|
130
|
+
/**
|
|
131
|
+
* Format Accuracy as percentage
|
|
132
|
+
* @param value - Accuracy value
|
|
133
|
+
* @returns Formatted accuracy string (e.g., "97%")
|
|
134
|
+
*/
|
|
135
|
+
export declare function formatAccuracy(value: number): string;
|
|
136
|
+
/**
|
|
137
|
+
* Format Error as "$/Ton"
|
|
138
|
+
* @param mae - MAE value from metrics_summary.24m.mae
|
|
139
|
+
* @returns Formatted error string (e.g., "0.05$/Ton")
|
|
140
|
+
*/
|
|
141
|
+
export declare function formatError(mae: number): string;
|
|
142
|
+
/**
|
|
143
|
+
* Calculate ROI
|
|
144
|
+
* Reference: ROI/calculatons.ts for example logic
|
|
145
|
+
* @param totalBenefit - Total annual benefit
|
|
146
|
+
* @param operatingCost - Annual operating cost
|
|
147
|
+
* @returns ROI percentage
|
|
148
|
+
*/
|
|
149
|
+
export declare function calculateROI(totalBenefit: number, operatingCost: number): number;
|
|
150
|
+
/**
|
|
151
|
+
* Calculate ROI Multiple
|
|
152
|
+
* Formula: ROI Multiple = ROI / 100
|
|
153
|
+
* Where ROI = (AB - IC) / IC × 100
|
|
154
|
+
* @param totalBenefit - Total annual benefit (AB)
|
|
155
|
+
* @param operatingCost - Annual operating cost (IC)
|
|
156
|
+
* @returns ROI multiple (e.g., 1.0 for 100% ROI, 2.0 for 200% ROI)
|
|
157
|
+
*/
|
|
158
|
+
export declare function calculateROIMultiple(totalBenefit: number, operatingCost: number): number;
|
|
159
|
+
/**
|
|
160
|
+
* Format ROI as multiplier (xN format)
|
|
161
|
+
* Formula: ROI Multiple = ROI / 100
|
|
162
|
+
* Examples: 100% ROI = x1, 200% ROI = x2, 0% ROI = x0
|
|
163
|
+
* Note: Negative ROI (when benefit < cost) is displayed as x1
|
|
164
|
+
* @param totalBenefit - Total annual benefit (AB)
|
|
165
|
+
* @param operatingCost - Annual operating cost (IC)
|
|
166
|
+
* @returns Formatted ROI string (e.g., "x1.5")
|
|
167
|
+
*/
|
|
168
|
+
export declare function formatROI(totalBenefit: number, operatingCost: number): string;
|
|
169
|
+
/**
|
|
170
|
+
* Calculate Benefit p/a
|
|
171
|
+
* Formula: Annual Benefit = PV × V × C × PI
|
|
172
|
+
* Where:
|
|
173
|
+
* - PV = Procurement Volume
|
|
174
|
+
* - V = Variable Raw Material Share (as decimal)
|
|
175
|
+
* - C = Controllable Cost Share (as decimal)
|
|
176
|
+
* - PI = Price Improvement = |FA_new - FA_current| × 0.2 (correlation factor)
|
|
177
|
+
* @param mae - MAE value (not used in calculation, kept for backward compatibility)
|
|
178
|
+
* @param mape - MAPE value (used to calculate actual forecast accuracy)
|
|
179
|
+
* @param adjustParams - Adjust parameters from dialog
|
|
180
|
+
* @param baselineAccuracy - Optional baseline accuracy for comparison (if provided, uses actual improvement)
|
|
181
|
+
* @returns Benefit per annum
|
|
182
|
+
*/
|
|
183
|
+
export declare function calculateBenefit(mae: number, mape: number, adjustParams: {
|
|
184
|
+
procurementVolume: number;
|
|
185
|
+
variableRawMaterialCostShare: number;
|
|
186
|
+
controllableCosts: number;
|
|
187
|
+
currentForecastAccuracy: number;
|
|
188
|
+
expectedImprovement: number;
|
|
189
|
+
analystHourlyRate: number;
|
|
190
|
+
}, baselineAccuracy?: number): number;
|
|
191
|
+
/**
|
|
192
|
+
* Format Benefit as euros
|
|
193
|
+
* @param value - Benefit value
|
|
194
|
+
* @returns Formatted benefit string (e.g., "€616.640")
|
|
195
|
+
*/
|
|
196
|
+
export declare function formatBenefit(value: number): string;
|
|
197
|
+
/**
|
|
198
|
+
* Map forecast model key to display name
|
|
199
|
+
* @param key - Forecast model key (e.g., "mean", "drift", "seasonal")
|
|
200
|
+
* @returns Display name (e.g., "Mean", "Drift", "Seasonal")
|
|
201
|
+
*/
|
|
202
|
+
export declare function getForecastModelDisplayName(key: string): string;
|
|
203
|
+
/**
|
|
204
|
+
* Calculate Y range (min/max) from chart data points
|
|
205
|
+
* Extracts all numeric values from chart data points and calculates min/max with padding
|
|
206
|
+
* @param chartData - Array of chart data points
|
|
207
|
+
* @returns Object with yMin and yMax values
|
|
208
|
+
*/
|
|
209
|
+
export declare function calculateYRangeFromChartData(chartData: Array<Record<string, unknown>>): {
|
|
210
|
+
yMin: number;
|
|
211
|
+
yMax: number;
|
|
212
|
+
};
|
package/dist/esm/types/src/components/widgets/PerformanceChart/performanceChartUserSeries.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ForecastData } from '#uilib/types/forecast-data';
|
|
2
|
+
export declare const SPAGHETTI_TIME_SERIES_MATRIX_V: 2;
|
|
3
|
+
export interface SpaghettiPerformanceMatrixPayload {
|
|
4
|
+
v: typeof SPAGHETTI_TIME_SERIES_MATRIX_V;
|
|
5
|
+
dates: string[];
|
|
6
|
+
horizonKeys: string[];
|
|
7
|
+
grid: number[][];
|
|
8
|
+
perHorizonDates?: string[][];
|
|
9
|
+
}
|
|
10
|
+
export declare const SPAGHETTI_MATRIX_SYNTHETIC_BASE = 9800000;
|
|
11
|
+
export declare const SPAGHETTI_MATRIX_MAX_COLS = 128;
|
|
12
|
+
export declare const SPAGHETTI_LOCAL_LS_USER_SERIES_ROW_ID = 9000001;
|
|
13
|
+
export declare function spaghettiMatrixSyntheticId(userSeriesRowId: number, horizonIndex: number): number;
|
|
14
|
+
export declare function isSpaghettiMatrixSyntheticLineId(id: number): boolean;
|
|
15
|
+
export declare function getCustomMatrixSeriesForHorizonTab(matrix: SpaghettiPerformanceMatrixPayload, horizonKey: string, rowId: number, forecastData: Record<string, ForecastData> | undefined): {
|
|
16
|
+
lineId: number;
|
|
17
|
+
dates: string[];
|
|
18
|
+
forecastValues: number[];
|
|
19
|
+
} | null;
|
|
20
|
+
export declare function tryParseSpaghettiPerformanceMatrix(parsed: unknown): SpaghettiPerformanceMatrixPayload | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function PerformanceChartPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -69,6 +69,7 @@ export * from './components/widgets/SidebarDatasetsItemsGrouped';
|
|
|
69
69
|
export * from './components/widgets/DriverCard';
|
|
70
70
|
export * from './components/widgets/DriverMap';
|
|
71
71
|
export * from './components/widgets/DriversComparisonChart';
|
|
72
|
+
export * from './components/widgets/PerformanceChart';
|
|
72
73
|
export * from './components/widgets/SybilionAppHeader';
|
|
73
74
|
export * from './components/widgets/SybilionAuthLayout';
|
|
74
75
|
export * from './components/widgets/SybilionSignInPanel';
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Tooltip,
|
|
@@ -18,9 +18,7 @@ function TextWithDeferTooltip({
|
|
|
18
18
|
...props
|
|
19
19
|
}: TextWithDeferTooltipProps) {
|
|
20
20
|
const [withTooltip, setWithTooltip] = useState(false);
|
|
21
|
-
const [tooltipStyles, setTooltipStyles] = useState<CSSProperties>({});
|
|
22
21
|
const ref = useRef<HTMLDivElement>(null);
|
|
23
|
-
const cachedFontSizeRef = useRef<string | null>(null);
|
|
24
22
|
|
|
25
23
|
const handleMouseEnter = () => {
|
|
26
24
|
if (!ref.current) return;
|
|
@@ -31,33 +29,6 @@ function TextWithDeferTooltip({
|
|
|
31
29
|
ref.current.scrollHeight - ref.current.clientHeight > 3;
|
|
32
30
|
|
|
33
31
|
if (isOverflowingHorizontally || isOverflowingVertically) {
|
|
34
|
-
const styles: CSSProperties = {
|
|
35
|
-
fontSize: cachedFontSizeRef.current || undefined,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (ref.current) {
|
|
39
|
-
const {
|
|
40
|
-
width: rectWidth,
|
|
41
|
-
left,
|
|
42
|
-
top,
|
|
43
|
-
} = ref.current.getBoundingClientRect();
|
|
44
|
-
|
|
45
|
-
styles.width = `${width ?? rectWidth}px`;
|
|
46
|
-
|
|
47
|
-
if (!cachedFontSizeRef.current) {
|
|
48
|
-
const { fontSize } = window.getComputedStyle(ref.current);
|
|
49
|
-
cachedFontSizeRef.current = fontSize;
|
|
50
|
-
styles.fontSize = fontSize;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (overTrigger) {
|
|
54
|
-
styles.transform = `translate(${left}px, ${top}px) !important`;
|
|
55
|
-
// styles.translateX = `${left}px`;
|
|
56
|
-
// styles.translateY = `${top}px`;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
setTooltipStyles(styles);
|
|
61
32
|
setWithTooltip(true);
|
|
62
33
|
}
|
|
63
34
|
};
|
|
@@ -74,17 +45,14 @@ function TextWithDeferTooltip({
|
|
|
74
45
|
);
|
|
75
46
|
|
|
76
47
|
if (withTooltip) {
|
|
77
|
-
const tooltipSide = overTrigger ? 'bottom' : side;
|
|
78
|
-
|
|
79
48
|
return (
|
|
80
49
|
<Tooltip open={withTooltip} onOpenChange={setWithTooltip}>
|
|
81
50
|
<TooltipTrigger asChild>{textElement}</TooltipTrigger>
|
|
82
51
|
<TooltipContent
|
|
83
|
-
side={
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}}
|
|
52
|
+
side={side}
|
|
53
|
+
overTrigger={overTrigger}
|
|
54
|
+
maxWidth={maxWidth}
|
|
55
|
+
style={width !== undefined ? { width: `${width}px` } : undefined}
|
|
88
56
|
>
|
|
89
57
|
{children}
|
|
90
58
|
</TooltipContent>
|
|
@@ -57,6 +57,18 @@
|
|
|
57
57
|
&[data-state="closed"][data-side="top"]
|
|
58
58
|
animation fade-out 0.1s ease-in, zoom-out 0.1s ease-in
|
|
59
59
|
|
|
60
|
+
.tooltipContentOverTrigger
|
|
61
|
+
box-sizing border-box
|
|
62
|
+
height auto
|
|
63
|
+
|
|
64
|
+
&[data-state="open"],
|
|
65
|
+
&[data-state="instant-open"],
|
|
66
|
+
&[data-state="delayed-open"]
|
|
67
|
+
animation fade-in 0.15s ease-out
|
|
68
|
+
|
|
69
|
+
&[data-state="closed"]
|
|
70
|
+
animation fade-out 0.1s ease-in
|
|
71
|
+
|
|
60
72
|
.tooltipArrow
|
|
61
73
|
z-index 50
|
|
62
74
|
width 10px
|