@agridea/suibi-module 0.1.0-preview.8 → 0.1.0-preview.87cac2d

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 (121) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +75 -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 +75 -64
  6. package/dist/elements/browser/{suibi-module.v0.1.0-preview.8.css → suibi-module.v0.1.0-preview.87cac2d.css} +1 -1
  7. package/dist/elements/browser/suibi-module.v0.1.0-preview.87cac2d.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 -0
  11. package/dist/types/app/app.d.ts +14 -6
  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 +233 -0
  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 +49 -0
  16. package/dist/types/app/components/header-bar/header-bar.component.d.ts +14 -0
  17. package/dist/types/app/components/inline-table/inline-table.component.d.ts +159 -0
  18. package/dist/types/app/components/inline-table/inline-table.types.d.ts +212 -0
  19. package/dist/types/app/components/module-placeholder-page/module-placeholder-page.component.d.ts +6 -0
  20. package/dist/types/app/components/planning-result/planning-result.component.d.ts +46 -0
  21. package/dist/types/app/components/planning-result-row/planning-result-row.component.d.ts +34 -0
  22. package/dist/types/app/components/planning-trigger/planning-trigger.component.d.ts +13 -0
  23. package/dist/types/app/components/results-page/results-page.component.d.ts +13 -0
  24. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +32 -0
  25. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-metrics.service.d.ts +21 -0
  26. package/dist/types/app/components/suissebilanz-minibar/suissebilanz-minibar.component.d.ts +19 -0
  27. package/dist/types/app/components/validation-page/validation-page.component.d.ts +18 -0
  28. package/dist/types/app/components/welcome-page/metadata.types.d.ts +1 -0
  29. package/dist/types/app/components/welcome-page/welcome-page.component.d.ts +30 -0
  30. package/dist/types/app/components/workflow-stepper/workflow-stepper.component.d.ts +49 -0
  31. package/dist/types/app/core/data/naebi-data.service.d.ts +52 -31
  32. package/dist/types/app/core/error/global-error-handler.d.ts +5 -0
  33. package/dist/types/app/core/events/suibi-data-emitter.service.d.ts +13 -0
  34. package/dist/types/app/core/events/suibi-data-event.d.ts +26 -0
  35. package/dist/types/app/core/i18n/i18n.service.d.ts +5 -3
  36. package/dist/types/app/core/i18n/locales/fr.d.ts +2 -0
  37. package/dist/types/app/core/i18n/locales/it.d.ts +2 -0
  38. package/dist/types/app/core/master-data/master-data.service.d.ts +15 -1
  39. package/dist/types/app/core/metadata/suibi-metadata.service.d.ts +6 -0
  40. package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +18 -0
  41. package/dist/types/app/core/navigation/navigation.service.d.ts +59 -5
  42. package/dist/types/app/core/planning/planning-balance.service.d.ts +46 -0
  43. package/dist/types/app/core/planning/planning-balance.types.d.ts +206 -0
  44. package/dist/types/app/core/planning/planning-balance.utils.d.ts +10 -0
  45. package/dist/types/app/core/schemas/schema-localization.util.d.ts +18 -0
  46. package/dist/types/app/core/telemetry/telemetry.service.d.ts +12 -0
  47. package/dist/types/app/core/utils/custom-unit.util.d.ts +39 -0
  48. package/dist/types/app/core/utils/object.util.d.ts +46 -0
  49. package/dist/types/app/core/validation/ajv-custom.d.ts +1 -0
  50. package/dist/types/app/core/validation/capabilities.d.ts +11 -5
  51. package/dist/types/app/core/validation/global-validation.service.d.ts +33 -4
  52. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  53. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +12 -0
  54. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  55. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +16 -2
  56. package/dist/types/app/jsonforms/renderers/layout/array/array-layout.renderer.d.ts +43 -0
  57. package/dist/types/app/jsonforms/renderers/layout/categorization/selected-category-categorization.renderer.d.ts +34 -0
  58. package/dist/types/app/jsonforms/renderers/layout/constraint/constraint-layout.renderer.d.ts +1 -0
  59. package/dist/types/app/jsonforms/renderers/layout/group/base-group.renderer.d.ts +2 -0
  60. package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +38 -0
  61. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail/animal-stock-detail.component.d.ts +21 -0
  62. package/dist/types/app/{animal-stock → nutrient-cycle/animal-stock/animal-stock-list}/animal-stock-list.component.d.ts +6 -9
  63. package/dist/types/app/{animal-stock → nutrient-cycle/animal-stock/animal-stock-master-detail}/animal-stock-master-detail.component.d.ts +5 -2
  64. package/dist/types/app/{animal-stock → nutrient-cycle/animal-stock}/animal-stock.types.d.ts +6 -6
  65. package/dist/types/app/nutrient-cycle/animal-stock/index.d.ts +4 -0
  66. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail/farm-manure-trading-master-detail.component.d.ts +19 -0
  67. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.component.d.ts +37 -0
  68. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.config.d.ts +24 -0
  69. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading.types.d.ts +31 -0
  70. package/dist/types/app/nutrient-cycle/farm-manure-trading/index.d.ts +4 -0
  71. package/dist/types/app/nutrient-cycle/farm-manure-trading/transaction-unit.util.d.ts +3 -0
  72. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.component.d.ts +23 -0
  73. package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.config.d.ts +16 -0
  74. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.component.d.ts +21 -0
  75. package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.config.d.ts +13 -0
  76. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail/field-cultivation-detail.component.d.ts +22 -0
  77. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general/field-cultivation-general.component.d.ts +20 -0
  78. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list/field-cultivation-list.component.d.ts +17 -0
  79. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail/field-cultivation-master-detail.component.d.ts +29 -0
  80. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +45 -0
  81. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +10 -0
  82. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.component.d.ts +29 -0
  83. package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.config.d.ts +21 -0
  84. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +9 -0
  85. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.component.d.ts +29 -0
  86. package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.config.d.ts +54 -0
  87. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +52 -0
  88. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.config.d.ts +20 -0
  89. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +36 -0
  90. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.types.d.ts +44 -0
  91. package/dist/types/app/nutrient-cycle/field-spreading/index.d.ts +2 -0
  92. package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
  93. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +32 -0
  94. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +17 -0
  95. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
  96. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail/fodder-master-detail.component.d.ts +25 -0
  97. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.component.d.ts +28 -0
  98. package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.config.d.ts +9 -0
  99. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +34 -0
  100. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +3 -0
  101. package/dist/types/app/nutrient-cycle/fodder/ingredient.util.d.ts +8 -0
  102. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  103. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  104. package/dist/types/app/nutrient-cycle/lifetime-performance/lifetime-performance-form.component.d.ts +27 -0
  105. package/dist/types/app/nutrient-cycle/lifetime-performance/lifetime-performance.types.d.ts +5 -0
  106. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  107. package/dist/types/app/nutrient-cycle/storage/storage-detail/storage-detail.component.d.ts +30 -0
  108. package/dist/types/app/nutrient-cycle/storage/storage-general/storage-general.component.d.ts +29 -0
  109. package/dist/types/app/nutrient-cycle/storage/storage-list/storage-list.component.d.ts +23 -0
  110. package/dist/types/app/nutrient-cycle/storage/storage-master-detail/storage-master-detail.component.d.ts +32 -0
  111. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  112. package/dist/types/environments/environment.d.ts +11 -0
  113. package/dist/types/public-api.d.ts +2 -0
  114. package/dist/types/shared/material-icons.d.ts +3 -3
  115. package/package.json +69 -17
  116. package/dist/elements/browser/suibi-module.v0.1.0-preview.8.js +0 -67
  117. package/dist/types/app/animal-stock/animal-stock-detail.component.d.ts +0 -22
  118. package/dist/types/app/data-preview.d.ts +0 -7
  119. package/dist/types/app/header-bar.d.ts +0 -19
  120. package/dist/types/app/welcome-page.d.ts +0 -4
  121. /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,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,18 @@
1
+ import { UISchemaElement } from '@jsonforms/core';
2
+ /**
3
+ * Deeply clones a UI schema and translates its labels.
4
+ *
5
+ * This utility is essential for JSONForms integration in a multi-language environment.
6
+ * Since UI schemas are typically static JSON objects, we must clone them before
7
+ * modifying their labels to avoid mutating the shared source or leaking translations
8
+ * across language switches.
9
+ *
10
+ * It traverses:
11
+ * - Nested `elements` arrays (standard layouts)
12
+ * - `options.detail` objects (often used in array controls)
13
+ *
14
+ * @param ui The original UI schema to localize
15
+ * @param translate A function that takes a translation key and returns the translated string
16
+ * @returns A new UI schema object with translated labels
17
+ */
18
+ export declare function cloneAndLocalize(ui: any, translate: (key: string) => string): UISchemaElement;
@@ -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
+ }
@@ -0,0 +1,39 @@
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(s) — i.e. each base unit 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); pass an array of bases (e.g. ['kg', 'm3'])
23
+ * to pre-filter to their union before the exact base is known.
24
+ *
25
+ * Works on any entry shape exposing `id` (and `baseUnit` for custom units).
26
+ */
27
+ export declare function unitOptionsForBaseUnit<T extends {
28
+ id: string | number;
29
+ }>(contextBaseUnit: string | readonly string[] | null | undefined): (entry: T) => boolean;
30
+ /** Converts a quantity expressed in a custom unit to its base unit; pass-through for
31
+ * base/unknown units and null quantities. */
32
+ export declare function convertToBaseUnit(quantity: number | null | undefined, unit: string | null | undefined): {
33
+ quantity: number | null | undefined;
34
+ unit: string | null | undefined;
35
+ };
36
+ /** Converts a quantity between two units sharing the same base unit (kg ↔ t ↔ dt,
37
+ * m2 ↔ ha). Returns the quantity unchanged when either unit is missing or the units
38
+ * are incompatible (different base units). */
39
+ export declare function convertQuantityBetween(quantity: number | null | undefined, fromUnit: string | null | undefined, toUnit: string | null | undefined): number | null | undefined;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Recursively compares two values for deep equality.
3
+ *
4
+ * Useful for checking if complex objects or arrays have changed content,
5
+ * often used in change detection strategies or form dirty checking.
6
+ *
7
+ * @param a The first value to compare
8
+ * @param b The second value to compare
9
+ * @returns True if the values are deeply equal, false otherwise
10
+ */
11
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
12
+ /**
13
+ * Creates a deep copy of a value.
14
+ *
15
+ * Essential for immutable state updates where you need to modify a nested property
16
+ * without mutating the original object.
17
+ *
18
+ * Uses `structuredClone` if available, falling back to JSON serialization.
19
+ * Note: The JSON fallback has limitations (e.g. loses Date objects, functions, undefined).
20
+ *
21
+ * @param value The value to clone
22
+ * @returns A deep copy of the value
23
+ */
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
+ * - `nutrientCycle.animalStock[].feeding.(winter|summer)Feeding`: never-filled routine
38
+ * slots (`{}` rows pre-created by the inline tables) and null fields are dropped;
39
+ * a season — and `feeding` itself — is removed when nothing filled-in remains
40
+ * - `nutrientCycle.fieldSpreading`: null fields dropped (`soilPh`, `slurry.*`,
41
+ * `manure.*`); `slurry`/`manure` removed when nothing filled-in remains
42
+ */
43
+ export declare function sanitizePlanningPayload(data: NaebiDataLike): NaebiDataLike;
44
+ /** Structural type so object.util stays free of a NaebiData import (circular-safe). */
45
+ type NaebiDataLike = Record<string, unknown>;
46
+ 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
  */
@@ -5,14 +5,20 @@
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[]>;
19
+ /**
20
+ * Pre-computed map of non-zero per-category minimum yields (yieldPerSquareMeasure).
21
+ * Only 8 of the 314 crop categories declare a minimum > 0 (e.g. cereals, peas);
22
+ * all others fall back to the schema-level `minimum: 0`.
23
+ */
24
+ export declare const CROP_MINIMUM_YIELD_PER_SQUARE_MEASURE: Record<string, number>;
@@ -1,5 +1,5 @@
1
1
  import { ErrorObject } from 'ajv';
2
- import { AnimalStockCategory, 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;
@@ -9,6 +9,34 @@ export interface EnrichedValidationError extends ErrorObject {
9
9
  targetAnimalStockIndex?: number;
10
10
  /** Navigation target: detail category (tab) */
11
11
  targetCategory?: AnimalStockCategory;
12
+ /** Navigation target: static section (e.g., lifetime performance panel) */
13
+ targetSection?: 'lifetimePerformance';
14
+ /** Navigation target: farm manure trading tab */
15
+ targetFarmManureTradingMode?: FarmManureTradingMode;
16
+ /** Navigation target: farm manure trading entry index */
17
+ targetFarmManureTradingIndex?: number;
18
+ /** Category tab inside farm manure trading detail */
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;
26
+ /** Category tab inside field spreading */
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;
12
40
  }
13
41
  /**
14
42
  * GlobalValidationService
@@ -21,12 +49,13 @@ export declare class GlobalValidationService {
21
49
  private readonly dataSvc;
22
50
  private readonly ajv;
23
51
  private readonly validateFn;
24
- private readonly rawErrors;
25
52
  readonly errors: import("@angular/core").Signal<EnrichedValidationError[]>;
26
- constructor();
27
- validate(): void;
28
53
  private consolidateErrors;
29
54
  private enrichErrors;
30
55
  private inferCategory;
56
+ private inferFarmTradingCategory;
57
+ private inferFieldSpreadingCategory;
58
+ private inferFodderCategory;
59
+ private inferStorageTab;
31
60
  private inferFieldLabel;
32
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,11 +3,17 @@ 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';
9
+ import { SelectedCategoryCategorizationRenderer } from '../renderers/layout/categorization/selected-category-categorization.renderer';
10
+ import { CustomArrayLayoutRenderer } from '../renderers/layout/array/array-layout.renderer';
8
11
  export declare const CUSTOM_JSONFORMS_RENDERERS: ({
9
12
  tester: RankedTester;
10
13
  renderer: typeof ConstraintLayoutRenderer;
14
+ } | {
15
+ tester: RankedTester;
16
+ renderer: typeof SelectedCategoryCategorizationRenderer;
11
17
  } | {
12
18
  tester: RankedTester;
13
19
  renderer: typeof CardGroupRenderer;
@@ -17,10 +23,16 @@ export declare const CUSTOM_JSONFORMS_RENDERERS: ({
17
23
  } | {
18
24
  tester: RankedTester;
19
25
  renderer: typeof LogicalGroupRenderer;
26
+ } | {
27
+ tester: RankedTester;
28
+ renderer: typeof ModuleToggleGroupRenderer;
20
29
  } | {
21
30
  tester: RankedTester;
22
31
  renderer: typeof AnimalCategorySelectRenderer;
23
32
  } | {
24
33
  tester: RankedTester;
25
34
  renderer: typeof CodeListSelectRenderer;
35
+ } | {
36
+ tester: RankedTester;
37
+ renderer: typeof CustomArrayLayoutRenderer;
26
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,20 +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;
13
+ private readonly controlScope;
14
+ private explicitCodeListKey;
10
15
  private controlKey;
11
16
  private listKey;
12
17
  readonly options: Signal<BaseCodeListEntry[]>;
18
+ readonly isMultiSelect: Signal<boolean>;
13
19
  private readonly filterConfig;
20
+ private readonly emptyHintKey;
21
+ private readonly dependsOnDataPath;
22
+ private readonly autoDependsOnDataPath;
23
+ private scopePointerToDataPath;
24
+ private inferListKeyFromScope;
25
+ private readValueAtPath;
14
26
  readonly filteredOptions: Signal<BaseCodeListEntry[]>;
15
27
  constructor(jsonFormsService: JsonFormsAngularService);
16
28
  getEventValue: (event: any) => any;
17
29
  optionLabel(opt: BaseCodeListEntry): string;
18
- onSelectionChange(value: number | string): void;
30
+ emptyHint(): string;
31
+ shouldShowEmptyHint(): boolean;
32
+ onSelectionChange(value: number | string | Array<number | string>): void;
19
33
  }
20
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;
@@ -0,0 +1,34 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { JsonFormsBaseRenderer } from '@jsonforms/angular';
3
+ import { Categorization, Category } from '@jsonforms/core';
4
+ /**
5
+ * Custom categorization renderer with programmatic tab selection via NavigationService.
6
+ *
7
+ * Extends JSONForms default categorization by reading category keys from UI schema options
8
+ * and syncing with NavigationService.selectedCategory signal for deep-linking (e.g., validation errors).
9
+ *
10
+ * UI Schema: Add "options": { "categoryKey": "<key>" } to each Category element.
11
+ * Navigation: Call navigationSvc.setCategory(page, key) or navigate methods to select tabs programmatically.
12
+ * Bidirectional: User tab clicks update NavigationService state automatically.
13
+ */
14
+ export declare class SelectedCategoryCategorizationRenderer extends JsonFormsBaseRenderer<Categorization> implements OnInit {
15
+ private readonly jsonFormsService;
16
+ private readonly navigationSvc;
17
+ hidden: boolean;
18
+ visibleCategories: (Category | Categorization)[];
19
+ categoryLabels: string[];
20
+ private readonly categoryKeyToIndex;
21
+ private readonly indexToCategoryKey;
22
+ private _prevCategorySignature;
23
+ readonly selectedTabIndex: import("@angular/core").Signal<number>;
24
+ ngOnInit(): void;
25
+ /**
26
+ * Build bidirectional category key ↔ tab index mapping from UI schema.
27
+ * Reads options.categoryKey from each visible Category element.
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).
31
+ */
32
+ private buildCategoryMappings;
33
+ onTabChange(newIndex: number): void;
34
+ }
@@ -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,38 @@
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 _enabled: import("@angular/core").WritableSignal<boolean>;
24
+ protected readonly _label: import("@angular/core").WritableSignal<string | undefined>;
25
+ protected readonly _description: import("@angular/core").WritableSignal<string | undefined>;
26
+ protected readonly _modules: import("@angular/core").WritableSignal<ModuleCard[]>;
27
+ readonly labelId: string;
28
+ hidden: () => boolean;
29
+ enabled: () => boolean;
30
+ label: () => string | undefined;
31
+ description: () => string | undefined;
32
+ modules: () => ModuleCard[];
33
+ ngOnInit(): void;
34
+ ngOnDestroy(): void;
35
+ /** Flip a single module boolean in the JSONForms data store. No-op while the group is disabled. */
36
+ toggle(dataPath: string): void;
37
+ }
38
+ export {};
@@ -0,0 +1,21 @@
1
+ import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
+ import { AnimalStockRow } from '../animal-stock.types';
3
+ import { ErrorObject } from 'ajv';
4
+ export declare class AnimalStockDetailComponent {
5
+ private readonly i18n;
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>;
11
+ private readonly baseUi;
12
+ localizedUi: import("@angular/core").Signal<UISchemaElement>;
13
+ jsonFormsData: import("@angular/core").Signal<(AnimalStockRow & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
14
+ readonly renderers: {
15
+ tester: import("@jsonforms/core").RankedTester;
16
+ renderer: any;
17
+ }[];
18
+ readonly suibiAjv: import("ajv").Ajv;
19
+ onDataChange(newData: any): void;
20
+ onValidationErrors(_errors: ErrorObject[] | null | undefined): void;
21
+ }
@@ -1,15 +1,12 @@
1
- import { EventEmitter, Signal } from '@angular/core';
2
- import { MatTable } from '@angular/material/table';
3
1
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
4
- import { AnimalStockRow } from './animal-stock.types';
2
+ import { AnimalStockRow } from '../animal-stock.types';
5
3
  export declare class AnimalStockListComponent {
6
4
  private readonly masterData;
7
- table: MatTable<AnimalStockRow>;
8
- rows: Signal<AnimalStockRow[]>;
9
- select: EventEmitter<number>;
10
- add: EventEmitter<void>;
11
- delete: EventEmitter<number>;
12
- reorder: EventEmitter<{
5
+ rows: import("@angular/core").InputSignal<AnimalStockRow[]>;
6
+ select: import("@angular/core").OutputEmitterRef<number>;
7
+ add: import("@angular/core").OutputEmitterRef<void>;
8
+ delete: import("@angular/core").OutputEmitterRef<number>;
9
+ reorder: import("@angular/core").OutputEmitterRef<{
13
10
  previousIndex: number;
14
11
  currentIndex: number;
15
12
  }>;
@@ -1,10 +1,11 @@
1
- import { AnimalStockRow } from './animal-stock.types';
1
+ import { AnimalStockRow } from '../animal-stock.types';
2
+ import { LifetimePerformance } from '../../lifetime-performance/lifetime-performance.types';
2
3
  export declare class AnimalStockMasterDetailComponent {
3
4
  private readonly dataSvc;
4
5
  private readonly navigationSvc;
5
- private readonly rootData;
6
6
  constructor();
7
7
  readonly rows: import("@angular/core").Signal<AnimalStockRow[]>;
8
+ readonly lifetimePerformance: import("@angular/core").Signal<LifetimePerformance | null>;
8
9
  readonly selectedIndex: import("@angular/core").WritableSignal<number | null>;
9
10
  readonly detailData: import("@angular/core").Signal<any>;
10
11
  openDetail(index: number): void;
@@ -17,5 +18,7 @@ export declare class AnimalStockMasterDetailComponent {
17
18
  currentIndex: number;
18
19
  }): void;
19
20
  onDetailChange(newData: any): void;
21
+ onLifetimePerformanceChange(payload: LifetimePerformance): void;
20
22
  private patchRows;
23
+ private patchLifetimePerformance;
21
24
  }
@@ -18,18 +18,18 @@ export interface Feeding {
18
18
  export interface Stall {
19
19
  stableSystem?: number;
20
20
  stableCapacity?: number;
21
- stableVentilationType?: number;
22
- stableAirPurification?: number;
21
+ stableVentilationType?: number | null;
22
+ stableAirPurification?: number | null;
23
23
  hasStableDeepLitter?: boolean;
24
24
  hasStableManureBeltDrying?: boolean;
25
- stableManureRemovalFrequency?: number;
26
- stableWaterSupply?: number;
25
+ stableManureRemovalFrequency?: number | null;
26
+ stableWaterSupply?: number | null;
27
27
  hasStableManureAndSlurryProduction?: boolean;
28
28
  hasStableFeedingStationElevated?: boolean;
29
29
  hasStableFloorSlopedUrineDrainage?: boolean;
30
30
  hasYard?: boolean;
31
- yardFeeding?: number;
32
- yardFloorType?: number;
31
+ yardFeeding?: number | null;
32
+ yardFloorType?: number | null;
33
33
  yardDays?: number;
34
34
  yardHoursPerDay?: number;
35
35
  }
@@ -0,0 +1,4 @@
1
+ export * from './animal-stock-list/animal-stock-list.component';
2
+ export * from './animal-stock-detail/animal-stock-detail.component';
3
+ export * from './animal-stock-master-detail/animal-stock-master-detail.component';
4
+ export * from './animal-stock.types';
@@ -0,0 +1,19 @@
1
+ import { FarmManureTradingSupply, FarmManureTradingDispense } from '../farm-manure-trading.types';
2
+ /**
3
+ * Farm manure trading page — two inline tables (supply "Reprises" / dispense
4
+ * "Cessions") editing `nutrientCycle.farmManureTrading` directly. The former
5
+ * master-detail round-trip (list + JSONForms detail pane) was replaced by inline
6
+ * editing, so validation deep-links (`selectedFarmManureTrading`) are merely
7
+ * consumed and cleared — there is no detail pane left to open (fodder pattern).
8
+ */
9
+ export declare class FarmManureTradingMasterDetailComponent {
10
+ private readonly dataSvc;
11
+ private readonly navigationSvc;
12
+ constructor();
13
+ readonly supplyRows: import("@angular/core").Signal<FarmManureTradingSupply[]>;
14
+ readonly dispenseRows: import("@angular/core").Signal<FarmManureTradingDispense[]>;
15
+ onSupplyChange(rows: FarmManureTradingSupply[]): void;
16
+ onDispenseChange(rows: FarmManureTradingDispense[]): void;
17
+ private patchRows;
18
+ private cloneTrading;
19
+ }
@@ -0,0 +1,37 @@
1
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
2
+ import { FarmManureTradingMode } from '../../../core/navigation/navigation.service';
3
+ import { FarmManureTradingSupply, FarmManureTradingDispense } from '../farm-manure-trading.types';
4
+ type TradingRow = FarmManureTradingSupply | FarmManureTradingDispense;
5
+ /**
6
+ * FarmManureTradingTableComponent — thin wrapper around InlineTableComponent.
7
+ *
8
+ * Responsibilities:
9
+ * 1. Provides the per-mode column/section config (the "uischema").
10
+ * 2. Bridges typed `FarmManureTradingSupply[]`/`Dispense[]` to/from the generic
11
+ * `Record<string, unknown>[]` API of InlineTableComponent.
12
+ * 3. Supplies `deriveUnits` as a `rowTransform` — the base `transactionUnit` ('kg'/'m3')
13
+ * and every ingredient's `unit` ('kg/t'/'kg/m3') are derived from the selected
14
+ * product's matterState; the user may switch to a custom unit sharing the same base
15
+ * (t, dt for kg), which converts the entered quantity on the fly.
16
+ */
17
+ export declare class FarmManureTradingTableComponent {
18
+ readonly mode: import("@angular/core").InputSignal<FarmManureTradingMode>;
19
+ readonly entries: import("@angular/core").InputSignal<TradingRow[]>;
20
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<TradingRow[]>;
21
+ protected readonly config: import("@angular/core").Signal<InlineTableConfig>;
22
+ /** Cast typed entries to generic Record[] for InlineTableComponent. */
23
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
24
+ /** Cast generic output back to typed trading rows. */
25
+ onRowsChange(rows: Record<string, unknown>[]): void;
26
+ /**
27
+ * Row transform deriving the ingredient units from the product's matterState on each
28
+ * edit, and handling `transactionUnit`:
29
+ * - product change (or missing unit on legacy rows): reset to the derived base unit,
30
+ * - unit switch: convert the entered quantity from the previous to the new unit
31
+ * (both share the same base), so the transacted amount is preserved.
32
+ * - no product picked yet: keep the pre-filtered unit the user chose (kg/m3/t/dt)
33
+ * instead of clearing it on every edit.
34
+ */
35
+ readonly deriveUnits: (changedKey: string, newValue: unknown, row: Record<string, unknown>, previousRow?: Record<string, unknown>) => Record<string, unknown>;
36
+ }
37
+ export {};