@agridea/suibi-module 0.1.0-preview.2f7b6e2 → 0.1.0-preview.387f5dc

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 (79) hide show
  1. package/README.md +10 -10
  2. package/dist/elements/browser/main.js +71 -72
  3. package/dist/elements/browser/suibi-module-latest.js +71 -72
  4. package/dist/elements/browser/suibi-module.v0.1.0-preview.387f5dc.js +78 -0
  5. package/dist/elements/browser/suibi-theme-dark.css +1 -1
  6. package/dist/elements/browser/version.txt +1 -1
  7. package/dist/types/app/components/data-preview/data-preview.component.d.ts +2 -2
  8. package/dist/types/app/components/empty-state/empty-state.component.d.ts +2 -0
  9. package/dist/types/app/components/gauge-arc/gauge-arc.component.d.ts +49 -0
  10. package/dist/types/app/{header-bar.d.ts → components/header-bar/header-bar.component.d.ts} +3 -4
  11. package/dist/types/app/components/inline-table/inline-table.component.d.ts +104 -0
  12. package/dist/types/app/components/inline-table/inline-table.types.d.ts +129 -0
  13. package/dist/types/app/components/module-placeholder-page/module-placeholder-page.component.d.ts +6 -0
  14. package/dist/types/app/components/planning-result/planning-result.component.d.ts +3 -26
  15. package/dist/types/app/components/planning-result-row/planning-result-row.component.d.ts +34 -0
  16. package/dist/types/app/components/planning-trigger/planning-trigger.component.d.ts +13 -0
  17. package/dist/types/app/components/results-page/results-page.component.d.ts +13 -0
  18. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +30 -0
  19. package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-metrics.service.d.ts +21 -0
  20. package/dist/types/app/components/suissebilanz-minibar/suissebilanz-minibar.component.d.ts +19 -0
  21. package/dist/types/app/components/validation-page/validation-page.component.d.ts +18 -0
  22. package/dist/types/app/components/welcome-page/metadata.types.d.ts +1 -1
  23. package/dist/types/app/components/welcome-page/welcome-page.component.d.ts +5 -3
  24. package/dist/types/app/components/workflow-stepper/workflow-stepper.component.d.ts +1 -0
  25. package/dist/types/app/core/data/naebi-data.service.d.ts +28 -28
  26. package/dist/types/app/core/error/global-error-handler.d.ts +2 -3
  27. package/dist/types/app/core/i18n/i18n.service.d.ts +4 -3
  28. package/dist/types/app/core/i18n/locales/fr.d.ts +2 -0
  29. package/dist/types/app/core/i18n/locales/it.d.ts +2 -0
  30. package/dist/types/app/core/master-data/master-data.service.d.ts +2 -0
  31. package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +11 -1
  32. package/dist/types/app/core/navigation/navigation.service.d.ts +27 -1
  33. package/dist/types/app/core/planning/planning-balance.service.d.ts +23 -3
  34. package/dist/types/app/core/planning/planning-balance.utils.d.ts +10 -0
  35. package/dist/types/app/core/utils/object.util.d.ts +10 -0
  36. package/dist/types/app/core/validation/global-validation.service.d.ts +19 -1
  37. package/dist/types/app/jsonforms/filters/code-list-filter-resolvers.d.ts +3 -0
  38. package/dist/types/app/jsonforms/registry/renderers.registry.d.ts +4 -0
  39. package/dist/types/app/jsonforms/renderers/controls/selects/animal-category/animal-category-select.renderer.d.ts +1 -1
  40. package/dist/types/app/jsonforms/renderers/controls/selects/code-list/code-list-select.renderer.d.ts +10 -4
  41. package/dist/types/app/jsonforms/renderers/layout/constraint/constraint-layout.renderer.d.ts +1 -0
  42. package/dist/types/app/jsonforms/renderers/layout/group/base-group.renderer.d.ts +2 -0
  43. package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +36 -0
  44. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-detail.component.d.ts +7 -8
  45. package/dist/types/app/nutrient-cycle/animal-stock/animal-stock-list.component.d.ts +5 -8
  46. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +8 -9
  47. package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +6 -7
  48. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-detail.component.d.ts +22 -0
  49. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-general.component.d.ts +22 -0
  50. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-list.component.d.ts +17 -0
  51. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail.component.d.ts +37 -0
  52. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +40 -0
  53. package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.util.d.ts +6 -0
  54. package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +4 -0
  55. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +43 -0
  56. package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.config.d.ts +20 -0
  57. package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +16 -3
  58. package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
  59. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +31 -0
  60. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +17 -0
  61. package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
  62. package/dist/types/app/nutrient-cycle/fodder/fodder-detail.component.d.ts +31 -0
  63. package/dist/types/app/nutrient-cycle/fodder/fodder-list.component.d.ts +20 -0
  64. package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail.component.d.ts +37 -0
  65. package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +27 -0
  66. package/dist/types/app/nutrient-cycle/fodder/index.d.ts +4 -0
  67. package/dist/types/app/nutrient-cycle/fodder/transaction-unit.util.d.ts +2 -0
  68. package/dist/types/app/nutrient-cycle/lifetime-performance/index.d.ts +2 -0
  69. package/dist/types/app/nutrient-cycle/storage/index.d.ts +4 -0
  70. package/dist/types/app/nutrient-cycle/storage/storage-detail.component.d.ts +30 -0
  71. package/dist/types/app/nutrient-cycle/storage/storage-general.component.d.ts +29 -0
  72. package/dist/types/app/nutrient-cycle/storage/storage-list.component.d.ts +23 -0
  73. package/dist/types/app/nutrient-cycle/storage/storage-master-detail.component.d.ts +32 -0
  74. package/dist/types/app/nutrient-cycle/storage/storage.types.d.ts +40 -0
  75. package/dist/types/shared/material-icons.d.ts +3 -3
  76. package/package.json +68 -17
  77. package/dist/elements/browser/suibi-module.v0.1.0-preview.2f7b6e2.js +0 -79
  78. /package/dist/elements/browser/{suibi-module.v0.1.0-preview.2f7b6e2.css → suibi-module.v0.1.0-preview.387f5dc.css} +0 -0
  79. /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,17 @@
1
+ import { FieldCultivationDetailEntry, FieldCultivationDetailMode } from './field-cultivation.types';
2
+ export declare class FieldCultivationListComponent {
3
+ private readonly masterData;
4
+ private readonly i18n;
5
+ readonly rows: import("@angular/core").InputSignal<FieldCultivationDetailEntry[]>;
6
+ readonly selectedIndex: import("@angular/core").InputSignal<number | null>;
7
+ readonly mode: import("@angular/core").InputSignal<FieldCultivationDetailMode>;
8
+ readonly select: import("@angular/core").OutputEmitterRef<number>;
9
+ readonly add: import("@angular/core").OutputEmitterRef<void>;
10
+ readonly delete: import("@angular/core").OutputEmitterRef<number>;
11
+ readonly displayedColumns: string[];
12
+ resolveCrop(code: string | null | undefined): string;
13
+ emptyLabel(): string;
14
+ emptyHintLabel(): string;
15
+ addLabel(): string;
16
+ onDelete(index: number, event: Event): void;
17
+ }
@@ -0,0 +1,37 @@
1
+ import { FieldCultivationTab } from '../../core/navigation/navigation.service';
2
+ import { FieldCultivationArableLand, FieldCultivationData, FieldCultivationDetailEntry, FieldCultivationDetailMode, FieldCultivationFodderCropland, FieldCultivationSpecial } from './field-cultivation.types';
3
+ export declare class FieldCultivationMasterDetailComponent {
4
+ private readonly dataSvc;
5
+ private readonly navigationSvc;
6
+ constructor();
7
+ readonly fieldCultivation: import("@angular/core").Signal<FieldCultivationData>;
8
+ readonly fodderCroplandRows: import("@angular/core").Signal<FieldCultivationFodderCropland[]>;
9
+ readonly arableLandRows: import("@angular/core").Signal<FieldCultivationArableLand[]>;
10
+ readonly specialRows: import("@angular/core").Signal<FieldCultivationSpecial[]>;
11
+ readonly activeTab: import("@angular/core").WritableSignal<FieldCultivationTab>;
12
+ readonly selectedFodderCroplandIndex: import("@angular/core").WritableSignal<number | null>;
13
+ readonly selectedArableLandIndex: import("@angular/core").WritableSignal<number | null>;
14
+ readonly selectedSpecialIndex: import("@angular/core").WritableSignal<number | null>;
15
+ readonly detailOpen: import("@angular/core").Signal<boolean>;
16
+ readonly currentIndex: import("@angular/core").Signal<number | null>;
17
+ readonly currentDetail: import("@angular/core").Signal<FieldCultivationDetailEntry | null>;
18
+ readonly selectedFodderCroplandListIndex: import("@angular/core").Signal<number | null>;
19
+ readonly selectedArableLandListIndex: import("@angular/core").Signal<number | null>;
20
+ readonly selectedSpecialListIndex: import("@angular/core").Signal<number | null>;
21
+ readonly activeDetailMode: import("@angular/core").Signal<FieldCultivationDetailMode>;
22
+ readonly activeTabIndex: import("@angular/core").Signal<0 | 1 | 2 | 3>;
23
+ onTabChange(index: number): void;
24
+ openDetail(mode: FieldCultivationDetailMode, index: number): void;
25
+ closeDetail(): void;
26
+ addEntry(mode: FieldCultivationDetailMode): void;
27
+ deleteEntry(mode: FieldCultivationDetailMode, index: number): void;
28
+ onGeneralChange(value: FieldCultivationData): void;
29
+ onDetailChange(value: FieldCultivationDetailEntry): void;
30
+ private patchRows;
31
+ private patchFieldCultivation;
32
+ private rowsForMode;
33
+ private selectedIndexSignal;
34
+ private clearSelections;
35
+ private clearInvalidSelection;
36
+ private parseTab;
37
+ }
@@ -0,0 +1,40 @@
1
+ export interface FieldCultivationRequirementCorrection {
2
+ quantity?: number | null;
3
+ molecularFormula?: string | null;
4
+ unit?: string | null;
5
+ }
6
+ export interface FieldCultivationCropHarvest {
7
+ agronomicCropCategory?: string | null;
8
+ userSpecificPlantName?: string | null;
9
+ effectiveYield?: number | null;
10
+ }
11
+ export interface FieldCultivationBaseEntry {
12
+ agronomicCropCategory?: string | null;
13
+ userSpecificPlantName?: string | null;
14
+ isMainCrop?: boolean;
15
+ areaSize?: number | null;
16
+ yieldPerSquareMeasure?: number | null;
17
+ }
18
+ export interface FieldCultivationFodderCropland extends FieldCultivationBaseEntry {
19
+ fieldName?: string | null;
20
+ calculateYieldThroughFodderBalance?: boolean;
21
+ }
22
+ export interface FieldCultivationArableLand extends FieldCultivationBaseEntry {
23
+ hasLongTermYieldDivergence?: boolean;
24
+ requirementCorrection?: FieldCultivationRequirementCorrection[];
25
+ }
26
+ export interface FieldCultivationSpecial extends FieldCultivationBaseEntry {
27
+ requirementCorrection?: FieldCultivationRequirementCorrection[];
28
+ }
29
+ export interface FieldCultivationData {
30
+ buildingZoneAreaSize?: number | null;
31
+ outdoorVegetableMainCropAreaSize?: number | null;
32
+ indoorVegetableMainCropAreaSize?: number | null;
33
+ feedingOfCropHarvest?: FieldCultivationCropHarvest[];
34
+ dispenseOfCropHarvest?: FieldCultivationCropHarvest[];
35
+ fodderCropland?: FieldCultivationFodderCropland[];
36
+ arableLand?: FieldCultivationArableLand[];
37
+ special?: FieldCultivationSpecial[];
38
+ }
39
+ export type FieldCultivationDetailMode = 'fodderCropland' | 'arableLand' | 'special';
40
+ export type FieldCultivationDetailEntry = FieldCultivationFodderCropland | FieldCultivationArableLand | FieldCultivationSpecial;
@@ -0,0 +1,6 @@
1
+ import { FieldCultivationCropHarvest, FieldCultivationData, FieldCultivationDetailEntry, FieldCultivationDetailMode, FieldCultivationRequirementCorrection } from './field-cultivation.types';
2
+ export declare function normalizeRequirementCorrection(source: Partial<FieldCultivationRequirementCorrection> | undefined): FieldCultivationRequirementCorrection;
3
+ export declare function normalizeCropHarvestEntry(source: Partial<FieldCultivationCropHarvest> | undefined): FieldCultivationCropHarvest;
4
+ export declare function normalizeFieldCultivationDetailEntry(mode: FieldCultivationDetailMode, source: Partial<FieldCultivationDetailEntry> | undefined): FieldCultivationDetailEntry;
5
+ export declare function createEmptyFieldCultivationDetailEntry(mode: FieldCultivationDetailMode): FieldCultivationDetailEntry;
6
+ export declare function normalizeFieldCultivation(source: Partial<FieldCultivationData> | undefined): FieldCultivationData;
@@ -0,0 +1,4 @@
1
+ export * from './field-cultivation-list.component';
2
+ export * from './field-cultivation-detail.component';
3
+ export * from './field-cultivation-master-detail.component';
4
+ export * from './field-cultivation.types';
@@ -0,0 +1,43 @@
1
+ import { FieldSpreadingFertiliserEntry } from '../field-spreading.types';
2
+ /**
3
+ * FertiliserTableComponent — thin wrapper around InlineTableComponent.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Provides `FERTILISER_TABLE_CONFIG` (the column/section "uischema") to the
7
+ * generic table component.
8
+ * 2. Bridges the typed `FieldSpreadingFertiliserEntry[]` inputs/outputs to the
9
+ * generic `Record<string, unknown>[]` API expected by InlineTableComponent.
10
+ * 3. Supplies `autoPopulateNutrients` as a `rowTransform` — domain logic that
11
+ * pre-fills Ntot/P₂O₅/K₂O/Mg from the product's max values on product selection.
12
+ *
13
+ * To create a similar table for another domain:
14
+ * 1. Copy `fertiliser-table.config.ts` and define new columns there.
15
+ * 2. Create a new thin wrapper component (like this one) that wires the config
16
+ * and an optional rowTransform.
17
+ * 3. The generic InlineTableComponent requires no changes.
18
+ */
19
+ export declare class FertiliserTableComponent {
20
+ readonly entries: import("@angular/core").InputSignal<FieldSpreadingFertiliserEntry[]>;
21
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldSpreadingFertiliserEntry[]>;
22
+ /** Column/section config exposed to the template (constant — no signal needed). */
23
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
24
+ /** Cast typed entries to the generic Record[] expected by InlineTableComponent. */
25
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
26
+ /** Cast the generic output back to the typed FieldSpreadingFertiliserEntry[], stripping any
27
+ * ingredient with a 0 quantity so it never reaches the final JSON. */
28
+ onRowsChange(rows: Record<string, unknown>[]): void;
29
+ /**
30
+ * Row transform for auto-populating nutrient columns when a product is selected.
31
+ *
32
+ * Also imposes `transactionUnit = 'kg'` on every edit (not just product changes) so
33
+ * stale/imported rows with a different or null unit get corrected once touched —
34
+ * `createRow` already defaults new rows to 'kg', this is only a safety net.
35
+ *
36
+ * Defined as an arrow-function property so `this` is never needed and the function
37
+ * can be passed as a value to InlineTableComponent without losing its context.
38
+ *
39
+ * Only reacts to changes on the `fertiliserProductCategory` column key; all other
40
+ * edits pass through unchanged.
41
+ */
42
+ readonly autoPopulateNutrients: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
43
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Column and section configuration for the Mineral Fertiliser inline table.
3
+ *
4
+ * This is the "uischema" for the Mineral fertilisers tab — it is the ONLY file
5
+ * that needs to be created/modified when adapting the inline table pattern for
6
+ * a different domain (e.g. recycling entries).
7
+ *
8
+ * Relationship to InlineTableComponent:
9
+ * - `columns` → drives header labels, cell widgets, grid widths, and code-list sources
10
+ * - `createRow` → produces a blank row with the ingredient sub-array pre-initialised
11
+ * - Labels reference i18n keys; chemical formula headers use `labelLiteral: true`
12
+ *
13
+ * Auto-population of nutrient columns on product selection is NOT configured here —
14
+ * that business logic lives in FertiliserTableComponent as a `rowTransform` function.
15
+ */
16
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
17
+ /** The four nutrient formulas tracked per fertiliser entry, in display order. */
18
+ export declare const NUTRIENT_COLUMNS: readonly ["Ntot", "P2O5", "K2O", "Mg"];
19
+ export type NutrientFormula = (typeof NUTRIENT_COLUMNS)[number];
20
+ export declare const FERTILISER_TABLE_CONFIG: InlineTableConfig;
@@ -1,12 +1,12 @@
1
- import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
- import { FieldSpreadingData } from './field-spreading.types';
1
+ import { JsonSchema } from '@jsonforms/core';
2
+ import { FieldSpreadingData, FieldSpreadingFertiliserEntry, FieldSpreadingRecyclingEntry } from './field-spreading.types';
3
3
  export declare class FieldSpreadingComponent {
4
4
  private readonly dataSvc;
5
5
  private readonly navigationSvc;
6
6
  private readonly i18n;
7
7
  constructor();
8
8
  readonly schema: import("@angular/core").Signal<JsonSchema>;
9
- readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
9
+ readonly localizedGeneralUi: import("@angular/core").Signal<import("@jsonforms/core").UISchemaElement>;
10
10
  readonly renderers: {
11
11
  tester: import("@jsonforms/core").RankedTester;
12
12
  renderer: any;
@@ -14,7 +14,20 @@ export declare class FieldSpreadingComponent {
14
14
  readonly ajv: import("ajv").Ajv;
15
15
  private readonly normalizedFieldSpreading;
16
16
  readonly jsonFormsData: import("@angular/core").Signal<(FieldSpreadingData & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
17
+ /** Fertiliser entries exposed to the custom table component. */
18
+ readonly fertiliserEntries: import("@angular/core").Signal<FieldSpreadingFertiliserEntry[]>;
19
+ /** Recycling entries exposed to the custom table component. */
20
+ readonly recyclingEntries: import("@angular/core").Signal<FieldSpreadingRecyclingEntry[]>;
21
+ /** Drives mat-tab-group [selectedIndex] from NavigationService state. */
22
+ readonly activeTabIndex: import("@angular/core").Signal<number>;
23
+ onTabChange(index: number): void;
24
+ /** Called by both general JSONForms instances on data change.
25
+ * Preserves fertiliser and recycling entries managed by their custom table components. */
17
26
  onDataChange(event: unknown): void;
27
+ /** Called by FertiliserTableComponent when entries are added/edited/removed. */
28
+ onFertiliserChange(fertiliser: FieldSpreadingFertiliserEntry[]): void;
29
+ /** Called by RecyclingTableComponent when entries are added/edited/removed. */
30
+ onRecyclingChange(recycling: FieldSpreadingRecyclingEntry[]): void;
18
31
  private patchFieldSpreading;
19
32
  private normalizeFieldSpreading;
20
33
  private areFieldSpreadingEqual;
@@ -0,0 +1,8 @@
1
+ import { FieldSpreadingIngredient } from './field-spreading.types';
2
+ /**
3
+ * Ensures all ingredients are present in the output, converting `null` quantities to `0`
4
+ * to satisfy API requirements while still filtering out explicitly zeroed entries.
5
+ */
6
+ export declare function stripZeroQuantityIngredients<T extends {
7
+ ingredient?: FieldSpreadingIngredient[];
8
+ }>(entries: T[]): T[];
@@ -0,0 +1,31 @@
1
+ import { FieldSpreadingRecyclingEntry } from '../field-spreading.types';
2
+ /**
3
+ * RecyclingTableComponent — thin wrapper around InlineTableComponent.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Provides `RECYCLING_TABLE_CONFIG` (the column/section "uischema").
7
+ * 2. Bridges typed `FieldSpreadingRecyclingEntry[]` to/from the generic
8
+ * `Record<string, unknown>[]` API of InlineTableComponent.
9
+ * 3. Supplies `deriveUnits` as a `rowTransform` — `transactionUnit` ('kg'/'m3') and every
10
+ * ingredient's `unit` ('kg/t'/'kg/m3') are fully derived from the selected product's
11
+ * matterState (never user-entered) — they are separate mappings, NOT a concatenation of
12
+ * one into the other (kg/kg would be wrong for solid products).
13
+ */
14
+ export declare class RecyclingTableComponent {
15
+ readonly entries: import("@angular/core").InputSignal<FieldSpreadingRecyclingEntry[]>;
16
+ readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldSpreadingRecyclingEntry[]>;
17
+ /** Column/section config (constant — no signal needed). */
18
+ protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
19
+ /** Cast typed entries to generic Record[] for InlineTableComponent. */
20
+ readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
21
+ /** Cast generic output back to typed FieldSpreadingRecyclingEntry[], stripping any
22
+ * ingredient with a 0 quantity so it never reaches the final JSON. */
23
+ onRowsChange(rows: Record<string, unknown>[]): void;
24
+ /**
25
+ * Row transform re-deriving `transactionUnit` and every ingredient's `unit` from the
26
+ * product's matterState on each edit — runs unconditionally (not just when
27
+ * `typeOfManureRecyclingProduct` changes) so an edit made before the product is picked still
28
+ * resolves once it is.
29
+ */
30
+ readonly deriveUnits: (_changedKey: string, _newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
31
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Column and section configuration for the Recycling Fertiliser inline table.
3
+ *
4
+ * This is the "uischema" for the Recycling fertilisers tab.
5
+ * The structure mirrors fertiliser-table.config.ts — only the columns differ:
6
+ * - Product field: typeOfManureRecyclingProduct (different code list)
7
+ * - Nutrient columns: Ntot, Nlos, P₂O₅, K₂O, Mg expressed in kg/unit (not %)
8
+ * — 5 nutrients vs 4 for mineral fertilisers, no auto-population on product select.
9
+ *
10
+ * To adapt again for a new domain, copy this file and adjust columns + i18n keys.
11
+ */
12
+ import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
13
+ /** Nutrient formulas tracked per recycling entry, in display order. 'Nlos' = soluble nitrogen (matches the
14
+ * `molecularFormula` enum from assets/master-data/substances.json — NOT 'NSol', which the API rejects). */
15
+ export declare const RECYCLING_NUTRIENT_COLUMNS: readonly ["Ntot", "Nlos", "P2O5", "K2O", "Mg"];
16
+ export type RecyclingNutrientFormula = (typeof RECYCLING_NUTRIENT_COLUMNS)[number];
17
+ export declare const RECYCLING_TABLE_CONFIG: InlineTableConfig;
@@ -0,0 +1,4 @@
1
+ /** Derives the mandatory transaction unit ('kg' or 'm3') from the product's matterState. */
2
+ export declare function deriveRecyclingTransactionUnit(productCode: string | null | undefined): string | null;
3
+ /** Derives the mandatory ingredient unit ('kg/t' or 'kg/m3') from the product's matterState. */
4
+ export declare function deriveRecyclingIngredientUnit(productCode: string | null | undefined): string | null;
@@ -0,0 +1,31 @@
1
+ import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
+ import { FodderMode } from '../../core/navigation/navigation.service';
3
+ import { FodderCropFromNonFodderCropland, FodderDispense, FodderSupply } from './fodder.types';
4
+ type FodderRow = FodderSupply | FodderDispense | FodderCropFromNonFodderCropland;
5
+ export declare class FodderDetailComponent {
6
+ private readonly i18n;
7
+ row: import("@angular/core").InputSignal<FodderRow | null>;
8
+ index: import("@angular/core").InputSignal<number | null>;
9
+ mode: import("@angular/core").InputSignal<FodderMode>;
10
+ rowChange: import("@angular/core").OutputEmitterRef<FodderRow>;
11
+ close: import("@angular/core").OutputEmitterRef<void>;
12
+ readonly renderers: {
13
+ tester: import("@jsonforms/core").RankedTester;
14
+ renderer: any;
15
+ }[];
16
+ readonly suibiAjv: import("ajv").Ajv;
17
+ private readonly baseSchemas;
18
+ private readonly baseUis;
19
+ readonly itemSchema: import("@angular/core").Signal<JsonSchema>;
20
+ readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
21
+ readonly detailTitle: import("@angular/core").Signal<string>;
22
+ readonly jsonFormsData: import("@angular/core").Signal<({
23
+ quantity?: number;
24
+ typeOfFeedstuffProduct?: string;
25
+ transactionUnit?: string;
26
+ ingredient?: import("./fodder.types").FodderIngredient[];
27
+ } & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
28
+ onDataChange(event: unknown): void;
29
+ private applyDerivedFields;
30
+ }
31
+ export {};
@@ -0,0 +1,20 @@
1
+ import { FodderCropFromNonFodderCropland, FodderDispense, FodderSupply } from './fodder.types';
2
+ import { FodderMode } from '../../core/navigation/navigation.service';
3
+ type FodderRow = FodderSupply | FodderDispense | FodderCropFromNonFodderCropland;
4
+ export declare class FodderListComponent {
5
+ private readonly masterData;
6
+ private readonly i18n;
7
+ rows: import("@angular/core").InputSignal<FodderRow[]>;
8
+ selectedIndex: import("@angular/core").InputSignal<number | null>;
9
+ mode: import("@angular/core").InputSignal<FodderMode>;
10
+ select: import("@angular/core").OutputEmitterRef<number>;
11
+ add: import("@angular/core").OutputEmitterRef<void>;
12
+ delete: import("@angular/core").OutputEmitterRef<number>;
13
+ readonly displayedColumns: string[];
14
+ resolveProduct(code: string | null | undefined): string;
15
+ emptyLabel(): string;
16
+ emptyHintLabel(): string;
17
+ addLabel(): string;
18
+ onDelete(index: number, event: Event): void;
19
+ }
20
+ export {};
@@ -0,0 +1,37 @@
1
+ import { FodderMode } from '../../core/navigation/navigation.service';
2
+ import { FodderCropFromNonFodderCropland, FodderDispense, FodderSupply } from './fodder.types';
3
+ type FodderRow = FodderSupply | FodderDispense | FodderCropFromNonFodderCropland;
4
+ export declare class FodderMasterDetailComponent {
5
+ private readonly dataSvc;
6
+ private readonly navigationSvc;
7
+ constructor();
8
+ readonly supplyRows: import("@angular/core").Signal<FodderSupply[]>;
9
+ readonly dispenseRows: import("@angular/core").Signal<FodderDispense[]>;
10
+ readonly nonFodderCroplandRows: import("@angular/core").Signal<FodderCropFromNonFodderCropland[]>;
11
+ readonly proportionStorageLoss: import("@angular/core").Signal<number | undefined>;
12
+ readonly totalBalanceErrorMargin: import("@angular/core").Signal<number | undefined>;
13
+ readonly activeTab: import("@angular/core").WritableSignal<FodderMode>;
14
+ readonly selectedSupplyIndex: import("@angular/core").WritableSignal<number | null>;
15
+ readonly selectedDispenseIndex: import("@angular/core").WritableSignal<number | null>;
16
+ readonly selectedNonFodderCroplandIndex: import("@angular/core").WritableSignal<number | null>;
17
+ readonly currentDetail: import("@angular/core").Signal<FodderRow | null>;
18
+ readonly currentIndex: import("@angular/core").Signal<number | null>;
19
+ readonly detailOpen: import("@angular/core").Signal<boolean>;
20
+ readonly activeTabIndex: import("@angular/core").Signal<0 | 1 | 2>;
21
+ onTabChange(index: number): void;
22
+ openDetail(mode: FodderMode, index: number): void;
23
+ closeDetail(): void;
24
+ addEntry(mode: FodderMode): void;
25
+ deleteEntry(mode: FodderMode, index: number): void;
26
+ onDetailChange(payload: FodderRow): void;
27
+ onScalarInput(field: 'proportionStorageLoss' | 'totalBalanceErrorMargin', event: Event): void;
28
+ scalarInputValue(value: number | undefined): string;
29
+ private clearInvalidSelection;
30
+ private selectedIndexSignal;
31
+ private rowsForMode;
32
+ private createEmptyEntry;
33
+ private patchRows;
34
+ private cloneFodder;
35
+ private cloneTrading;
36
+ }
37
+ export {};
@@ -0,0 +1,27 @@
1
+ export interface FodderIngredient {
2
+ quantity?: number;
3
+ molecularFormula?: string;
4
+ unit?: string;
5
+ }
6
+ export interface FodderTradingEntry {
7
+ quantity?: number;
8
+ typeOfFeedstuffProduct?: string;
9
+ transactionUnit?: string;
10
+ ingredient?: FodderIngredient[];
11
+ }
12
+ export interface FodderSupply extends FodderTradingEntry {
13
+ }
14
+ export interface FodderDispense extends FodderTradingEntry {
15
+ }
16
+ export interface FodderCropFromNonFodderCropland extends FodderTradingEntry {
17
+ }
18
+ export interface FodderTradingData {
19
+ supply?: FodderSupply[];
20
+ dispense?: FodderDispense[];
21
+ }
22
+ export interface FodderData {
23
+ trading?: FodderTradingData;
24
+ cropFromNonFodderCropland?: FodderCropFromNonFodderCropland[];
25
+ proportionStorageLoss?: number;
26
+ totalBalanceErrorMargin?: number;
27
+ }
@@ -0,0 +1,4 @@
1
+ export * from './fodder-list.component';
2
+ export * from './fodder-detail.component';
3
+ export * from './fodder-master-detail.component';
4
+ export * from './fodder.types';
@@ -0,0 +1,2 @@
1
+ export declare const FODDER_TRANSACTION_UNIT = "kg";
2
+ export declare function deriveFodderTransactionUnit(): string;
@@ -0,0 +1,2 @@
1
+ export * from './lifetime-performance-form.component';
2
+ export * from './lifetime-performance.types';
@@ -0,0 +1,4 @@
1
+ export * from './storage-list.component';
2
+ export * from './storage-detail.component';
3
+ export * from './storage-master-detail.component';
4
+ export * from './storage.types';
@@ -0,0 +1,30 @@
1
+ import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
+ import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from './storage.types';
3
+ export declare class StorageDetailComponent {
4
+ private readonly i18n;
5
+ readonly type: import("@angular/core").InputSignal<StorageEntryType>;
6
+ readonly row: import("@angular/core").InputSignal<ManurePitEntry | SlurryTankEntry | null>;
7
+ readonly rowChange: import("@angular/core").OutputEmitterRef<ManurePitEntry | SlurryTankEntry>;
8
+ readonly close: import("@angular/core").OutputEmitterRef<void>;
9
+ readonly renderers: {
10
+ tester: import("@jsonforms/core").RankedTester;
11
+ renderer: any;
12
+ }[];
13
+ readonly ajv: import("ajv").Ajv;
14
+ readonly schema: import("@angular/core").Signal<JsonSchema>;
15
+ readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
16
+ readonly detailTitle: import("@angular/core").Signal<string>;
17
+ readonly jsonFormsData: import("@angular/core").Signal<(({
18
+ descriptor?: string;
19
+ cover?: number | null;
20
+ manureFromAnimalStockStored?: import("./storage.types").ManureFromAnimalStockStored[];
21
+ } | {
22
+ descriptor?: string;
23
+ volumeInM3?: number | null;
24
+ depthInM?: number | null;
25
+ cover?: number | null;
26
+ mixingFrequency?: number | null;
27
+ manureDerivation?: string[];
28
+ }) & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
29
+ onDataChange(event: unknown): void;
30
+ }
@@ -0,0 +1,29 @@
1
+ import { JsonSchema, UISchemaElement } from '@jsonforms/core';
2
+ import { StorageNormalized } from './storage.types';
3
+ type StorageSection = 'manure' | 'slurry' | 'slurryFacilityToggle' | 'general';
4
+ export declare class StorageGeneralComponent {
5
+ private readonly i18n;
6
+ readonly section: import("@angular/core").InputSignal<StorageSection>;
7
+ readonly value: import("@angular/core").InputSignal<StorageNormalized>;
8
+ readonly valueChange: import("@angular/core").OutputEmitterRef<StorageNormalized>;
9
+ readonly renderers: {
10
+ tester: import("@jsonforms/core").RankedTester;
11
+ renderer: any;
12
+ }[];
13
+ readonly ajv: import("ajv").Ajv;
14
+ readonly schema: import("@angular/core").Signal<JsonSchema>;
15
+ readonly localizedUi: import("@angular/core").Signal<UISchemaElement>;
16
+ readonly jsonFormsData: import("@angular/core").Signal<({
17
+ stableStrawLitter: number | null;
18
+ manureSupplyProportionStored: number | null;
19
+ createFacilitySpecificManureProduct: boolean;
20
+ } & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | ({
21
+ createFacilitySpecificSlurryProduct: boolean;
22
+ } & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | ({
23
+ slurrySupplyProportionStored: number | null;
24
+ slurryTankQuantity: number | null;
25
+ dilutionRatio: number | null;
26
+ } & import("../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
27
+ onDataChange(event: unknown): void;
28
+ }
29
+ export {};
@@ -0,0 +1,23 @@
1
+ import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from './storage.types';
2
+ export declare class StorageListComponent {
3
+ private readonly i18n;
4
+ private readonly masterData;
5
+ readonly rows: import("@angular/core").InputSignal<(ManurePitEntry | SlurryTankEntry)[]>;
6
+ readonly selectedIndex: import("@angular/core").InputSignal<number | null>;
7
+ readonly type: import("@angular/core").InputSignal<StorageEntryType>;
8
+ readonly errorIndices: import("@angular/core").InputSignal<ReadonlySet<number>>;
9
+ readonly select: import("@angular/core").OutputEmitterRef<number>;
10
+ readonly add: import("@angular/core").OutputEmitterRef<void>;
11
+ readonly delete: import("@angular/core").OutputEmitterRef<number>;
12
+ readonly displayedColumns: string[];
13
+ readonly headerName: import("@angular/core").Signal<string>;
14
+ readonly headerMeta: import("@angular/core").Signal<string>;
15
+ resolveName(row: ManurePitEntry | SlurryTankEntry, index: number): string;
16
+ rowHasError(index: number): boolean;
17
+ rowErrorLabel(): string;
18
+ resolveMeta(row: ManurePitEntry | SlurryTankEntry): string;
19
+ emptyLabel(): string;
20
+ emptyHintLabel(): string;
21
+ addLabel(): string;
22
+ onDelete(index: number, event: Event): void;
23
+ }
@@ -0,0 +1,32 @@
1
+ import { StorageTab } from '../../core/navigation/navigation.service';
2
+ import { ManurePitEntry, SlurryTankEntry, StorageEntryType, StorageNormalized } from './storage.types';
3
+ export declare class StorageMasterDetailComponent {
4
+ private readonly dataSvc;
5
+ private readonly navigationSvc;
6
+ private readonly globalValidation;
7
+ constructor();
8
+ readonly storage: import("@angular/core").Signal<StorageNormalized>;
9
+ readonly manurePitRows: import("@angular/core").Signal<ManurePitEntry[]>;
10
+ readonly slurryTankRows: import("@angular/core").Signal<SlurryTankEntry[]>;
11
+ readonly selectedDetailType: import("@angular/core").WritableSignal<StorageEntryType | null>;
12
+ readonly selectedIndex: import("@angular/core").WritableSignal<number | null>;
13
+ readonly manureFacilitySpecificEnabled: import("@angular/core").Signal<boolean>;
14
+ readonly slurryFacilitySpecificEnabled: import("@angular/core").Signal<boolean>;
15
+ readonly manurePitErrorIndices: import("@angular/core").Signal<Set<number>>;
16
+ readonly slurryTankErrorIndices: import("@angular/core").Signal<Set<number>>;
17
+ readonly detailOpen: import("@angular/core").Signal<boolean>;
18
+ readonly detailType: import("@angular/core").Signal<StorageEntryType>;
19
+ readonly currentDetail: import("@angular/core").Signal<ManurePitEntry | SlurryTankEntry | null>;
20
+ readonly activeTab: import("@angular/core").Signal<StorageTab>;
21
+ openDetail(type: StorageEntryType, index: number): void;
22
+ closeDetail(): void;
23
+ addEntry(type: StorageEntryType): void;
24
+ deleteEntry(type: StorageEntryType, index: number): void;
25
+ onGeneralChange(value: StorageNormalized): void;
26
+ onDetailChange(value: ManurePitEntry | SlurryTankEntry): void;
27
+ private patchRows;
28
+ private patchStorage;
29
+ private normalizeStorage;
30
+ private createEmptyManurePit;
31
+ private createEmptySlurryTank;
32
+ }
@@ -0,0 +1,40 @@
1
+ export interface ManureFromAnimalStockStored {
2
+ manureDerivation?: string;
3
+ proportionStored?: number | null;
4
+ }
5
+ export interface ManurePitEntry {
6
+ descriptor?: string;
7
+ cover?: number | null;
8
+ manureFromAnimalStockStored?: ManureFromAnimalStockStored[];
9
+ }
10
+ export interface SlurryTankEntry {
11
+ descriptor?: string;
12
+ volumeInM3?: number | null;
13
+ depthInM?: number | null;
14
+ cover?: number | null;
15
+ mixingFrequency?: number | null;
16
+ manureDerivation?: string[];
17
+ }
18
+ export interface StorageData {
19
+ stableStrawLitter?: number | null;
20
+ manureSupplyProportionStored?: number | null;
21
+ slurrySupplyProportionStored?: number | null;
22
+ createFacilitySpecificManureProduct?: boolean;
23
+ createFacilitySpecificSlurryProduct?: boolean;
24
+ slurryTankQuantity?: number | null;
25
+ dilutionRatio?: number | null;
26
+ manurePit?: ManurePitEntry[];
27
+ slurryTank?: SlurryTankEntry[];
28
+ }
29
+ export interface StorageNormalized {
30
+ stableStrawLitter: number | null;
31
+ manureSupplyProportionStored: number | null;
32
+ slurrySupplyProportionStored: number | null;
33
+ createFacilitySpecificManureProduct: boolean;
34
+ createFacilitySpecificSlurryProduct: boolean;
35
+ slurryTankQuantity: number | null;
36
+ dilutionRatio: number | null;
37
+ manurePit: ManurePitEntry[];
38
+ slurryTank: SlurryTankEntry[];
39
+ }
40
+ export type StorageEntryType = 'manure_pit' | 'slurry_tank';
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Ensure the Material Icons stylesheet exists in the document <head> (SPA / non-shadow usage).
2
+ * Ensure the Material icon stylesheets exist in the document <head> (SPA / non-shadow usage).
3
3
  * Idempotent: returns immediately if DOM unavailable (SSR) or link already present.
4
4
  *
5
5
  * @param doc Optional document for testing / dependency injection.
6
6
  */
7
7
  export declare function ensureMaterialIconsInHead(doc?: Document): void;
8
8
  /**
9
- * Ensure the Material Icons stylesheet is available inside a ShadowRoot so that
9
+ * Ensure the Material icon stylesheets are available inside a ShadowRoot so that
10
10
  * icon ligatures render when the component is embedded as a Web Component.
11
11
  * We prepend so icons load early without disturbing existing adopted stylesheets.
12
- * Idempotent: guarded by a custom attribute selector.
12
+ * Idempotent: each font link is guarded by its own custom attribute selector.
13
13
  *
14
14
  * @param shadow Target ShadowRoot; silently no-ops if null/undefined or DOM unavailable.
15
15
  */