@sybilion/uilib 1.3.22 → 1.3.25
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/widgets/DriversComparisonChart/DriversComparisonChart.js +139 -0
- package/dist/esm/components/widgets/DriversComparisonChart/DriversComparisonChart.styl.js +7 -0
- package/dist/esm/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.js +159 -0
- 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 +6 -0
- package/dist/esm/types/src/components/widgets/DriversComparisonChart/DriversComparisonChart.d.ts +18 -0
- package/dist/esm/types/src/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.d.ts +26 -0
- package/dist/esm/types/src/components/widgets/DriversComparisonChart/index.d.ts +2 -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/DriversComparisonChartPage.d.ts +1 -0
- package/dist/esm/types/src/docs/pages/PerformanceChartPage.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +2 -0
- package/dist/esm/utils/chartConnectionPoint.js +9 -1
- package/package.json +1 -1
- package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.styl +145 -0
- package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.styl.d.ts +29 -0
- package/src/components/widgets/DriversComparisonChart/DriversComparisonChart.tsx +325 -0
- package/src/components/widgets/DriversComparisonChart/driversComparisonChart.helpers.ts +206 -0
- package/src/components/widgets/DriversComparisonChart/index.ts +13 -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/DriversComparisonChartPage.tsx +174 -0
- package/src/docs/pages/PerformanceChartPage.tsx +211 -0
- package/src/docs/registry.ts +12 -0
- package/src/index.ts +2 -0
package/dist/esm/index.js
CHANGED
|
@@ -104,6 +104,12 @@ export { DriverMap } from './components/widgets/DriverMap/DriverMap.js';
|
|
|
104
104
|
export { getCategoryIcon } from './components/widgets/DriverMap/driverCategoryIcon.js';
|
|
105
105
|
export { getDriverImportance, getHighestImportanceDriver } from './components/widgets/DriverMap/driverMapSelection.js';
|
|
106
106
|
export { geographicCoordinates, geographicToSVG, getContinentFromRegion, getPreciseCoordinates, getResponsiveCoordinates, svgToPercentage } from './components/widgets/DriverMap/driverMapGeography.js';
|
|
107
|
+
export { DriversComparisonChart } from './components/widgets/DriversComparisonChart/DriversComparisonChart.js';
|
|
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';
|
|
107
113
|
export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
|
|
108
114
|
export { SybilionAuthLayout } from './components/widgets/SybilionAuthLayout/SybilionAuthLayout.js';
|
|
109
115
|
export { SybilionAuthHeadline } from './components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js';
|
package/dist/esm/types/src/components/widgets/DriversComparisonChart/DriversComparisonChart.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
|
|
2
|
+
import type { BacktestsComponentPayload } from '@sybilion/platform-sdk';
|
|
3
|
+
export type DriversComparisonChartProps = {
|
|
4
|
+
payload: BacktestsComponentPayload | null;
|
|
5
|
+
datasetHistorical?: ChartDataPoint[];
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
chartLoading?: boolean;
|
|
8
|
+
statusHint?: string | null;
|
|
9
|
+
statusTone?: 'destructive' | 'muted';
|
|
10
|
+
runAnalysisHint?: boolean;
|
|
11
|
+
timeRange?: string;
|
|
12
|
+
onTimeRangeChange?: (range: string) => void;
|
|
13
|
+
isDarkTheme?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Resets visible series when this key changes (e.g. selected analysis id). */
|
|
16
|
+
seriesInitKey?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function DriversComparisonChart({ payload, datasetHistorical, loading, chartLoading, statusHint, statusTone, runAnalysisHint, timeRange: timeRangeProp, onTimeRangeChange, isDarkTheme, className, seriesInitKey, }: DriversComparisonChartProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
|
|
2
|
+
import type { BacktestsComponentPayload } from '@sybilion/platform-sdk';
|
|
3
|
+
export declare const DRIVER_FORECAST_ID_BASE = 8000000;
|
|
4
|
+
export declare const INITIAL_VISIBLE_SERIES_COUNT = 3;
|
|
5
|
+
/** Months of historical context before the earliest forecast month (inclusive). */
|
|
6
|
+
export declare const DRIVER_COMPARISON_CHART_LEAD_MONTHS = 6;
|
|
7
|
+
export declare function formatSeriesImportance(value: number | null): string;
|
|
8
|
+
export declare function mergeBacktestsChartData(payload: BacktestsComponentPayload | null): ChartDataPoint[];
|
|
9
|
+
/** While drivers comparison is not loaded: dataset historical only. After load: normalized historical from target.normalized_series (see mergeBacktestsChartData) replaces it. */
|
|
10
|
+
export declare function mergeDatasetHistoricalWithBacktestsChartData(datasetHistorical: ChartDataPoint[], backtestsMerged: ChartDataPoint[]): ChartDataPoint[];
|
|
11
|
+
/**
|
|
12
|
+
* For each driver, first month with materially non-zero value; anchor = median of those months.
|
|
13
|
+
* (Min is too early with outliers; max matched logs where one driver started 2017-12 while most started 2015-01.)
|
|
14
|
+
*/
|
|
15
|
+
export declare function getZoomAnchorMonthFromDriverMaterialStarts(points: ChartDataPoint[], forecastIds: number[]): {
|
|
16
|
+
anchor: string | null;
|
|
17
|
+
perDriverFirstMaterial: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare function subtractMonthsFromMonthStart(date: string, count: number): string;
|
|
20
|
+
/**
|
|
21
|
+
* Backtests payload often starts at the same month for target + drivers, so xMin falls
|
|
22
|
+
* in a range with no rows. Prepend historical-only months from raw dataset series
|
|
23
|
+
* (scaled to the first normalized point) so the lead-in shows the target line alone.
|
|
24
|
+
*/
|
|
25
|
+
export declare function prependHistoricalLeadFromDataset(points: ChartDataPoint[], datasetHistorical: ChartDataPoint[], xMin: string): ChartDataPoint[];
|
|
26
|
+
export declare function buildDriversComparisonChartData(mergedWithHistorical: ChartDataPoint[], datasetHistorical: ChartDataPoint[], forecastIds: number[]): ChartDataPoint[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { DriversComparisonChart, type DriversComparisonChartProps, } from './DriversComparisonChart';
|
|
2
|
+
export { buildDriversComparisonChartData, DRIVER_COMPARISON_CHART_LEAD_MONTHS, DRIVER_FORECAST_ID_BASE, formatSeriesImportance, INITIAL_VISIBLE_SERIES_COUNT, mergeBacktestsChartData, mergeDatasetHistoricalWithBacktestsChartData, } from './driversComparisonChart.helpers';
|
|
@@ -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 DriversComparisonChartPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function PerformanceChartPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -68,6 +68,8 @@ export * from './components/ui/WorkspaceAppSwitcher';
|
|
|
68
68
|
export * from './components/widgets/SidebarDatasetsItemsGrouped';
|
|
69
69
|
export * from './components/widgets/DriverCard';
|
|
70
70
|
export * from './components/widgets/DriverMap';
|
|
71
|
+
export * from './components/widgets/DriversComparisonChart';
|
|
72
|
+
export * from './components/widgets/PerformanceChart';
|
|
71
73
|
export * from './components/widgets/SybilionAppHeader';
|
|
72
74
|
export * from './components/widgets/SybilionAuthLayout';
|
|
73
75
|
export * from './components/widgets/SybilionSignInPanel';
|
|
@@ -101,5 +101,13 @@ function getPreviousMonth(date) {
|
|
|
101
101
|
d.setMonth(d.getMonth() - 1);
|
|
102
102
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the next month date (first day of next month)
|
|
106
|
+
*/
|
|
107
|
+
function getNextMonth(date) {
|
|
108
|
+
const d = new Date(date);
|
|
109
|
+
d.setMonth(d.getMonth() + 1);
|
|
110
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`;
|
|
111
|
+
}
|
|
104
112
|
|
|
105
|
-
export { ensureChartForecastBridge, findLastValidHistoricalChartPoint, getPreviousMonth, normalizeToMonthStart };
|
|
113
|
+
export { ensureChartForecastBridge, findLastValidHistoricalChartPoint, getNextMonth, getPreviousMonth, normalizeToMonthStart };
|
package/package.json
CHANGED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
@import '../../../lib/theme.styl';
|
|
2
|
+
|
|
3
|
+
.root
|
|
4
|
+
display flex
|
|
5
|
+
flex-direction column
|
|
6
|
+
gap var(--p-4)
|
|
7
|
+
width 100%
|
|
8
|
+
|
|
9
|
+
.chartShell
|
|
10
|
+
position relative
|
|
11
|
+
width 100%
|
|
12
|
+
|
|
13
|
+
.chartShellLoading
|
|
14
|
+
.chartSlot
|
|
15
|
+
opacity 0.3
|
|
16
|
+
pointer-events none
|
|
17
|
+
|
|
18
|
+
:global(.recharts-line-dots)
|
|
19
|
+
display none
|
|
20
|
+
|
|
21
|
+
.chartSlot
|
|
22
|
+
width 100%
|
|
23
|
+
|
|
24
|
+
.loadingLayer
|
|
25
|
+
position absolute
|
|
26
|
+
inset 0
|
|
27
|
+
z-index 10
|
|
28
|
+
pointer-events none
|
|
29
|
+
|
|
30
|
+
.loadingMessage
|
|
31
|
+
position absolute
|
|
32
|
+
z-index 1
|
|
33
|
+
top calc(50% - 4em)
|
|
34
|
+
left 0
|
|
35
|
+
width 100%
|
|
36
|
+
display block
|
|
37
|
+
text-align center
|
|
38
|
+
color var(--foreground)
|
|
39
|
+
|
|
40
|
+
.loadingText
|
|
41
|
+
font-size 16px
|
|
42
|
+
font-weight 500
|
|
43
|
+
color var(--foreground)
|
|
44
|
+
border-radius var(--p-4)
|
|
45
|
+
padding 0 var(--p-3)
|
|
46
|
+
backdrop-filter blur(10px)
|
|
47
|
+
box-shadow 0 0 0 2px var(--page-color)
|
|
48
|
+
|
|
49
|
+
.chartWithOverlay
|
|
50
|
+
position relative
|
|
51
|
+
width 100%
|
|
52
|
+
|
|
53
|
+
.chartInteractiveLayer
|
|
54
|
+
width 100%
|
|
55
|
+
transition opacity 0.2s ease-out
|
|
56
|
+
|
|
57
|
+
.chartInteractiveDimmed
|
|
58
|
+
opacity 0.3
|
|
59
|
+
pointer-events none
|
|
60
|
+
|
|
61
|
+
:global(.recharts-line-dots)
|
|
62
|
+
display none
|
|
63
|
+
|
|
64
|
+
.chartEmptyOverlay
|
|
65
|
+
position absolute
|
|
66
|
+
inset 0
|
|
67
|
+
z-index 6
|
|
68
|
+
display flex
|
|
69
|
+
align-items center
|
|
70
|
+
justify-content center
|
|
71
|
+
padding var(--p-4)
|
|
72
|
+
pointer-events none
|
|
73
|
+
|
|
74
|
+
.chartEmptyBlurb
|
|
75
|
+
max-width 42rem
|
|
76
|
+
padding 0 var(--p-3)
|
|
77
|
+
|
|
78
|
+
.seriesEmptyWrap
|
|
79
|
+
display flex
|
|
80
|
+
justify-content center
|
|
81
|
+
padding var(--p-8) var(--p-4)
|
|
82
|
+
|
|
83
|
+
.seriesSection
|
|
84
|
+
width 100%
|
|
85
|
+
|
|
86
|
+
.seriesTableWrapper
|
|
87
|
+
position relative
|
|
88
|
+
margin 0 calc(var(--page-x-padding) * -1)
|
|
89
|
+
|
|
90
|
+
.seriesTableContainer
|
|
91
|
+
position relative
|
|
92
|
+
width 100%
|
|
93
|
+
overflow-x auto
|
|
94
|
+
|
|
95
|
+
.seriesScrollbar
|
|
96
|
+
bottom calc(var(--p-7) * -1 + 2px) !important
|
|
97
|
+
|
|
98
|
+
.seriesTable
|
|
99
|
+
table-layout auto
|
|
100
|
+
width 100%
|
|
101
|
+
max-width 100%
|
|
102
|
+
|
|
103
|
+
tr
|
|
104
|
+
position relative
|
|
105
|
+
cursor pointer
|
|
106
|
+
|
|
107
|
+
td
|
|
108
|
+
th
|
|
109
|
+
&:not(:first-child)
|
|
110
|
+
text-align right
|
|
111
|
+
|
|
112
|
+
.seriesColSeries
|
|
113
|
+
text-align left
|
|
114
|
+
vertical-align middle
|
|
115
|
+
|
|
116
|
+
.rowHidden
|
|
117
|
+
opacity .4
|
|
118
|
+
|
|
119
|
+
.colorSwatch
|
|
120
|
+
display inline-flex
|
|
121
|
+
flex-shrink 0
|
|
122
|
+
width 10px
|
|
123
|
+
height 10px
|
|
124
|
+
margin-right var(--p-2)
|
|
125
|
+
border-radius 2px
|
|
126
|
+
|
|
127
|
+
.seriesLabel
|
|
128
|
+
min-width 0
|
|
129
|
+
max-width 60vw
|
|
130
|
+
padding var(--p-2) 0
|
|
131
|
+
line-clamp(3)
|
|
132
|
+
white-space break-spaces
|
|
133
|
+
|
|
134
|
+
.chartContainer
|
|
135
|
+
margin-left calc(-1 * var(--page-x-padding) + 26px)
|
|
136
|
+
width calc(100% + 60px)
|
|
137
|
+
max-width @width
|
|
138
|
+
transition opacity 300ms ease-out
|
|
139
|
+
|
|
140
|
+
:global(.recharts-yAxis-tick-labels)
|
|
141
|
+
display none
|
|
142
|
+
|
|
143
|
+
@media (max-width: unit(MOBILE, 'px'))
|
|
144
|
+
margin-left calc(-1 * var(--page-x-padding) + 10px)
|
|
145
|
+
width calc(100% + 30px)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// This file is automatically generated.
|
|
2
|
+
// Please do not change this file!
|
|
3
|
+
interface CssExports {
|
|
4
|
+
'chartContainer': string;
|
|
5
|
+
'chartEmptyBlurb': string;
|
|
6
|
+
'chartEmptyOverlay': string;
|
|
7
|
+
'chartInteractiveDimmed': string;
|
|
8
|
+
'chartInteractiveLayer': string;
|
|
9
|
+
'chartShell': string;
|
|
10
|
+
'chartShellLoading': string;
|
|
11
|
+
'chartSlot': string;
|
|
12
|
+
'chartWithOverlay': string;
|
|
13
|
+
'colorSwatch': string;
|
|
14
|
+
'loadingLayer': string;
|
|
15
|
+
'loadingMessage': string;
|
|
16
|
+
'loadingText': string;
|
|
17
|
+
'root': string;
|
|
18
|
+
'rowHidden': string;
|
|
19
|
+
'seriesColSeries': string;
|
|
20
|
+
'seriesEmptyWrap': string;
|
|
21
|
+
'seriesLabel': string;
|
|
22
|
+
'seriesScrollbar': string;
|
|
23
|
+
'seriesSection': string;
|
|
24
|
+
'seriesTable': string;
|
|
25
|
+
'seriesTableContainer': string;
|
|
26
|
+
'seriesTableWrapper': string;
|
|
27
|
+
}
|
|
28
|
+
export const cssExports: CssExports;
|
|
29
|
+
export default cssExports;
|