@agridea/suibi-module 0.1.0-preview.18 → 0.1.0-preview.1f6a532

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 (82) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +74 -64
  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 +74 -64
  6. package/dist/elements/browser/{suibi-module.v0.1.0-preview.18.css → suibi-module.v0.1.0-preview.1f6a532.css} +1 -1
  7. package/dist/elements/browser/suibi-module.v0.1.0-preview.1f6a532.js +77 -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 -0
  11. package/dist/types/app/app.d.ts +8 -2
  12. package/dist/types/app/components/add-dashed-button/add-dashed-button.component.d.ts +9 -0
  13. package/dist/types/app/components/data-preview/data-preview.component.d.ts +6 -8
  14. package/dist/types/app/components/empty-state/empty-state.component.d.ts +12 -0
  15. package/dist/types/app/components/gauge-arc/gauge-arc.component.d.ts +47 -0
  16. package/dist/types/app/{header-bar.d.ts → components/header-bar/header-bar.component.d.ts} +4 -4
  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 +46 -0
  19. package/dist/types/app/components/planning-trigger/planning-trigger.component.d.ts +13 -0
  20. package/dist/types/app/components/results-page/results-page.component.d.ts +13 -0
  21. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +24 -0
  22. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-metrics.service.d.ts +21 -0
  23. package/dist/types/app/components/suissebilanz-minibar/suissebilanz-minibar.component.d.ts +19 -0
  24. package/dist/types/app/components/validation-page/validation-page.component.d.ts +18 -0
  25. package/dist/types/app/components/welcome-page/metadata.types.d.ts +1 -1
  26. package/dist/types/app/components/welcome-page/welcome-page.component.d.ts +3 -3
  27. package/dist/types/app/components/workflow-stepper/workflow-stepper.component.d.ts +49 -0
  28. package/dist/types/app/core/data/naebi-data.service.d.ts +45 -5
  29. package/dist/types/app/core/error/global-error-handler.d.ts +5 -0
  30. package/dist/types/app/core/events/suibi-data-emitter.service.d.ts +13 -0
  31. package/dist/types/app/core/i18n/i18n.service.d.ts +1 -2
  32. package/dist/types/app/core/master-data/master-data.service.d.ts +8 -1
  33. package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +10 -0
  34. package/dist/types/app/core/navigation/navigation.service.d.ts +29 -1
  35. package/dist/types/app/core/planning/planning-balance.service.d.ts +37 -0
  36. package/dist/types/app/core/planning/planning-balance.types.d.ts +206 -0
  37. package/dist/types/app/core/planning/planning-balance.utils.d.ts +10 -0
  38. package/dist/types/app/core/telemetry/telemetry.service.d.ts +12 -0
  39. package/dist/types/app/core/validation/capabilities.d.ts +5 -5
  40. package/dist/types/app/core/validation/global-validation.service.d.ts +19 -4
  41. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  42. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +8 -0
  43. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  44. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +10 -4
  45. package/dist/types/app/jsonforms/renderers/layout/array/array-layout.renderer.d.ts +43 -0
  46. package/dist/types/app/jsonforms/renderers/layout/categorization/selected-category-categorization.renderer.d.ts +3 -0
  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 +36 -0
  50. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail.component.d.ts +7 -8
  51. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-list.component.d.ts +5 -8
  52. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-master-detail.component.d.ts +0 -1
  53. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +9 -10
  54. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +7 -7
  55. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail.component.d.ts +0 -1
  56. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail.component.d.ts +22 -0
  57. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general.component.d.ts +22 -0
  58. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list.component.d.ts +17 -0
  59. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail.component.d.ts +37 -0
  60. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +40 -0
  61. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +6 -0
  62. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +4 -0
  63. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +0 -1
  64. package/dist/types/app/nutrient-cycle/fodder/fodder-detail.component.d.ts +31 -0
  65. package/dist/types/app/nutrient-cycle/fodder/fodder-list.component.d.ts +20 -0
  66. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail.component.d.ts +37 -0
  67. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +27 -0
  68. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +4 -0
  69. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  70. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  71. package/dist/types/app/nutrient-cycle/lifetime-performance/lifetime-performance-form.component.d.ts +1 -1
  72. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  73. package/dist/types/app/nutrient-cycle/storage/storage-detail.component.d.ts +30 -0
  74. package/dist/types/app/nutrient-cycle/storage/storage-general.component.d.ts +29 -0
  75. package/dist/types/app/nutrient-cycle/storage/storage-list.component.d.ts +20 -0
  76. package/dist/types/app/nutrient-cycle/storage/storage-master-detail.component.d.ts +31 -0
  77. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  78. package/dist/types/environments/environment.d.ts +11 -0
  79. package/dist/types/shared/material-icons.d.ts +3 -3
  80. package/package.json +68 -16
  81. package/dist/elements/browser/suibi-module.v0.1.0-preview.18.js +0 -67
  82. /package/dist/types/app/{core/validation/validation-errors-panel.d.ts → components/validation-errors-panel/validation-errors-panel.component.d.ts} +0 -0
@@ -1,8 +1,18 @@
1
1
  export type SuibiVersion = '1.19' | '1.20';
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,21 @@ 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>;
41
61
  /** True if currently viewing animal stock detail (not list) */
42
62
  readonly isAnimalStockDetailView: import("@angular/core").Signal<boolean>;
43
63
  /** True if currently on animal stock page (list or detail) */
@@ -58,10 +78,18 @@ export declare class NavigationService {
58
78
  navigateToAnimalStockDetail(index: number, category?: AnimalStockCategory): void;
59
79
  navigateToFarmManureTradingDetail(mode: FarmManureTradingMode, index: number, category?: FarmManureTradingCategory): void;
60
80
  navigateToFarmManureTradingList(): void;
81
+ navigateToFodderDetail(mode: FodderMode, index: number, category?: FodderCategory): void;
82
+ navigateToFodderList(): void;
61
83
  navigateToFieldSpreading(category?: FieldSpreadingCategory): void;
84
+ navigateToFieldCultivationDetail(tab: Exclude<FieldCultivationTab, 'general'>, index: number): void;
85
+ navigateToFieldCultivationList(tab?: FieldCultivationTab): void;
86
+ navigateToStorageDetail(type: StorageEntryType, index: number): void;
87
+ navigateToStorageList(tab?: StorageTab): void;
62
88
  /**
63
89
  * Set active category/tab for current page (without changing page/entry).
64
90
  * Generic method supporting any page's categorization navigation.
91
+ * No-op when page and category are already the same values to prevent
92
+ * unnecessary signal emissions that re-trigger the tab index computed.
65
93
  */
66
94
  setCategory(page: PageId, category: string): void;
67
95
  /**
@@ -0,0 +1,37 @@
1
+ import { NaebiData } from '../data/naebi-data.service';
2
+ import type { PlanningBalanceResponse } from './planning-balance.types';
3
+ export type { PlanningBalanceResponse } from './planning-balance.types';
4
+ /** Which backend to target for planning requests. */
5
+ export type PlanningEndpoint = 'ebilanz' | 'blw';
6
+ /**
7
+ * Sends NAEBI data to a planning endpoint and exposes the result as a
8
+ * signal-based resource. Call `runPlanning(data, endpoint)` to trigger a request.
9
+ *
10
+ * The ID counter ensures each call re-fetches even if the payload hasn't changed.
11
+ */
12
+ export declare class PlanningBalanceService {
13
+ private readonly http;
14
+ private readonly _value;
15
+ private readonly _error;
16
+ private readonly _isLoading;
17
+ private readonly _selectedEndpoint;
18
+ private readonly _lastStartedRequestId;
19
+ private readonly _lastCompletedRequestId;
20
+ private readonly _lastSuccessfulRequestId;
21
+ private _nextId;
22
+ private activeRequestId;
23
+ private activeRequestSub;
24
+ readonly planningResource: {
25
+ value: import("@angular/core").Signal<PlanningBalanceResponse | undefined>;
26
+ error: import("@angular/core").Signal<unknown>;
27
+ isLoading: import("@angular/core").Signal<boolean>;
28
+ hasValue: import("@angular/core").Signal<boolean>;
29
+ lastStartedRequestId: import("@angular/core").Signal<number>;
30
+ lastCompletedRequestId: import("@angular/core").Signal<number>;
31
+ lastSuccessfulRequestId: import("@angular/core").Signal<number>;
32
+ };
33
+ readonly selectedEndpoint: import("@angular/core").Signal<PlanningEndpoint>;
34
+ setSelectedEndpoint(endpoint: PlanningEndpoint): void;
35
+ /** Fire a new planning-balance request with the current NAEBI data payload. */
36
+ runPlanning(data: NaebiData, endpoint?: PlanningEndpoint): void;
37
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * TypeScript interfaces for the planning-balance API response.
3
+ * These match the eBilanz / BLW response shape observed in the example data.
4
+ */
5
+ /** A single nutrient quantity entry (kg or % unit). */
6
+ export interface NutrientEntry {
7
+ molecularFormula: string;
8
+ quantity: number;
9
+ quantityCorrected?: number;
10
+ unit: string;
11
+ productFamilyType?: string;
12
+ typeOfManureRecyclingProduct?: string;
13
+ fertiliserProductCategory?: string;
14
+ }
15
+ export interface CalculationVersion {
16
+ version: string;
17
+ validFrom: string;
18
+ validTo: string;
19
+ }
20
+ export interface AreaAndYieldPerAgronomicCropCategory {
21
+ agronomicCropCategory: string;
22
+ areaSize: number;
23
+ effectiveYield: number;
24
+ isMainCrop: boolean;
25
+ isNutrientPoorFodder: boolean;
26
+ yieldPerSquareMeasure?: number;
27
+ }
28
+ export interface AreaPerCultivationType {
29
+ areaSize: number;
30
+ isMainCrop: boolean;
31
+ }
32
+ export interface AreaAndYieldPerCultivationCategory {
33
+ cultivationCategory: string;
34
+ areaAndYieldPerAgronomicCropCategory: AreaAndYieldPerAgronomicCropCategory[];
35
+ areaPerCultivationType: AreaPerCultivationType[];
36
+ }
37
+ export interface AreaPerSubCategory {
38
+ cultivationSubCategory: string;
39
+ areaSize: number;
40
+ isMainCrop: boolean;
41
+ }
42
+ export interface FieldCultivation {
43
+ areaAndYieldPerCultivationCategory: AreaAndYieldPerCultivationCategory[];
44
+ areaPerSubCategory: AreaPerSubCategory[];
45
+ fertilizableAreaSize: number;
46
+ slurrySpreadingAreaSize: number;
47
+ totalAgriculturalLandAreaSize: number;
48
+ }
49
+ export interface FodderQuantity {
50
+ quantity: number;
51
+ unit: string;
52
+ proportionNutrientPoorFodder?: number;
53
+ }
54
+ export interface FodderProduct {
55
+ typeOfFeedstuffProduct: string;
56
+ quantity: number;
57
+ unit: string;
58
+ isNutrientPoorFodder: boolean;
59
+ }
60
+ export interface ConsumptionAnimalStock {
61
+ animalCategoryPRIF: number;
62
+ averageQuantity: number;
63
+ order: string;
64
+ quantity: number;
65
+ unit: string;
66
+ }
67
+ export interface RequiredEffectiveYieldFromFodderCropland {
68
+ consumptionAnimalStock: ConsumptionAnimalStock[];
69
+ cropFromNonFodderCroplandPerProduct: FodderProduct[];
70
+ dispensePerProduct: FodderProduct[];
71
+ supplyPerProduct: FodderProduct[];
72
+ totalBalance: FodderQuantity;
73
+ totalConsumptionAnimalStock: FodderQuantity;
74
+ totalCropFromNonFodderCropland: FodderQuantity;
75
+ totalDispense: FodderQuantity;
76
+ totalSupply: FodderQuantity;
77
+ }
78
+ export interface FodderBalance {
79
+ requiredEffectiveYieldFromFodderCropland: RequiredEffectiveYieldFromFodderCropland;
80
+ totalBalance: FodderQuantity;
81
+ totalEffectiveYieldFromFodderCropland: FodderQuantity;
82
+ totalNutrientPoorFodder: FodderQuantity;
83
+ }
84
+ export interface EmissionAndAccumulationEntry {
85
+ animalCategoryPRIF: number;
86
+ order: string;
87
+ accumulation: NutrientEntry[];
88
+ emission: NutrientEntry[];
89
+ manureExcretion?: unknown[];
90
+ }
91
+ export interface AccumulationEntireExcretion {
92
+ animalCategoryPRIF: number;
93
+ order: string;
94
+ durationSumTotalCorrectedNutrientBalance: number;
95
+ accumulation: NutrientEntry[];
96
+ }
97
+ export interface TotalNutrientSet {
98
+ accumulation: NutrientEntry[];
99
+ emission?: NutrientEntry[];
100
+ }
101
+ export interface AnimalStock {
102
+ accumulationEntireExcretion: AccumulationEntireExcretion[];
103
+ emissionAndAccumulationPasture: EmissionAndAccumulationEntry[];
104
+ emissionAndAccumulationStall: EmissionAndAccumulationEntry[];
105
+ emissionAndAccumulationYard: EmissionAndAccumulationEntry[];
106
+ totalAccumulationEntireExcretion: TotalNutrientSet;
107
+ totalEmissionAndAccumulationAnimalStock: TotalNutrientSet;
108
+ totalEmissionAndAccumulationPasture: TotalNutrientSet;
109
+ totalEmissionAndAccumulationStall: TotalNutrientSet;
110
+ totalEmissionAndAccumulationYard: TotalNutrientSet;
111
+ }
112
+ export interface ManureTradingProduct {
113
+ typeOfManureRecyclingProduct: string;
114
+ quantity: number;
115
+ unit: string;
116
+ ingredient: NutrientEntry[];
117
+ }
118
+ export interface FarmManureTrading {
119
+ balancePerProduct: ManureTradingProduct[];
120
+ dispensePerProduct: ManureTradingProduct[];
121
+ supplyPerProduct: ManureTradingProduct[];
122
+ totalBalance: {
123
+ ingredient: NutrientEntry[];
124
+ };
125
+ }
126
+ export interface NutrientRequirementEntry {
127
+ agronomicCropCategory?: string;
128
+ cultivationCategory?: string;
129
+ isMainCrop?: boolean;
130
+ requirement: NutrientEntry[];
131
+ }
132
+ export interface FieldCultivationNutrients {
133
+ nutrientTransferUnfertilizedCultivation: NutrientEntry[];
134
+ requirementPerAgronomicCropCategory: NutrientRequirementEntry[];
135
+ requirementPerCultivationCategory: NutrientRequirementEntry[];
136
+ totalRequirement: NutrientEntry[];
137
+ }
138
+ export interface FieldSpreading {
139
+ emissionAndAccumulationFieldSpreading: TotalNutrientSet;
140
+ totalEmissionAndAccumulationFieldSpreading: TotalNutrientSet;
141
+ }
142
+ export interface StorageBalance {
143
+ emissionAndAccumulationManureStorage: TotalNutrientSet;
144
+ totalEmissionAndAccumulationManureStorage: TotalNutrientSet;
145
+ }
146
+ export interface NutrientBalance {
147
+ animalStock: AnimalStock;
148
+ farmManureTrading: FarmManureTrading;
149
+ fieldCultivation: FieldCultivationNutrients;
150
+ fieldSpreading: FieldSpreading;
151
+ storage: StorageBalance;
152
+ /** Final per-nutrient balance figures: kg lines + % lines interleaved. */
153
+ totalBalance: NutrientEntry[];
154
+ /** Farm-wide gas emissions (NH3, NO, N2O, N2). */
155
+ totalEmissionFarm: NutrientEntry[];
156
+ nutrientBalanceTMP?: unknown[];
157
+ }
158
+ export interface NutrientCycle {
159
+ creationDateTime: string;
160
+ facilitySpecificProducts: {
161
+ manureRecyclingProduct: unknown[];
162
+ };
163
+ fieldCultivation: FieldCultivation;
164
+ fodderBalance: FodderBalance;
165
+ nutrientBalance: NutrientBalance;
166
+ version: string;
167
+ /** Base64-encoded PDF report, if returned by the endpoint. */
168
+ report?: string;
169
+ }
170
+ export interface ValidationMessageDetail {
171
+ designation_deu: string;
172
+ designation_eng: string;
173
+ designation_fra: string;
174
+ designation_ita: string;
175
+ }
176
+ export interface ValidationMessage {
177
+ field: string;
178
+ type: string;
179
+ detail: ValidationMessageDetail;
180
+ }
181
+ /** Full response from the planning-balance endpoint. */
182
+ export interface PlanningBalanceResponse {
183
+ calculationVersion: CalculationVersion;
184
+ nutrientCycle: NutrientCycle;
185
+ validationMessage: ValidationMessage[];
186
+ }
187
+ /** Merged kg + % row for the final balance table (Section D). */
188
+ export interface BalanceRow {
189
+ molecularFormula: string;
190
+ quantity: number;
191
+ quantityCorrected: number;
192
+ quantityPct: number | null;
193
+ quantityCorrectedPct: number | null;
194
+ unit: 'kg';
195
+ }
196
+ /** Crop requirement row enriched with area and yield for display (Section C). */
197
+ export interface CropRequirementRow {
198
+ cropCode: string;
199
+ cultivationCategory: string;
200
+ isMainCrop: boolean;
201
+ areaHa: number;
202
+ effectiveYield: number;
203
+ /** kg/ha yield per square measure field (m² basis), converted to dt/ha for display. */
204
+ yieldDtHa: number | null;
205
+ requirement: NutrientEntry[];
206
+ }
@@ -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,12 @@
1
+ export declare class TelemetryService {
2
+ private appInsights;
3
+ private isEnabled;
4
+ constructor();
5
+ private init;
6
+ setTelemetryEnabled(enabled: boolean): void;
7
+ trackPageView(name?: string, uri?: string): void;
8
+ trackEvent(name: string, properties?: {
9
+ [key: string]: any;
10
+ }): void;
11
+ trackException(exception: Error): void;
12
+ }
@@ -5,14 +5,14 @@
5
5
  * All master data is embedded statically at compile time - no runtime HTTP calls.
6
6
  */
7
7
  /**
8
- * Derives permitted stable systems (husbandry type IDs) for a given animal category.
8
+ * Derives permitted stable systems (stableSystem enum strings) for a given animal category.
9
9
  *
10
10
  * @param animalCategoryPRIF - The PRIF animal category ID
11
- * @returns Array of permitted husbandry type IDs (stable systems)
11
+ * @returns Array of permitted stableSystem enum strings (e.g. 'HUS_TETHER')
12
12
  */
13
- export declare function derivePermittedStableSystems(animalCategoryPRIF: number | null | undefined): number[];
13
+ export declare function derivePermittedStableSystems(animalCategoryPRIF: number | null | undefined): string[];
14
14
  /**
15
15
  * Pre-computed map for performance (memoized at module load).
16
- * Maps animalCategoryPRIF -> array of permitted stableSystem values.
16
+ * Maps animalCategoryPRIF -> array of permitted stableSystem enum strings.
17
17
  */
18
- export declare const PERMITTED_STABLE_SYSTEMS: Record<number, number[]>;
18
+ export declare const PERMITTED_STABLE_SYSTEMS: Record<number, string[]>;
@@ -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,24 @@ 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
+ /** Category tab inside field cultivation */
29
+ targetFieldCultivationTab?: FieldCultivationTab;
30
+ /** Field cultivation detail index */
31
+ targetFieldCultivationIndex?: number;
32
+ /** Storage detail type */
33
+ targetStorageType?: StorageEntryType;
34
+ /** Storage detail index */
35
+ targetStorageIndex?: number;
36
+ /** Storage tab for list-level or scalar navigation */
37
+ targetStorageTab?: StorageTab;
22
38
  }
23
39
  /**
24
40
  * GlobalValidationService
@@ -31,14 +47,13 @@ export declare class GlobalValidationService {
31
47
  private readonly dataSvc;
32
48
  private readonly ajv;
33
49
  private readonly validateFn;
34
- private readonly rawErrors;
35
50
  readonly errors: import("@angular/core").Signal<EnrichedValidationError[]>;
36
- constructor();
37
- validate(): void;
38
51
  private consolidateErrors;
39
52
  private enrichErrors;
40
53
  private inferCategory;
41
54
  private inferFarmTradingCategory;
42
55
  private inferFieldSpreadingCategory;
56
+ private inferFodderCategory;
57
+ private inferStorageTab;
43
58
  private inferFieldLabel;
44
59
  }
@@ -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,9 +3,11 @@ 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';
10
+ import { CustomArrayLayoutRenderer } from '../renderers/layout/array/array-layout.renderer';
9
11
  export declare const CUSTOM_JSONFORMS_RENDERERS: ({
10
12
  tester: RankedTester;
11
13
  renderer: typeof ConstraintLayoutRenderer;
@@ -21,10 +23,16 @@ export declare const CUSTOM_JSONFORMS_RENDERERS: ({
21
23
  } | {
22
24
  tester: RankedTester;
23
25
  renderer: typeof LogicalGroupRenderer;
26
+ } | {
27
+ tester: RankedTester;
28
+ renderer: typeof ModuleToggleGroupRenderer;
24
29
  } | {
25
30
  tester: RankedTester;
26
31
  renderer: typeof AnimalCategorySelectRenderer;
27
32
  } | {
28
33
  tester: RankedTester;
29
34
  renderer: typeof CodeListSelectRenderer;
35
+ } | {
36
+ tester: RankedTester;
37
+ renderer: typeof CustomArrayLayoutRenderer;
30
38
  })[];
@@ -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;
@@ -0,0 +1,43 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { JsonFormsAbstractControl, JsonFormsAngularService } from '@jsonforms/angular';
3
+ import { ArrayLayoutProps, ArrayTranslations, JsonFormsState, OwnPropsOfRenderer, RankedTester, StatePropsOfArrayLayout, UISchemaElement, UISchemaTester } from '@jsonforms/core';
4
+ /**
5
+ * CustomArrayLayoutRenderer
6
+ * Overrides the stock JSONForms `ArrayLayoutRenderer` (rank 4 → this is rank 5) to apply
7
+ * the project UX pattern: centered empty-state placeholder when the array has no entries,
8
+ * and the full-width dashed add-button always anchored below the list.
9
+ *
10
+ * The add button label is driven by `translations.addTooltip` resolved via the JSONForms
11
+ * i18n pipeline — configure per-array labels there.
12
+ */
13
+ export declare class CustomArrayLayoutRenderer extends JsonFormsAbstractControl<StatePropsOfArrayLayout> implements OnInit {
14
+ noData: boolean;
15
+ /** Indices 0..n-1 used to render per-item cards and drive sort-button disabled state. */
16
+ indices: number[];
17
+ translations: ArrayTranslations;
18
+ showSortButtons: boolean;
19
+ addItem: (path: string, value: unknown) => () => void;
20
+ moveItemUp: (path: string, index: number) => () => void;
21
+ moveItemDown: (path: string, index: number) => () => void;
22
+ removeItems: (path: string, toDelete: number[]) => () => void;
23
+ uischemas: {
24
+ tester: UISchemaTester;
25
+ uischema: UISchemaElement;
26
+ }[];
27
+ constructor(jsonFormsService: JsonFormsAngularService);
28
+ get emptyText(): string;
29
+ get addLabel(): string;
30
+ mapToProps(state: JsonFormsState): StatePropsOfArrayLayout & {
31
+ translations: ArrayTranslations;
32
+ };
33
+ mapAdditionalProps(props: ArrayLayoutProps & {
34
+ translations: ArrayTranslations;
35
+ }): void;
36
+ remove(index: number): void;
37
+ add(): void;
38
+ up(index: number): void;
39
+ down(index: number): void;
40
+ ngOnInit(): void;
41
+ getProps(index: number): OwnPropsOfRenderer;
42
+ }
43
+ export declare const customArrayLayoutRendererTester: RankedTester;
@@ -19,12 +19,15 @@ export declare class SelectedCategoryCategorizationRenderer extends JsonFormsBas
19
19
  categoryLabels: string[];
20
20
  private readonly categoryKeyToIndex;
21
21
  private readonly indexToCategoryKey;
22
+ private _prevCategorySignature;
22
23
  readonly selectedTabIndex: import("@angular/core").Signal<number>;
23
24
  ngOnInit(): void;
24
25
  /**
25
26
  * Build bidirectional category key ↔ tab index mapping from UI schema.
26
27
  * Reads options.categoryKey from each visible Category element.
27
28
  * Example: { base: 0, formOfDetention: 1, feeding: 2 }
29
+ * Skips signal writes when the tab structure hasn't changed (pure data changes
30
+ * fire $state on every keystroke; no need to mark selectedTabIndex stale each time).
28
31
  */
29
32
  private buildCategoryMappings;
30
33
  onTabChange(newIndex: number): void;
@@ -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;
@@ -21,6 +21,8 @@ export declare class BaseGroupRenderer extends JsonFormsBaseRenderer<GroupLayout
21
21
  registryRenderers(): JsonFormsRendererRegistryEntry[];
22
22
  registryCells(): JsonFormsCellRendererRegistryEntry[] | undefined;
23
23
  private subscription;
24
+ private _destroyed;
25
+ private _prevSig?;
24
26
  ngOnInit(): void;
25
27
  ngOnDestroy(): void;
26
28
  protected resolveHost(): ViewContainerRef | undefined;
@@ -0,0 +1,36 @@
1
+ import { OnDestroy, OnInit } from '@angular/core';
2
+ import { JsonFormsBaseRenderer } from '@jsonforms/angular';
3
+ import { GroupLayout, RankedTester } from '@jsonforms/core';
4
+ interface ModuleCard {
5
+ path: string;
6
+ value: boolean;
7
+ label: string;
8
+ description?: string;
9
+ }
10
+ export declare const moduleToggleGroupTester: RankedTester;
11
+ /**
12
+ * Layout renderer for `{ type: 'Group', options: { variant: 'module-toggle' } }`.
13
+ *
14
+ * Renders boolean control children as interactive card-toggles in a horizontal
15
+ * row. Label and description are read from the (already-localised) schema that
16
+ * JSONForms passes into the renderer, so no extra i18n wiring is needed here.
17
+ */
18
+ export declare class ModuleToggleGroupRenderer extends JsonFormsBaseRenderer<GroupLayout> implements OnInit, OnDestroy {
19
+ private readonly service;
20
+ private readonly cdr;
21
+ private subscription?;
22
+ protected readonly _hidden: import("@angular/core").WritableSignal<boolean>;
23
+ protected readonly _label: import("@angular/core").WritableSignal<string | undefined>;
24
+ protected readonly _description: import("@angular/core").WritableSignal<string | undefined>;
25
+ protected readonly _modules: import("@angular/core").WritableSignal<ModuleCard[]>;
26
+ readonly labelId: string;
27
+ hidden: () => boolean;
28
+ label: () => string | undefined;
29
+ description: () => string | undefined;
30
+ modules: () => ModuleCard[];
31
+ ngOnInit(): void;
32
+ ngOnDestroy(): void;
33
+ /** Flip a single module boolean in the JSONForms data store. */
34
+ toggle(dataPath: string): void;
35
+ }
36
+ export {};
@@ -1,17 +1,16 @@
1
- import { EventEmitter, Signal } from '@angular/core';
2
1
  import { JsonSchema, UISchemaElement } from '@jsonforms/core';
3
2
  import { AnimalStockRow } from './animal-stock.types';
4
3
  import { ErrorObject } from 'ajv';
5
4
  export declare class AnimalStockDetailComponent {
6
5
  private readonly i18n;
7
- row: Signal<AnimalStockRow | null>;
8
- index: Signal<number | null>;
9
- rowChange: EventEmitter<AnimalStockRow>;
10
- close: EventEmitter<void>;
11
- itemSchema: Signal<JsonSchema>;
6
+ row: import("@angular/core").InputSignal<AnimalStockRow | null>;
7
+ index: import("@angular/core").InputSignal<number | null>;
8
+ rowChange: import("@angular/core").OutputEmitterRef<AnimalStockRow>;
9
+ close: import("@angular/core").OutputEmitterRef<void>;
10
+ itemSchema: import("@angular/core").Signal<JsonSchema>;
12
11
  private readonly baseUi;
13
- localizedUi: Signal<UISchemaElement>;
14
- jsonFormsData: Signal<(AnimalStockRow & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
12
+ localizedUi: import("@angular/core").Signal<UISchemaElement>;
13
+ jsonFormsData: import("@angular/core").Signal<(AnimalStockRow & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
15
14
  readonly renderers: {
16
15
  tester: import("@jsonforms/core").RankedTester;
17
16
  renderer: any;