@agridea/suibi-module 0.1.0-preview.2f7b6e2 → 0.1.0-preview.3626ce5

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.
Files changed (104) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +71 -72
  3. package/dist/elements/browser/styles.css +1 -1
  4. package/dist/elements/browser/suibi-module-latest.css +1 -1
  5. package/dist/elements/browser/suibi-module-latest.js +71 -72
  6. package/dist/elements/browser/{suibi-module.v0.1.0-preview.2f7b6e2.css → suibi-module.v0.1.0-preview.3626ce5.css} +1 -1
  7. package/dist/elements/browser/suibi-module.v0.1.0-preview.3626ce5.js +78 -0
  8. package/dist/elements/browser/suibi-theme-dark.css +1 -1
  9. package/dist/elements/browser/version.txt +1 -1
  10. package/dist/elements/browser/wc-global-utilities.css +1 -1
  11. package/dist/types/app/components/data-preview/data-preview.component.d.ts +2 -2
  12. package/dist/types/app/components/empty-state/empty-state.component.d.ts +2 -0
  13. package/dist/types/app/components/gauge-arc/gauge-arc.component.d.ts +49 -0
  14. package/dist/types/app/{header-bar.d.ts → components/header-bar/header-bar.component.d.ts} +3 -4
  15. package/dist/types/app/components/inline-table/inline-table.component.d.ts +159 -0
  16. package/dist/types/app/components/inline-table/inline-table.types.d.ts +212 -0
  17. package/dist/types/app/components/module-placeholder-page/module-placeholder-page.component.d.ts +6 -0
  18. package/dist/types/app/components/planning-result/planning-result.component.d.ts +3 -26
  19. package/dist/types/app/components/planning-result-row/planning-result-row.component.d.ts +34 -0
  20. package/dist/types/app/components/planning-trigger/planning-trigger.component.d.ts +13 -0
  21. package/dist/types/app/components/results-page/results-page.component.d.ts +13 -0
  22. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +32 -0
  23. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-metrics.service.d.ts +21 -0
  24. package/dist/types/app/components/suissebilanz-minibar/suissebilanz-minibar.component.d.ts +19 -0
  25. package/dist/types/app/components/validation-page/validation-page.component.d.ts +18 -0
  26. package/dist/types/app/components/welcome-page/metadata.types.d.ts +1 -1
  27. package/dist/types/app/components/welcome-page/welcome-page.component.d.ts +5 -3
  28. package/dist/types/app/components/workflow-stepper/workflow-stepper.component.d.ts +1 -0
  29. package/dist/types/app/core/data/naebi-data.service.d.ts +28 -28
  30. package/dist/types/app/core/error/global-error-handler.d.ts +2 -3
  31. package/dist/types/app/core/i18n/i18n.service.d.ts +5 -3
  32. package/dist/types/app/core/i18n/locales/fr.d.ts +2 -0
  33. package/dist/types/app/core/i18n/locales/it.d.ts +2 -0
  34. package/dist/types/app/core/master-data/master-data.service.d.ts +2 -0
  35. package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +11 -1
  36. package/dist/types/app/core/navigation/navigation.service.d.ts +34 -1
  37. package/dist/types/app/core/planning/planning-balance.service.d.ts +23 -3
  38. package/dist/types/app/core/planning/planning-balance.utils.d.ts +10 -0
  39. package/dist/types/app/core/utils/custom-unit.util.d.ts +38 -0
  40. package/dist/types/app/core/utils/object.util.d.ts +17 -0
  41. package/dist/types/app/core/validation/ajv-custom.d.ts +1 -0
  42. package/dist/types/app/core/validation/global-validation.service.d.ts +21 -1
  43. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  44. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +4 -0
  45. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  46. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +10 -4
  47. package/dist/types/app/jsonforms/renderers/layout/constraint/constraint-layout.renderer.d.ts +1 -0
  48. package/dist/types/app/jsonforms/renderers/layout/group/base-group.renderer.d.ts +2 -0
  49. package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +38 -0
  50. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail/animal-stock-detail.component.d.ts +21 -0
  51. package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-list.component.d.ts → animal-stock-list/animal-stock-list.component.d.ts} +6 -9
  52. package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-master-detail.component.d.ts → animal-stock-master-detail/animal-stock-master-detail.component.d.ts} +2 -2
  53. package/dist/types/app/nutrient-cycle/animal-stock/index.d.ts +3 -3
  54. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail/farm-manure-trading-master-detail.component.d.ts +19 -0
  55. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.component.d.ts +35 -0
  56. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.config.d.ts +24 -0
  57. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading.types.d.ts +4 -0
  58. package/dist/types/app/nutrient-cycle/farm-manure-trading/index.d.ts +3 -3
  59. package/dist/types/app/nutrient-cycle/farm-manure-trading/transaction-unit.util.d.ts +2 -0
  60. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.component.d.ts +22 -0
  61. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.config.d.ts +9 -0
  62. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.component.d.ts +21 -0
  63. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.config.d.ts +13 -0
  64. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail/field-cultivation-detail.component.d.ts +22 -0
  65. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general/field-cultivation-general.component.d.ts +20 -0
  66. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list/field-cultivation-list.component.d.ts +17 -0
  67. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail/field-cultivation-master-detail.component.d.ts +29 -0
  68. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +45 -0
  69. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +6 -0
  70. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.component.d.ts +28 -0
  71. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.config.d.ts +16 -0
  72. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +9 -0
  73. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.component.d.ts +29 -0
  74. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.config.d.ts +51 -0
  75. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +52 -0
  76. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.config.d.ts +20 -0
  77. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +18 -3
  78. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.types.d.ts +1 -0
  79. package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
  80. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +32 -0
  81. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +17 -0
  82. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
  83. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail/fodder-master-detail.component.d.ts +25 -0
  84. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.component.d.ts +28 -0
  85. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.config.d.ts +9 -0
  86. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +34 -0
  87. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +3 -0
  88. package/dist/types/app/nutrient-cycle/fodder/ingredient.util.d.ts +8 -0
  89. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  90. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  91. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  92. package/dist/types/app/nutrient-cycle/storage/storage-detail/storage-detail.component.d.ts +30 -0
  93. package/dist/types/app/nutrient-cycle/storage/storage-general/storage-general.component.d.ts +29 -0
  94. package/dist/types/app/nutrient-cycle/storage/storage-list/storage-list.component.d.ts +23 -0
  95. package/dist/types/app/nutrient-cycle/storage/storage-master-detail/storage-master-detail.component.d.ts +32 -0
  96. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  97. package/dist/types/shared/material-icons.d.ts +3 -3
  98. package/package.json +68 -17
  99. package/dist/elements/browser/suibi-module.v0.1.0-preview.2f7b6e2.js +0 -79
  100. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail.component.d.ts +0 -22
  101. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +0 -27
  102. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +0 -23
  103. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail.component.d.ts +0 -25
  104. /package/dist/types/app/{core/validation/validation-errors-panel.d.ts → components/validation-errors-panel/validation-errors-panel.component.d.ts} +0 -0
@@ -0,0 +1,32 @@
1
+ import { SafeUrl } from '@angular/platform-browser';
2
+ import { PlanningBalanceService } from '../../core/planning/planning-balance.service';
3
+ import { GaugeStatus } from '../gauge-arc/gauge-arc.component';
4
+ import { SuisseBilanzMetricsService } from './suissebilanz-metrics.service';
5
+ /**
6
+ * Dashboard card displaying the 5 main SuisseBilanz metrics as semicircular
7
+ * SVG gauges. Derives all display data from `PlanningBalanceService` via
8
+ * computed signals — fully zoneless-safe, `OnPush`.
9
+ *
10
+ * Shows an empty-state panel when no planning result is available yet.
11
+ */
12
+ export declare class SuisseBilanzDashboardComponent {
13
+ readonly embedded: import("@angular/core").InputSignal<boolean>;
14
+ /** Shows the official PDF download link even when `embedded` (header hidden). */
15
+ readonly showPdfButton: import("@angular/core").InputSignal<boolean>;
16
+ protected readonly planning: PlanningBalanceService;
17
+ private readonly sanitizer;
18
+ protected readonly metricsService: SuisseBilanzMetricsService;
19
+ private readonly result;
20
+ protected readonly metrics: import("@angular/core").Signal<import("../gauge-arc/gauge-arc.component").GaugeMetric[]>;
21
+ /** Surface areas in ha, derived from the latest planning result. */
22
+ protected readonly surfaces: import("@angular/core").Signal<{
23
+ sau: number;
24
+ sfe: number;
25
+ to: number;
26
+ } | null>;
27
+ protected readonly officialPdfUrl: import("@angular/core").Signal<SafeUrl | null>;
28
+ private prevBlobUrl;
29
+ private readonly blobCleanup;
30
+ /** Maps a `GaugeStatus` to its Material icon name for the status badge. */
31
+ protected statusIcon(status: GaugeStatus): string;
32
+ }
@@ -0,0 +1,21 @@
1
+ import { GaugeMetric } from '../gauge-arc/gauge-arc.component';
2
+ /**
3
+ * Shared source of truth for all SuisseBilanz metric view-models.
4
+ *
5
+ * Both the full dashboard card and the slim minibar consume this service so
6
+ * the derivation logic lives in exactly one place. Metrics re-compute via
7
+ * `computed()` when either the planning result or the locale signal changes.
8
+ */
9
+ export declare class SuisseBilanzMetricsService {
10
+ private readonly planning;
11
+ private readonly i18n;
12
+ /** Wall-clock time of the most recent successful planning result. */
13
+ readonly lastUpdated: import("@angular/core").WritableSignal<Date | null>;
14
+ constructor();
15
+ /**
16
+ * Five gauge view-models for N avail., P₂O₅, K₂O, Mg and Rendement prairies.
17
+ * Returns placeholder 'empty' metrics until the first planning result arrives.
18
+ */
19
+ readonly metrics: import("@angular/core").Signal<GaugeMetric[]>;
20
+ private emptyMetric;
21
+ }
@@ -0,0 +1,19 @@
1
+ import { GaugeMetric, GaugeStatus } from '../gauge-arc/gauge-arc.component';
2
+ import { SuisseBilanzMetricsService } from '../suissebilanz-dashboard/suissebilanz-metrics.service';
3
+ /**
4
+ * Slim, always-visible metrics card placed above the workflow stepper.
5
+ *
6
+ * Shows the same 5 SuisseBilanz metrics as the full dashboard card but in a
7
+ * compact single-row layout: metric label → bold coloured value → thin
8
+ * progress bar. Shares all data logic via `SuisseBilanzMetricsService`.
9
+ */
10
+ export declare class SuisseBilanzMinibarComponent {
11
+ protected readonly metricsService: SuisseBilanzMetricsService;
12
+ /** Returns the status colour for a given metric status. */
13
+ protected statusColor(status: GaugeStatus): string;
14
+ /**
15
+ * Maps the metric value to a 0–100 fill percentage for the progress bar,
16
+ * clamped so bars never overflow the track.
17
+ */
18
+ protected fillPct(metric: GaugeMetric): number;
19
+ }
@@ -0,0 +1,18 @@
1
+ import { ErrorObject } from 'ajv';
2
+ import { PlanningBalanceService } from '../../core/planning/planning-balance.service';
3
+ /**
4
+ * Final submission step: review validation status and submit the planning balance.
5
+ */
6
+ export declare class ValidationPageComponent {
7
+ readonly showHeader: import("@angular/core").InputSignal<boolean>;
8
+ /** Navigation callback for validation error clicks — provided by App to keep routing logic centralised. */
9
+ readonly onErrorSelected: import("@angular/core").InputSignal<(error: ErrorObject) => void>;
10
+ /** Navigation callback triggered after a fresh successful planning submission. */
11
+ readonly onSubmitSuccess: import("@angular/core").InputSignal<() => void>;
12
+ protected readonly planning: PlanningBalanceService;
13
+ private readonly globalValidation;
14
+ private lastHandledSuccessRequestId;
15
+ constructor();
16
+ protected readonly validationErrors: import("@angular/core").Signal<import("../../../public-api").EnrichedValidationError[]>;
17
+ protected readonly errorCount: import("@angular/core").Signal<number>;
18
+ }
@@ -1 +1 @@
1
- export { DEFAULT_SUIBI_METADATA, type SubmissionStatus, type SuibiVersion, type SuibiMetadata } from '../../core/metadata/suibi-metadata.types';
1
+ export { DEFAULT_SUIBI_METADATA, DEFAULT_COMPUTATION_MODULES, type ComputationModules, type SubmissionStatus, type SuibiVersion, type SuibiMetadata } from '../../core/metadata/suibi-metadata.types';
@@ -1,9 +1,9 @@
1
- import { OnInit } from '@angular/core';
2
1
  import { JsonSchema, UISchemaElement } from '@jsonforms/core';
3
2
  import { SuibiMetadata } from '../../core/metadata/suibi-metadata.types';
4
- export declare class WelcomePageComponent implements OnInit {
3
+ export declare class WelcomePageComponent {
5
4
  private readonly i18n;
6
5
  private readonly metadataSvc;
6
+ private readonly naebi;
7
7
  startEvent: import("@angular/core").OutputEmitterRef<void>;
8
8
  metadataChange: import("@angular/core").OutputEmitterRef<SuibiMetadata>;
9
9
  private readonly baseSchema;
@@ -17,11 +17,13 @@ export declare class WelcomePageComponent implements OnInit {
17
17
  readonly localizedSchema: import("@angular/core").Signal<JsonSchema>;
18
18
  readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
19
19
  readonly jsonFormsData: import("@angular/core").Signal<{}>;
20
- ngOnInit(): void;
20
+ constructor();
21
21
  start(): void;
22
+ loadExampleData(): void;
22
23
  onMetadataChange(newValue: unknown): void;
23
24
  private normalizeJsonFormsPayload;
24
25
  private toMetadata;
26
+ private extractModules;
25
27
  private isSuibiVersion;
26
28
  private isSubmissionStatus;
27
29
  private isSameMetadata;
@@ -39,6 +39,7 @@ export declare class WorkflowStepperComponent {
39
39
  */
40
40
  readonly onNavigate: import("@angular/core").InputSignal<(page: PageId) => void>;
41
41
  private readonly validationSvc;
42
+ private readonly workflowPage;
42
43
  protected readonly pagesWithErrors: import("@angular/core").Signal<Set<PageId>>;
43
44
  protected readonly isOnWorkflowPage: import("@angular/core").Signal<boolean>;
44
45
  protected readonly clampedStepIndex: import("@angular/core").Signal<number>;
@@ -30,9 +30,7 @@ export declare class NaebiDataService {
30
30
  };
31
31
  stall: {
32
32
  stableSystem: string;
33
- stableCapacity: number;
34
33
  stableVentilationType: number;
35
- stableAirPurification: number;
36
34
  hasStableDeepLitter: boolean;
37
35
  hasStableManureBeltDrying: boolean;
38
36
  stableManureRemovalFrequency: number;
@@ -41,10 +39,6 @@ export declare class NaebiDataService {
41
39
  hasStableFeedingStationElevated: boolean;
42
40
  hasStableFloorSlopedUrineDrainage: boolean;
43
41
  hasYard: boolean;
44
- yardFeeding: number;
45
- yardFloorType: number;
46
- yardDays: number;
47
- yardHoursPerDay: number;
48
42
  };
49
43
  };
50
44
  hasImpexDerivedExcretion: boolean;
@@ -52,6 +46,7 @@ export declare class NaebiDataService {
52
46
  feeding: {
53
47
  fodderConsumption: number;
54
48
  concentratedFeedstuffConsumption: number;
49
+ concentratedFeedStuffConsumption: number;
55
50
  winterFeeding: {
56
51
  feedingRoutine: {
57
52
  typeOfFeedstuffProduct: string;
@@ -76,19 +71,14 @@ export declare class NaebiDataService {
76
71
  }[];
77
72
  storage: {
78
73
  stableStrawLitter: number;
79
- manureSupplyProportionStored: number;
80
74
  slurrySupplyProportionStored: number;
81
75
  createFacilitySpecificManureProduct: boolean;
82
76
  createFacilitySpecificSlurryProduct: boolean;
77
+ slurryTankQuantity: number;
83
78
  dilutionRatio: number;
84
- manurePit: {
85
- cover: number;
86
- manureFromAnimalStockStored: {
87
- manureDerivation: string;
88
- proportionStored: number;
89
- }[];
90
- }[];
79
+ manurePit: never[];
91
80
  slurryTank: {
81
+ descriptor: string;
92
82
  volumeInM3: number;
93
83
  depthInM: number;
94
84
  cover: number;
@@ -97,20 +87,7 @@ export declare class NaebiDataService {
97
87
  }[];
98
88
  };
99
89
  farmManureTrading: {
100
- supply: {
101
- quantity: number;
102
- typeOfManureRecyclingProduct: string;
103
- transactionUnit: string;
104
- manureDerivation: {
105
- zoologicalAnimal: string;
106
- percentageAllocation: number;
107
- }[];
108
- ingredient: {
109
- quantity: number;
110
- molecularFormula: string;
111
- unit: string;
112
- }[];
113
- }[];
90
+ supply: never[];
114
91
  dispense: {
115
92
  quantity: number;
116
93
  typeOfManureRecyclingProduct: string;
@@ -183,6 +160,12 @@ export declare class NaebiDataService {
183
160
  unit: string;
184
161
  }[];
185
162
  }[];
163
+ dispense: {
164
+ typeOfFeedstuffProduct: string;
165
+ quantity: number;
166
+ transactionUnit: string;
167
+ ingredient: never[];
168
+ }[];
186
169
  };
187
170
  cropFromNonFodderCropland: {
188
171
  typeOfFeedstuffProduct: string;
@@ -198,6 +181,17 @@ export declare class NaebiDataService {
198
181
  totalBalanceErrorMargin: number;
199
182
  };
200
183
  fieldCultivation: {
184
+ buildingZoneAreaSize: number;
185
+ outdoorVegetableMainCropAreaSize: number;
186
+ indoorVegetableMainCropAreaSize: number;
187
+ feedingOfCropHarvest: {
188
+ agronomicCropCategory: string;
189
+ effectiveYield: number;
190
+ }[];
191
+ dispenseOfCropHarvest: {
192
+ agronomicCropCategory: string;
193
+ effectiveYield: number;
194
+ }[];
201
195
  fodderCropland: ({
202
196
  agronomicCropCategory: string;
203
197
  isMainCrop: boolean;
@@ -216,12 +210,18 @@ export declare class NaebiDataService {
216
210
  isMainCrop: boolean;
217
211
  areaSize: number;
218
212
  yieldPerSquareMeasure: number;
213
+ hasLongTermYieldDivergence: boolean;
219
214
  }[];
220
215
  special: {
221
216
  agronomicCropCategory: string;
222
217
  userSpecificPlantName: string;
223
218
  isMainCrop: boolean;
224
219
  areaSize: number;
220
+ requirementCorrection: {
221
+ quantity: number;
222
+ molecularFormula: string;
223
+ unit: string;
224
+ }[];
225
225
  }[];
226
226
  };
227
227
  generateReport: boolean;
@@ -1,6 +1,5 @@
1
- import { ErrorHandler, Injector } from '@angular/core';
1
+ import { ErrorHandler } from '@angular/core';
2
2
  export declare class GlobalErrorHandler implements ErrorHandler {
3
- private injector;
4
- constructor(injector: Injector);
3
+ private readonly injector;
5
4
  handleError(error: any): void;
6
5
  }
@@ -1,5 +1,5 @@
1
1
  import { PipeTransform, Signal } from '@angular/core';
2
- export type Locale = 'en' | 'de';
2
+ export type Locale = 'en' | 'de' | 'fr' | 'it';
3
3
  export type JsonFormsTranslator = (key: string, defaultMessage: string | undefined, context: unknown) => string;
4
4
  export declare class I18nService {
5
5
  private readonly _locale;
@@ -8,13 +8,15 @@ export declare class I18nService {
8
8
  readonly jsonFormsI18n: Signal<{
9
9
  locale: Locale;
10
10
  translate: JsonFormsTranslator;
11
+ translateError: (error: unknown, translate: JsonFormsTranslator) => string;
11
12
  }>;
12
13
  setLocale(locale: Locale): void;
14
+ /** Returns true if the given string is a supported locale key. */
15
+ isValidLocale(value: string): value is Locale;
13
16
  t(key: string, defaultMessage?: string): string;
14
17
  }
15
18
  export declare class TranslatePipe implements PipeTransform {
16
- private readonly i18n;
17
19
  private readonly cache;
18
- constructor(i18n: I18nService);
20
+ private readonly i18n;
19
21
  transform(key: string, defaultMessage?: string): Signal<string>;
20
22
  }
@@ -0,0 +1,2 @@
1
+ export declare const frTranslations: Record<string, string>;
2
+ export type FrTranslationKeys = keyof typeof frTranslations;
@@ -0,0 +1,2 @@
1
+ export declare const itTranslations: Record<string, string>;
2
+ export type ItTranslationKeys = keyof typeof itTranslations;
@@ -26,5 +26,7 @@ export declare class MasterDataService {
26
26
  resolveCultivationCategory(code: string | null | undefined, locale?: Locale): string;
27
27
  resolveAgronomicCropCategory(code: string | null | undefined, locale?: Locale): string;
28
28
  resolveFeedstuffProduct(code: string | null | undefined, locale?: Locale): string;
29
+ resolveCover(id: number | string | null | undefined, locale?: Locale): string;
30
+ resolveMixingFrequency(id: number | string | null | undefined, locale?: Locale): string;
29
31
  }
30
32
  export {};
@@ -1,8 +1,18 @@
1
- export type SuibiVersion = '1.19' | '1.20';
1
+ export type SuibiVersion = 'v2.0';
2
2
  export type SubmissionStatus = 'draft' | 'submitted' | 'final';
3
+ /** Which computation modules are active for this dossier. */
4
+ export interface ComputationModules {
5
+ suisseBilanz: boolean;
6
+ gmf: boolean;
7
+ nh3: boolean;
8
+ impex: boolean;
9
+ linear: boolean;
10
+ }
11
+ export declare const DEFAULT_COMPUTATION_MODULES: ComputationModules;
3
12
  export interface SuibiMetadata {
4
13
  title: string;
5
14
  suibiVersion: SuibiVersion;
6
15
  status: SubmissionStatus;
16
+ modules: ComputationModules;
7
17
  }
8
18
  export declare const DEFAULT_SUIBI_METADATA: SuibiMetadata;
@@ -1,8 +1,13 @@
1
- export type PageId = 'welcome' | 'animal_stock' | 'data_preview' | 'storage' | 'field_spreading' | 'farm_manure_trading';
1
+ export type PageId = 'welcome' | 'animal_stock' | 'data_preview' | 'storage' | 'field_spreading' | 'farm_manure_trading' | 'fodder' | 'field_cultivation' | 'validation' | 'results';
2
2
  export type AnimalStockCategory = 'base' | 'formOfDetention' | 'feeding';
3
3
  export type FarmManureTradingMode = 'supply' | 'dispense';
4
4
  export type FarmManureTradingCategory = 'general' | 'derivation' | 'ingredients';
5
+ export type FodderMode = 'supply' | 'dispense' | 'non_fodder_cropland';
6
+ export type FodderCategory = 'general' | 'ingredients';
5
7
  export type FieldSpreadingCategory = 'general' | 'fertiliser' | 'recycling';
8
+ export type FieldCultivationTab = 'general' | 'fodderCropland' | 'arableLand' | 'special';
9
+ export type StorageTab = 'manure' | 'slurry';
10
+ export type StorageEntryType = 'manure_pit' | 'slurry_tank';
6
11
  /**
7
12
  * NavigationService
8
13
  * Global reactive store for application routing and deep-link state.
@@ -38,6 +43,26 @@ export declare class NavigationService {
38
43
  mode: FarmManureTradingMode;
39
44
  index: number;
40
45
  } | null>;
46
+ /** Selected fodder detail context (mode + index) */
47
+ readonly selectedFodderDetail: import("@angular/core").WritableSignal<{
48
+ mode: FodderMode;
49
+ index: number;
50
+ } | null>;
51
+ /** Selected field cultivation detail context (tab + index) */
52
+ readonly selectedFieldCultivationDetail: import("@angular/core").WritableSignal<{
53
+ tab: Exclude<FieldCultivationTab, "general">;
54
+ index: number;
55
+ } | null>;
56
+ /** Selected storage detail context (type + index) */
57
+ readonly selectedStorageDetail: import("@angular/core").WritableSignal<{
58
+ type: StorageEntryType;
59
+ index: number;
60
+ } | null>;
61
+ /** Selected field spreading row context (category/tab + row index) — used by validation deep-links */
62
+ readonly selectedFieldSpreadingDetail: import("@angular/core").WritableSignal<{
63
+ category: FieldSpreadingCategory;
64
+ index: number;
65
+ } | null>;
41
66
  /** True if currently viewing animal stock detail (not list) */
42
67
  readonly isAnimalStockDetailView: import("@angular/core").Signal<boolean>;
43
68
  /** True if currently on animal stock page (list or detail) */
@@ -58,7 +83,15 @@ export declare class NavigationService {
58
83
  navigateToAnimalStockDetail(index: number, category?: AnimalStockCategory): void;
59
84
  navigateToFarmManureTradingDetail(mode: FarmManureTradingMode, index: number, category?: FarmManureTradingCategory): void;
60
85
  navigateToFarmManureTradingList(): void;
86
+ navigateToFodderDetail(mode: FodderMode, index: number, category?: FodderCategory): void;
87
+ navigateToFodderList(): void;
61
88
  navigateToFieldSpreading(category?: FieldSpreadingCategory): void;
89
+ /** Deep-link to a specific row of a field spreading tab (e.g. from a validation error). */
90
+ navigateToFieldSpreadingDetail(category: FieldSpreadingCategory, index: number): void;
91
+ navigateToFieldCultivationDetail(tab: Exclude<FieldCultivationTab, 'general'>, index: number): void;
92
+ navigateToFieldCultivationList(tab?: FieldCultivationTab): void;
93
+ navigateToStorageDetail(type: StorageEntryType, index: number): void;
94
+ navigateToStorageList(tab?: StorageTab): void;
62
95
  /**
63
96
  * Set active category/tab for current page (without changing page/entry).
64
97
  * Generic method supporting any page's categorization navigation.
@@ -10,9 +10,29 @@ export type PlanningEndpoint = 'ebilanz' | 'blw';
10
10
  * The ID counter ensures each call re-fetches even if the payload hasn't changed.
11
11
  */
12
12
  export declare class PlanningBalanceService {
13
- private readonly _trigger;
13
+ private readonly http;
14
+ private readonly metadataSvc;
15
+ private readonly _value;
16
+ private readonly _error;
17
+ private readonly _isLoading;
18
+ private readonly _selectedEndpoint;
19
+ private readonly _lastStartedRequestId;
20
+ private readonly _lastCompletedRequestId;
21
+ private readonly _lastSuccessfulRequestId;
14
22
  private _nextId;
15
- readonly planningResource: import("@angular/common/http").HttpResourceRef<PlanningBalanceResponse | undefined>;
23
+ private activeRequestId;
24
+ private activeRequestSub;
25
+ readonly planningResource: {
26
+ value: import("@angular/core").Signal<PlanningBalanceResponse | undefined>;
27
+ error: import("@angular/core").Signal<unknown>;
28
+ isLoading: import("@angular/core").Signal<boolean>;
29
+ hasValue: import("@angular/core").Signal<boolean>;
30
+ lastStartedRequestId: import("@angular/core").Signal<number>;
31
+ lastCompletedRequestId: import("@angular/core").Signal<number>;
32
+ lastSuccessfulRequestId: import("@angular/core").Signal<number>;
33
+ };
34
+ readonly selectedEndpoint: import("@angular/core").Signal<PlanningEndpoint>;
35
+ setSelectedEndpoint(endpoint: PlanningEndpoint): void;
16
36
  /** Fire a new planning-balance request with the current NAEBI data payload. */
17
- runPlanning(data: NaebiData, endpoint: PlanningEndpoint): void;
37
+ runPlanning(data: NaebiData, endpoint?: PlanningEndpoint): void;
18
38
  }
@@ -0,0 +1,10 @@
1
+ import type { BalanceRow, NutrientEntry } from './planning-balance.types';
2
+ /**
3
+ * Merges the interleaved kg / % rows from `totalBalance` into one `BalanceRow`
4
+ * per nutrient formula, preserving the canonical KEY_NUTRIENTS display order.
5
+ *
6
+ * The planning-balance API returns two `NutrientEntry` objects per formula
7
+ * (one with `unit === 'kg'`, one with `unit === '%'`). This function coalesces
8
+ * them so callers work with a single, normalised row.
9
+ */
10
+ export declare function mergeBalanceRows(totalBalance: NutrientEntry[]): BalanceRow[];
@@ -0,0 +1,38 @@
1
+ export interface CustomUnit {
2
+ /** Unit code stored on the row (e.g. 'ha', 't', 'dt'). */
3
+ code: string;
4
+ /** API base unit this custom unit converts to (e.g. 'm2', 'kg'). */
5
+ baseUnit: string;
6
+ /** Multiplier from the custom unit to its base unit (1 ha = 10'000 m2 → 10000). */
7
+ factor: number;
8
+ descriptor?: Record<string, unknown>;
9
+ }
10
+ export declare const CUSTOM_UNITS: readonly CustomUnit[];
11
+ /** True when the unit code is a custom display unit (not an API base unit). */
12
+ export declare function isCustomUnit(unit: unknown): boolean;
13
+ /** Base unit a quantity can be converted to: the custom unit's `baseUnit`, or the unit
14
+ * itself when it already is a base (or unknown) unit. */
15
+ export declare function baseUnitOf(unit: string | null | undefined): string | null | undefined;
16
+ /** Custom units convertible to the given base unit (e.g. 'kg' → [t, dt]). */
17
+ export declare function customUnitsForBaseUnit(baseUnit: string): CustomUnit[];
18
+ /**
19
+ * Builds a filter (compatible with the inline table's `optionsFilter`) keeping only the
20
+ * units compatible with the given context base unit — i.e. the base unit itself plus its
21
+ * custom units. Pass a nullable base (e.g. derived from a product's matterState): `null`
22
+ * keeps the full list (nothing derived yet).
23
+ *
24
+ * Works on any entry shape exposing `id` (and `baseUnit` for custom units).
25
+ */
26
+ export declare function unitOptionsForBaseUnit<T extends {
27
+ id: string | number;
28
+ }>(contextBaseUnit: string | null | undefined): (entry: T) => boolean;
29
+ /** Converts a quantity expressed in a custom unit to its base unit; pass-through for
30
+ * base/unknown units and null quantities. */
31
+ export declare function convertToBaseUnit(quantity: number | null | undefined, unit: string | null | undefined): {
32
+ quantity: number | null | undefined;
33
+ unit: string | null | undefined;
34
+ };
35
+ /** Converts a quantity between two units sharing the same base unit (kg ↔ t ↔ dt,
36
+ * m2 ↔ ha). Returns the quantity unchanged when either unit is missing or the units
37
+ * are incompatible (different base units). */
38
+ export declare function convertQuantityBetween(quantity: number | null | undefined, fromUnit: string | null | undefined, toUnit: string | null | undefined): number | null | undefined;
@@ -22,3 +22,20 @@ export declare function deepEqual(a: unknown, b: unknown): boolean;
22
22
  * @returns A deep copy of the value
23
23
  */
24
24
  export declare function deepClone<T>(value: T): T;
25
+ export declare function stripIncompleteIngredients<T>(value: T): T;
26
+ /**
27
+ * Sanitizes the planning payload: the calculation API (OpenAPI, no `nullable: true`
28
+ * anywhere) accepts an optional field as *absent* but rejects it when present with a
29
+ * null value ("must be string/number"). The working data model normalizes optional
30
+ * fields to null, so strip them at the submission boundary — mirroring what
31
+ * `stripIncompleteIngredients` does for ingredient slots.
32
+ *
33
+ * - inside `fieldCultivation` entry collections (fodderCropland, arableLand, special,
34
+ * feedingOfCropHarvest, dispenseOfCropHarvest): any null property is dropped
35
+ * (fieldName, userSpecificPlantName, yieldPerSquareMeasure, effectiveYield, …)
36
+ * - `nutrientCycle.fodder.trading.<collection>[].quantity`: null → dropped
37
+ */
38
+ export declare function sanitizePlanningPayload(data: NaebiDataLike): NaebiDataLike;
39
+ /** Structural type so object.util stays free of a NaebiData import (circular-safe). */
40
+ type NaebiDataLike = Record<string, unknown>;
41
+ export {};
@@ -9,6 +9,7 @@ import Ajv from 'ajv';
9
9
  *
10
10
  * Custom keywords:
11
11
  * - `permittedStableSystem`: Validates stable system against animal category constraints
12
+ * - `proportionSum`: Validates the sum of one numeric field across array items
12
13
  *
13
14
  * @param options - Additional AJV options to merge with defaults
14
15
  */
@@ -1,5 +1,5 @@
1
1
  import { ErrorObject } from 'ajv';
2
- import { AnimalStockCategory, FarmManureTradingCategory, FarmManureTradingMode, FieldSpreadingCategory, PageId } from '../navigation/navigation.service';
2
+ import { AnimalStockCategory, FarmManureTradingCategory, FarmManureTradingMode, FieldCultivationTab, FieldSpreadingCategory, FodderCategory, FodderMode, PageId, StorageEntryType, StorageTab } from '../navigation/navigation.service';
3
3
  export interface EnrichedValidationError extends ErrorObject {
4
4
  /** Human-friendly field label (e.g., "Animal Category") */
5
5
  fieldLabel?: string;
@@ -17,8 +17,26 @@ export interface EnrichedValidationError extends ErrorObject {
17
17
  targetFarmManureTradingIndex?: number;
18
18
  /** Category tab inside farm manure trading detail */
19
19
  targetFarmManureTradingCategory?: FarmManureTradingCategory;
20
+ /** Navigation target: fodder mode */
21
+ targetFodderMode?: FodderMode;
22
+ /** Navigation target: fodder entry index */
23
+ targetFodderIndex?: number;
24
+ /** Category tab inside fodder detail */
25
+ targetFodderCategory?: FodderCategory;
20
26
  /** Category tab inside field spreading */
21
27
  targetFieldSpreadingCategory?: FieldSpreadingCategory;
28
+ /** Row index inside a field spreading tab (fertiliser/recycling) */
29
+ targetFieldSpreadingIndex?: number;
30
+ /** Category tab inside field cultivation */
31
+ targetFieldCultivationTab?: FieldCultivationTab;
32
+ /** Field cultivation detail index */
33
+ targetFieldCultivationIndex?: number;
34
+ /** Storage detail type */
35
+ targetStorageType?: StorageEntryType;
36
+ /** Storage detail index */
37
+ targetStorageIndex?: number;
38
+ /** Storage tab for list-level or scalar navigation */
39
+ targetStorageTab?: StorageTab;
22
40
  }
23
41
  /**
24
42
  * GlobalValidationService
@@ -37,5 +55,7 @@ export declare class GlobalValidationService {
37
55
  private inferCategory;
38
56
  private inferFarmTradingCategory;
39
57
  private inferFieldSpreadingCategory;
58
+ private inferFodderCategory;
59
+ private inferStorageTab;
40
60
  private inferFieldLabel;
41
61
  }
@@ -20,9 +20,11 @@
20
20
  */
21
21
  import { MasterDataService } from '../../core/master-data/master-data.service';
22
22
  import { I18nService } from '../../core/i18n/i18n.service';
23
+ import { NaebiDataService } from '../../core/data/naebi-data.service';
23
24
  import { BaseCodeListEntry } from '../shared/option-sources/code-lists';
24
25
  export interface FilterContext {
25
26
  data: unknown;
27
+ rootData: unknown;
26
28
  get<T = unknown>(pointer: string): T | undefined;
27
29
  masterData: MasterDataService;
28
30
  locale: string;
@@ -57,4 +59,5 @@ export declare function registerCodeListFilter(name: string, fn: CodeListFilterR
57
59
  export declare function evaluateFilter(list: BaseCodeListEntry[], cfg: FilterConfig | undefined, services: {
58
60
  masterData: MasterDataService;
59
61
  i18n: I18nService;
62
+ naebiData?: NaebiDataService;
60
63
  }, data: unknown): BaseCodeListEntry[];
@@ -3,6 +3,7 @@ import { CodeListSelectRenderer } from '../renderers/controls/selects/code-list/
3
3
  import { CardGroupRenderer } from '../renderers/layout/group/card-group.renderer';
4
4
  import { PlainGroupRenderer } from '../renderers/layout/group/plain-group.renderer';
5
5
  import { LogicalGroupRenderer } from '../renderers/layout/group/logical-group.renderer';
6
+ import { ModuleToggleGroupRenderer } from '../renderers/layout/group/module-toggle-group.renderer';
6
7
  import { RankedTester } from '@jsonforms/core';
7
8
  import { ConstraintLayoutRenderer } from '../renderers/layout/constraint/constraint-layout.renderer';
8
9
  import { SelectedCategoryCategorizationRenderer } from '../renderers/layout/categorization/selected-category-categorization.renderer';
@@ -22,6 +23,9 @@ export declare const CUSTOM_JSONFORMS_RENDERERS: ({
22
23
  } | {
23
24
  tester: RankedTester;
24
25
  renderer: typeof LogicalGroupRenderer;
26
+ } | {
27
+ tester: RankedTester;
28
+ renderer: typeof ModuleToggleGroupRenderer;
25
29
  } | {
26
30
  tester: RankedTester;
27
31
  renderer: typeof AnimalCategorySelectRenderer;
@@ -10,7 +10,7 @@ interface AnimalCategoryPrifEntry {
10
10
  };
11
11
  }
12
12
  export declare class AnimalCategorySelectRenderer extends BaseSelectControl<number> {
13
- options: AnimalCategoryPrifEntry[];
13
+ options: import("@angular/core").InputSignal<AnimalCategoryPrifEntry[]>;
14
14
  private readonly masterData;
15
15
  constructor(jsonFormsService: JsonFormsAngularService);
16
16
  getEventValue: (event: any) => any;
@@ -1,28 +1,34 @@
1
1
  import { Signal } from '@angular/core';
2
2
  import { JsonFormsAngularService } from '@jsonforms/angular';
3
- import { RankedTester } from '@jsonforms/core';
3
+ import { ControlElement, RankedTester } from '@jsonforms/core';
4
4
  import { BaseSelectControl } from '../../../../shared/base-control/base-select-control';
5
5
  import { BaseCodeListEntry } from '../../../../shared/option-sources/code-lists';
6
+ export declare function replaceDataPathLeaf(path: string | null | undefined, replacement: string): string | null;
7
+ export declare function deriveSiblingDependencyPath(uischema: ControlElement | null | undefined, path: string | null | undefined, replacement: string): string | null;
6
8
  export declare class CodeListSelectRenderer extends BaseSelectControl<number | string> {
7
9
  private readonly masterData;
8
10
  private readonly i18n;
11
+ private readonly naebiData;
9
12
  private readonly formData;
10
13
  private readonly controlScope;
11
14
  private explicitCodeListKey;
12
15
  private controlKey;
13
16
  private listKey;
14
17
  readonly options: Signal<BaseCodeListEntry[]>;
18
+ readonly isMultiSelect: Signal<boolean>;
15
19
  private readonly filterConfig;
20
+ private readonly emptyHintKey;
16
21
  private readonly dependsOnDataPath;
17
- private readonly autoDependsOnScope;
22
+ private readonly autoDependsOnDataPath;
18
23
  private scopePointerToDataPath;
19
- private replacePointerLeaf;
20
24
  private inferListKeyFromScope;
21
25
  private readValueAtPath;
22
26
  readonly filteredOptions: Signal<BaseCodeListEntry[]>;
23
27
  constructor(jsonFormsService: JsonFormsAngularService);
24
28
  getEventValue: (event: any) => any;
25
29
  optionLabel(opt: BaseCodeListEntry): string;
26
- onSelectionChange(value: number | string): void;
30
+ emptyHint(): string;
31
+ shouldShowEmptyHint(): boolean;
32
+ onSelectionChange(value: number | string | Array<number | string>): void;
27
33
  }
28
34
  export declare const codeListSelectTester: RankedTester;
@@ -12,6 +12,7 @@ export declare class ConstraintLayoutRenderer extends JsonFormsBaseRenderer<Layo
12
12
  private readonly service;
13
13
  private childrenHost?;
14
14
  private subscription;
15
+ private _prevSig?;
15
16
  private _elements;
16
17
  private _schema;
17
18
  private _path;