@agridea/suibi-module 0.1.0-preview.9159a63 → 0.1.0-preview.ae6b6f9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/elements/browser/main.js +70 -70
- package/dist/elements/browser/suibi-module-latest.js +70 -70
- package/dist/elements/browser/suibi-module.v0.1.0-preview.ae6b6f9.js +78 -0
- package/dist/elements/browser/version.txt +1 -1
- package/dist/types/app/components/inline-table/inline-table.component.d.ts +60 -3
- package/dist/types/app/components/inline-table/inline-table.types.d.ts +87 -2
- package/dist/types/app/components/suissebilanz-dashboard/suissebilanz-dashboard.component.d.ts +2 -0
- package/dist/types/app/core/i18n/i18n.service.d.ts +1 -0
- package/dist/types/app/core/metadata/suibi-metadata.types.d.ts +1 -1
- package/dist/types/app/core/navigation/navigation.service.d.ts +7 -0
- package/dist/types/app/core/planning/planning-balance.service.d.ts +1 -0
- package/dist/types/app/core/utils/object.util.d.ts +26 -0
- package/dist/types/app/core/validation/ajv-custom.d.ts +1 -0
- package/dist/types/app/core/validation/global-validation.service.d.ts +2 -0
- package/dist/types/app/jsonforms/renderers/layout/group/module-toggle-group.renderer.d.ts +3 -1
- package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-detail.component.d.ts → animal-stock-detail/animal-stock-detail.component.d.ts} +2 -2
- package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-list.component.d.ts → animal-stock-list/animal-stock-list.component.d.ts} +1 -1
- package/dist/types/app/nutrient-cycle/animal-stock/{animal-stock-master-detail.component.d.ts → animal-stock-master-detail/animal-stock-master-detail.component.d.ts} +2 -2
- package/dist/types/app/nutrient-cycle/animal-stock/index.d.ts +3 -3
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail/farm-manure-trading-master-detail.component.d.ts +19 -0
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.component.d.ts +34 -0
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-table/farm-manure-trading-table.config.d.ts +24 -0
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading.types.d.ts +4 -0
- package/dist/types/app/nutrient-cycle/farm-manure-trading/index.d.ts +3 -3
- package/dist/types/app/nutrient-cycle/farm-manure-trading/transaction-unit.util.d.ts +2 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.component.d.ts +22 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/arable-land-table/arable-land-table.config.d.ts +9 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.component.d.ts +21 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/crop-harvest-table/crop-harvest-table.config.d.ts +13 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/{field-cultivation-detail.component.d.ts → field-cultivation-detail/field-cultivation-detail.component.d.ts} +2 -2
- package/dist/types/app/nutrient-cycle/field-cultivation/{field-cultivation-general.component.d.ts → field-cultivation-general/field-cultivation-general.component.d.ts} +2 -4
- package/dist/types/app/nutrient-cycle/field-cultivation/{field-cultivation-list.component.d.ts → field-cultivation-list/field-cultivation-list.component.d.ts} +1 -1
- package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail/field-cultivation-master-detail.component.d.ts +29 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation.types.d.ts +1 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.component.d.ts +28 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/fodder-cropland-table/fodder-cropland-table.config.d.ts +16 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/index.d.ts +8 -3
- package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.component.d.ts +29 -0
- package/dist/types/app/nutrient-cycle/field-cultivation/special-crops-table/special-crops-table.config.d.ts +50 -0
- package/dist/types/app/nutrient-cycle/field-spreading/fertiliser-table/fertiliser-table.component.d.ts +18 -1
- package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.component.d.ts +2 -0
- package/dist/types/app/nutrient-cycle/field-spreading/field-spreading.types.d.ts +1 -0
- package/dist/types/app/nutrient-cycle/field-spreading/ingredient.util.d.ts +8 -0
- package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts +13 -4
- package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts +4 -3
- package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-transaction-unit.util.d.ts +4 -0
- package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail/fodder-master-detail.component.d.ts +25 -0
- package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.component.d.ts +26 -0
- package/dist/types/app/nutrient-cycle/fodder/fodder-table/fodder-table.config.d.ts +9 -0
- package/dist/types/app/nutrient-cycle/fodder/fodder.types.d.ts +7 -0
- package/dist/types/app/nutrient-cycle/fodder/index.d.ts +2 -3
- package/dist/types/app/nutrient-cycle/fodder/ingredient.util.d.ts +8 -0
- package/dist/types/app/nutrient-cycle/storage/index.d.ts +3 -3
- package/dist/types/app/nutrient-cycle/storage/{storage-detail.component.d.ts → storage-detail/storage-detail.component.d.ts} +3 -3
- package/dist/types/app/nutrient-cycle/storage/{storage-general.component.d.ts → storage-general/storage-general.component.d.ts} +4 -4
- package/dist/types/app/nutrient-cycle/storage/{storage-list.component.d.ts → storage-list/storage-list.component.d.ts} +4 -1
- package/dist/types/app/nutrient-cycle/storage/{storage-master-detail.component.d.ts → storage-master-detail/storage-master-detail.component.d.ts} +5 -2
- package/package.json +1 -1
- package/dist/elements/browser/suibi-module.v0.1.0-preview.9159a63.js +0 -78
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-detail.component.d.ts +0 -26
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-list.component.d.ts +0 -22
- package/dist/types/app/nutrient-cycle/farm-manure-trading/farm-manure-trading-master-detail.component.d.ts +0 -25
- package/dist/types/app/nutrient-cycle/field-cultivation/field-cultivation-master-detail.component.d.ts +0 -37
- package/dist/types/app/nutrient-cycle/fodder/fodder-detail.component.d.ts +0 -31
- package/dist/types/app/nutrient-cycle/fodder/fodder-list.component.d.ts +0 -20
- package/dist/types/app/nutrient-cycle/fodder/fodder-master-detail.component.d.ts +0 -37
- /package/dist/elements/browser/{suibi-module.v0.1.0-preview.9159a63.css → suibi-module.v0.1.0-preview.ae6b6f9.css} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FieldCultivationDetailEntry, FieldCultivationDetailMode } from '
|
|
1
|
+
import { FieldCultivationDetailEntry, FieldCultivationDetailMode } from '../field-cultivation.types';
|
|
2
2
|
export declare class FieldCultivationListComponent {
|
|
3
3
|
private readonly masterData;
|
|
4
4
|
private readonly i18n;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FieldCultivationTab } from '../../../core/navigation/navigation.service';
|
|
2
|
+
import { CropHarvestTableKind } from '../crop-harvest-table/crop-harvest-table.config';
|
|
3
|
+
import { FieldCultivationArableLand, FieldCultivationCropHarvest, FieldCultivationData, FieldCultivationFodderCropland, FieldCultivationSpecial } from '../field-cultivation.types';
|
|
4
|
+
export declare class FieldCultivationMasterDetailComponent {
|
|
5
|
+
private readonly dataSvc;
|
|
6
|
+
private readonly navigationSvc;
|
|
7
|
+
constructor();
|
|
8
|
+
readonly fieldCultivation: import("@angular/core").Signal<FieldCultivationData>;
|
|
9
|
+
readonly fodderCroplandRows: import("@angular/core").Signal<FieldCultivationFodderCropland[]>;
|
|
10
|
+
readonly arableLandRows: import("@angular/core").Signal<FieldCultivationArableLand[]>;
|
|
11
|
+
readonly specialRows: import("@angular/core").Signal<FieldCultivationSpecial[]>;
|
|
12
|
+
readonly feedingRows: import("@angular/core").Signal<FieldCultivationCropHarvest[]>;
|
|
13
|
+
readonly dispenseRows: import("@angular/core").Signal<FieldCultivationCropHarvest[]>;
|
|
14
|
+
readonly activeTab: import("@angular/core").WritableSignal<FieldCultivationTab>;
|
|
15
|
+
readonly activeTabIndex: import("@angular/core").Signal<0 | 1 | 2 | 3>;
|
|
16
|
+
onTabChange(index: number): void;
|
|
17
|
+
onGeneralChange(value: FieldCultivationData): void;
|
|
18
|
+
/** Persists one crop-harvest table's rows (fed / dispensed harvests of the general tab). */
|
|
19
|
+
onCropHarvestRowsChange(kind: CropHarvestTableKind, rows: FieldCultivationCropHarvest[]): void;
|
|
20
|
+
/** Persists the fodder-cropland rows produced by the inline table (edit / add / delete). */
|
|
21
|
+
onFodderCroplandRowsChange(rows: FieldCultivationFodderCropland[]): void;
|
|
22
|
+
/** Persists the arable-land rows produced by the inline table (edit / add / delete). */
|
|
23
|
+
onArableRowsChange(rows: FieldCultivationArableLand[]): void;
|
|
24
|
+
/** Persists the special-crops rows produced by the inline table (edit / add / delete). */
|
|
25
|
+
onSpecialRowsChange(rows: FieldCultivationSpecial[]): void;
|
|
26
|
+
private patchRows;
|
|
27
|
+
private patchFieldCultivation;
|
|
28
|
+
private parseTab;
|
|
29
|
+
}
|
|
@@ -18,6 +18,7 @@ export interface FieldCultivationBaseEntry {
|
|
|
18
18
|
export interface FieldCultivationFodderCropland extends FieldCultivationBaseEntry {
|
|
19
19
|
fieldName?: string | null;
|
|
20
20
|
calculateYieldThroughFodderBalance?: boolean;
|
|
21
|
+
requirementCorrection?: FieldCultivationRequirementCorrection[];
|
|
21
22
|
}
|
|
22
23
|
export interface FieldCultivationArableLand extends FieldCultivationBaseEntry {
|
|
23
24
|
hasLongTermYieldDivergence?: boolean;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FieldCultivationFodderCropland } from '../field-cultivation.types';
|
|
2
|
+
/**
|
|
3
|
+
* FodderCroplandTableComponent — thin wrapper around InlineTableComponent for the
|
|
4
|
+
* "Surface fourragère" tab: entries are edited directly in the table (no detail pane).
|
|
5
|
+
*
|
|
6
|
+
* Rows without a selected crop (freshly added) exist only in the local `uiRows`
|
|
7
|
+
* state and are emitted upstream once a crop is picked, so no empty rows ever
|
|
8
|
+
* reach the data store (fodder `uiRows` pattern). The rowTransform clears the
|
|
9
|
+
* yield whenever it is not user-editable for the row.
|
|
10
|
+
*/
|
|
11
|
+
export declare class FodderCroplandTableComponent {
|
|
12
|
+
readonly entries: import("@angular/core").InputSignal<FieldCultivationFodderCropland[]>;
|
|
13
|
+
readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationFodderCropland[]>;
|
|
14
|
+
/** Column/section config (constant — no signal needed). */
|
|
15
|
+
protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
|
|
16
|
+
/** Rows as last edited locally (may contain not-yet-committed empty rows); null = follow data. */
|
|
17
|
+
private readonly uiRows;
|
|
18
|
+
readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
|
|
19
|
+
constructor();
|
|
20
|
+
onRowsChange(rows: Record<string, unknown>[]): void;
|
|
21
|
+
/**
|
|
22
|
+
* Clears the yield whenever it stops being user-editable for the row (fodder-balance
|
|
23
|
+
* calculation switched on, or new crop without yield input), so no stale value
|
|
24
|
+
* lingers under the now-disabled cell. Requirement corrections are special-crops-only
|
|
25
|
+
* (SUIBIL-1143): strip them so they never reach the emitted JSON.
|
|
26
|
+
*/
|
|
27
|
+
readonly enforceFodderCroplandRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column and section configuration for the fodder-cropland inline table
|
|
3
|
+
* ("Surface fourragère" tab).
|
|
4
|
+
*
|
|
5
|
+
* Replaces the former list + JSONForms detail pane: entries are edited directly
|
|
6
|
+
* in the table. `userSpecificPlantName` and `fieldName` stay in the data model
|
|
7
|
+
* (filled by imports/API) but are no longer editable in the UI.
|
|
8
|
+
*/
|
|
9
|
+
import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
|
|
10
|
+
/**
|
|
11
|
+
* Yield is user-editable only when the selected crop permits yield input AND the
|
|
12
|
+
* yield is not calculated through the fodder balance — mirrors the former
|
|
13
|
+
* `fieldCultivation_shouldShowYieldInput` constraint of the detail form.
|
|
14
|
+
*/
|
|
15
|
+
export declare function yieldNotEditable(row: Record<string, unknown>): boolean;
|
|
16
|
+
export declare const FODDER_CROPLAND_TABLE_CONFIG: InlineTableConfig;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export * from './field-cultivation-list.component';
|
|
2
|
-
export * from './field-cultivation-detail.component';
|
|
3
|
-
export * from './field-cultivation-
|
|
1
|
+
export * from './field-cultivation-list/field-cultivation-list.component';
|
|
2
|
+
export * from './field-cultivation-detail/field-cultivation-detail.component';
|
|
3
|
+
export * from './field-cultivation-general/field-cultivation-general.component';
|
|
4
|
+
export * from './field-cultivation-master-detail/field-cultivation-master-detail.component';
|
|
5
|
+
export * from './crop-harvest-table/crop-harvest-table.component';
|
|
6
|
+
export * from './fodder-cropland-table/fodder-cropland-table.component';
|
|
7
|
+
export * from './arable-land-table/arable-land-table.component';
|
|
8
|
+
export * from './special-crops-table/special-crops-table.component';
|
|
4
9
|
export * from './field-cultivation.types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FieldCultivationSpecial } from '../field-cultivation.types';
|
|
2
|
+
/**
|
|
3
|
+
* SpecialCropsTableComponent — thin wrapper around InlineTableComponent for the
|
|
4
|
+
* "Cultures spéciales" tab: one table for the whole CULT_SPECIAL category.
|
|
5
|
+
*
|
|
6
|
+
* Rows without a selected crop (freshly added) exist only in the local `uiRows`
|
|
7
|
+
* state and are emitted upstream once a crop is picked, so no empty rows ever
|
|
8
|
+
* reach the data store (fodder `uiRows` pattern).
|
|
9
|
+
*/
|
|
10
|
+
export declare class SpecialCropsTableComponent {
|
|
11
|
+
readonly entries: import("@angular/core").InputSignal<FieldCultivationSpecial[]>;
|
|
12
|
+
readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldCultivationSpecial[]>;
|
|
13
|
+
/** Column/section config (constant — no signal needed). */
|
|
14
|
+
protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
|
|
15
|
+
/** Rows as last edited locally (may contain not-yet-committed empty rows); null = follow data. */
|
|
16
|
+
private readonly uiRows;
|
|
17
|
+
readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
|
|
18
|
+
constructor();
|
|
19
|
+
onRowsChange(rows: Record<string, unknown>[]): void;
|
|
20
|
+
/**
|
|
21
|
+
* Domain rules applied on every edit:
|
|
22
|
+
* - units of the managed nutrient slots are fixed (N2 in kg, corrections in %),
|
|
23
|
+
* - managed slots left empty are dropped (the API rejects null quantities),
|
|
24
|
+
* - selecting a crop pre-fills Nmin from its standard N2 requirement and resets the
|
|
25
|
+
* corrections to 100 %; clearing the crop (or picking one that forbids corrections)
|
|
26
|
+
* removes the managed slots.
|
|
27
|
+
*/
|
|
28
|
+
readonly enforceSpecialCropRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column and section configuration for the special-crops inline table
|
|
3
|
+
* ("Cultures spéciales" tab).
|
|
4
|
+
*
|
|
5
|
+
* ONE table for the whole CULT_SPECIAL category: the crop dropdown reuses the
|
|
6
|
+
* `agronomicCropCategorySpecial` code list, which is already filtered on
|
|
7
|
+
* cultivationCategory === 'CULT_SPECIAL'. Nutrient columns live in the row's
|
|
8
|
+
* `requirementCorrection[]` sub-array: Nmin is the N2 slot in kg, the three
|
|
9
|
+
* corrections are the P2O5/K2O/Mg slots in %.
|
|
10
|
+
*/
|
|
11
|
+
import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
|
|
12
|
+
/** Nmin maps to the N2 requirement-correction slot, always expressed in kg. */
|
|
13
|
+
export declare const NMIN_FORMULA = "N2";
|
|
14
|
+
export declare const NMIN_UNIT = "kg";
|
|
15
|
+
/** Correction slots managed by the table, always expressed in % (100 % = no correction). */
|
|
16
|
+
export declare const CORRECTION_FORMULAS: readonly ["P2O5", "K2O", "Mg"];
|
|
17
|
+
export declare const CORRECTION_UNIT = "%";
|
|
18
|
+
export declare const CORRECTION_DEFAULT = 100;
|
|
19
|
+
/** Code list feeding the crop dropdown — the whole CULT_SPECIAL category. */
|
|
20
|
+
export declare const SPECIAL_CROPS_CODE_LIST = "agronomicCropCategorySpecial";
|
|
21
|
+
/** Crop ids permitted in the table — every CULT_SPECIAL entry of the master data. */
|
|
22
|
+
export declare const SPECIAL_CROPS_IDS: Set<string>;
|
|
23
|
+
/** Looks up a crop entry in the table's code list. */
|
|
24
|
+
export declare function specialCropEntry(id: unknown): Record<string, unknown> | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Nutrient columns are read-only unless the selected crop has the
|
|
27
|
+
* `isPermittedForRequirementCorrection` flag: without it, the pre-filled Nmin and
|
|
28
|
+
* correction values are fixed defaults from master data and must not be user-editable.
|
|
29
|
+
*/
|
|
30
|
+
export declare function nutrientColumnsLocked(crop: Record<string, unknown> | undefined): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Applies the crop's defaults to the requirement-correction slots.
|
|
33
|
+
* - If the crop does NOT permit requirement corrections (or none is selected): the
|
|
34
|
+
* managed slots are removed entirely — nothing is editable and nothing is sent to the API.
|
|
35
|
+
* - If the crop DOES permit them: the managed slots are pre-filled from the crop's
|
|
36
|
+
* master-data `requirement` (N2 in kg; P2O5/K2O/Mg in %) and stay user-editable.
|
|
37
|
+
*/
|
|
38
|
+
export declare function applyCropDefaults(row: Record<string, unknown>, crop: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Normalizes the managed requirement-correction slots on every edit: fixed units
|
|
41
|
+
* (N2 → kg, corrections → %) and removal of managed entries left without a quantity
|
|
42
|
+
* (the API rejects present-but-null quantities).
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeManagedCorrections(row: Record<string, unknown>): Record<string, unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Shared column definitions for the requirement-correction sub-array (Nmin + P2O5/K2O/Mg),
|
|
47
|
+
* reusable across fodder, arable and special tables. `lockRow` disables editing per row.
|
|
48
|
+
*/
|
|
49
|
+
export declare function requirementCorrectionColumns(lockRow: (row: Record<string, unknown>) => boolean): InlineTableConfig['columns'];
|
|
50
|
+
export declare const SPECIAL_CROPS_TABLE_CONFIG: InlineTableConfig;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { InlineColumnDef } from '../../../components/inline-table/inline-table.types';
|
|
1
2
|
import { FieldSpreadingFertiliserEntry } from '../field-spreading.types';
|
|
2
3
|
/**
|
|
3
4
|
* FertiliserTableComponent — thin wrapper around InlineTableComponent.
|
|
@@ -17,17 +18,25 @@ import { FieldSpreadingFertiliserEntry } from '../field-spreading.types';
|
|
|
17
18
|
* 3. The generic InlineTableComponent requires no changes.
|
|
18
19
|
*/
|
|
19
20
|
export declare class FertiliserTableComponent {
|
|
21
|
+
private readonly i18n;
|
|
20
22
|
readonly entries: import("@angular/core").InputSignal<FieldSpreadingFertiliserEntry[]>;
|
|
21
23
|
readonly entriesChange: import("@angular/core").OutputEmitterRef<FieldSpreadingFertiliserEntry[]>;
|
|
24
|
+
/** Row index to highlight after a validation-error deep-link (forwarded to the table). */
|
|
25
|
+
readonly highlightRowIndex: import("@angular/core").InputSignal<number | null>;
|
|
22
26
|
/** Column/section config exposed to the template (constant — no signal needed). */
|
|
23
27
|
protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
|
|
24
28
|
/** Cast typed entries to the generic Record[] expected by InlineTableComponent. */
|
|
25
29
|
readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
|
|
26
|
-
/** Cast the generic output back to the typed FieldSpreadingFertiliserEntry[]
|
|
30
|
+
/** Cast the generic output back to the typed FieldSpreadingFertiliserEntry[], stripping any
|
|
31
|
+
* ingredient with a 0 quantity so it never reaches the final JSON. */
|
|
27
32
|
onRowsChange(rows: Record<string, unknown>[]): void;
|
|
28
33
|
/**
|
|
29
34
|
* Row transform for auto-populating nutrient columns when a product is selected.
|
|
30
35
|
*
|
|
36
|
+
* Also imposes `transactionUnit = 'kg'` on every edit (not just product changes) so
|
|
37
|
+
* stale/imported rows with a different or null unit get corrected once touched —
|
|
38
|
+
* `createRow` already defaults new rows to 'kg', this is only a safety net.
|
|
39
|
+
*
|
|
31
40
|
* Defined as an arrow-function property so `this` is never needed and the function
|
|
32
41
|
* can be passed as a value to InlineTableComponent without losing its context.
|
|
33
42
|
*
|
|
@@ -35,4 +44,12 @@ export declare class FertiliserTableComponent {
|
|
|
35
44
|
* edits pass through unchanged.
|
|
36
45
|
*/
|
|
37
46
|
readonly autoPopulateNutrients: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Per-cell validation for the nutrient % columns: each value capped at 100 %
|
|
49
|
+
* and the sum of the four ingredients capped at 100 % per row.
|
|
50
|
+
* The inline table bypasses JSONForms/AJV, so these rules (mirroring the
|
|
51
|
+
* `maximum` / `proportionSum` keywords in schema.json) must be surfaced
|
|
52
|
+
* visually here — the global validation panel alone is not visible while typing.
|
|
53
|
+
*/
|
|
54
|
+
readonly nutrientCellError: (row: Record<string, unknown>, col: InlineColumnDef) => string | null;
|
|
38
55
|
}
|
|
@@ -5,6 +5,8 @@ export declare class FieldSpreadingComponent {
|
|
|
5
5
|
private readonly navigationSvc;
|
|
6
6
|
private readonly i18n;
|
|
7
7
|
constructor();
|
|
8
|
+
/** Fertiliser row to highlight (set by validation deep-links, cleared by the next one). */
|
|
9
|
+
readonly highlightedFertiliserIndex: import("@angular/core").WritableSignal<number | null>;
|
|
8
10
|
readonly schema: import("@angular/core").Signal<JsonSchema>;
|
|
9
11
|
readonly localizedGeneralUi: import("@angular/core").Signal<import("@jsonforms/core").UISchemaElement>;
|
|
10
12
|
readonly renderers: {
|
|
@@ -23,6 +23,7 @@ export interface FieldSpreadingIngredient {
|
|
|
23
23
|
unit?: string | null;
|
|
24
24
|
}
|
|
25
25
|
export interface FieldSpreadingFertiliserEntry {
|
|
26
|
+
descriptor?: string | null;
|
|
26
27
|
fertiliserProductCategory?: string | null;
|
|
27
28
|
quantity?: number | null;
|
|
28
29
|
transactionUnit?: string | null;
|
|
@@ -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[];
|
package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.component.d.ts
CHANGED
|
@@ -6,9 +6,10 @@ import { FieldSpreadingRecyclingEntry } from '../field-spreading.types';
|
|
|
6
6
|
* 1. Provides `RECYCLING_TABLE_CONFIG` (the column/section "uischema").
|
|
7
7
|
* 2. Bridges typed `FieldSpreadingRecyclingEntry[]` to/from the generic
|
|
8
8
|
* `Record<string, unknown>[]` API of InlineTableComponent.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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).
|
|
12
13
|
*/
|
|
13
14
|
export declare class RecyclingTableComponent {
|
|
14
15
|
readonly entries: import("@angular/core").InputSignal<FieldSpreadingRecyclingEntry[]>;
|
|
@@ -17,6 +18,14 @@ export declare class RecyclingTableComponent {
|
|
|
17
18
|
protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
|
|
18
19
|
/** Cast typed entries to generic Record[] for InlineTableComponent. */
|
|
19
20
|
readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
|
|
20
|
-
/** Cast generic output back to typed FieldSpreadingRecyclingEntry[]
|
|
21
|
+
/** Cast generic output back to typed FieldSpreadingRecyclingEntry[], stripping any
|
|
22
|
+
* ingredient with a 0 quantity so it never reaches the final JSON. */
|
|
21
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>;
|
|
22
31
|
}
|
package/dist/types/app/nutrient-cycle/field-spreading/recycling-table/recycling-table.config.d.ts
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* This is the "uischema" for the Recycling fertilisers tab.
|
|
5
5
|
* The structure mirrors fertiliser-table.config.ts — only the columns differ:
|
|
6
6
|
* - Product field: typeOfManureRecyclingProduct (different code list)
|
|
7
|
-
* - Nutrient columns: Ntot,
|
|
7
|
+
* - Nutrient columns: Ntot, Nlos, P₂O₅, K₂O, Mg expressed in kg/unit (not %)
|
|
8
8
|
* — 5 nutrients vs 4 for mineral fertilisers, no auto-population on product select.
|
|
9
9
|
*
|
|
10
10
|
* To adapt again for a new domain, copy this file and adjust columns + i18n keys.
|
|
11
11
|
*/
|
|
12
12
|
import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
|
|
13
|
-
/** Nutrient formulas tracked per recycling entry, in display order.
|
|
14
|
-
|
|
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"];
|
|
15
16
|
export type RecyclingNutrientFormula = (typeof RECYCLING_NUTRIENT_COLUMNS)[number];
|
|
16
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,25 @@
|
|
|
1
|
+
import { FodderCropFromNonFodderCropland, FodderDispense, FodderSupply, FodderTableRow } from '../fodder.types';
|
|
2
|
+
export declare class FodderMasterDetailComponent {
|
|
3
|
+
private readonly dataSvc;
|
|
4
|
+
private readonly navigationSvc;
|
|
5
|
+
constructor();
|
|
6
|
+
readonly supplyRows: import("@angular/core").Signal<FodderSupply[]>;
|
|
7
|
+
readonly dispenseRows: import("@angular/core").Signal<FodderDispense[]>;
|
|
8
|
+
readonly nonFodderCroplandRows: import("@angular/core").Signal<FodderCropFromNonFodderCropland[]>;
|
|
9
|
+
readonly proportionStorageLoss: import("@angular/core").Signal<number | undefined>;
|
|
10
|
+
readonly totalBalanceErrorMargin: import("@angular/core").Signal<number | undefined>;
|
|
11
|
+
/** Rows in the order last produced by the table (local UI order); null = follow the data. */
|
|
12
|
+
private readonly uiRows;
|
|
13
|
+
/** Data-derived merged list: supply block, then dispense, then non-fodder cropland. */
|
|
14
|
+
private readonly dataRows;
|
|
15
|
+
/** Rows shown in the table. The local UI order wins so that adding a row or changing its
|
|
16
|
+
* type never reshuffles the list under the user's hands. */
|
|
17
|
+
readonly rows: import("@angular/core").Signal<FodderTableRow[]>;
|
|
18
|
+
/** Persists the edited rows (split back into their three collections) while keeping the
|
|
19
|
+
* emitted order as the local UI order. */
|
|
20
|
+
onRowsChange(rows: FodderTableRow[]): void;
|
|
21
|
+
onScalarInput(field: 'proportionStorageLoss' | 'totalBalanceErrorMargin', event: Event): void;
|
|
22
|
+
scalarInputValue(value: number | undefined): string;
|
|
23
|
+
private cloneFodder;
|
|
24
|
+
private cloneTrading;
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FodderTableRow } from '../fodder.types';
|
|
2
|
+
/**
|
|
3
|
+
* FodderTableComponent — thin wrapper around InlineTableComponent for the merged fodder table
|
|
4
|
+
* (supply / dispense / non-fodder cropland in one table, distinguished per row via `rowKind`).
|
|
5
|
+
* The config provides the columns; the rowTransform imposes the fixed units (transactionUnit
|
|
6
|
+
* 'kg', dry-matter ingredient T/S in '%') and keeps the product compatible with the row kind.
|
|
7
|
+
*/
|
|
8
|
+
export declare class FodderTableComponent {
|
|
9
|
+
readonly entries: import("@angular/core").InputSignal<FodderTableRow[]>;
|
|
10
|
+
readonly entriesChange: import("@angular/core").OutputEmitterRef<FodderTableRow[]>;
|
|
11
|
+
/** Column/section config (constant — no signal needed). */
|
|
12
|
+
protected readonly config: import("../../../components/inline-table/inline-table.types").InlineTableConfig;
|
|
13
|
+
/** Cast typed entries to the generic Record[] expected by InlineTableComponent. */
|
|
14
|
+
readonly rowsForTable: import("@angular/core").Signal<Record<string, unknown>[]>;
|
|
15
|
+
onRowsChange(rows: Record<string, unknown>[]): void;
|
|
16
|
+
/**
|
|
17
|
+
* Domain rules applied on every edit:
|
|
18
|
+
* - `rowKind` change: normalize unknown/cleared values to 'supply' and clear the product
|
|
19
|
+
* when it is not permitted for the new kind.
|
|
20
|
+
* - Product change: pre-fill the dry matter share (T/S %) with the product's
|
|
21
|
+
* `standardDryMatterContent` (stays editable afterwards; null when none is defined).
|
|
22
|
+
* - Units are fixed, never user-entered: quantity is always transacted in kg and the only
|
|
23
|
+
* permitted ingredient is dry matter (T/S) expressed in % — re-appended when missing.
|
|
24
|
+
*/
|
|
25
|
+
readonly enforceFodderRules: (changedKey: string, newValue: unknown, row: Record<string, unknown>) => Record<string, unknown>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column and section configuration for the single fodder inline table.
|
|
3
|
+
*
|
|
4
|
+
* The three former mode tabs (supply / dispense / non-fodder cropland) are merged into one
|
|
5
|
+
* table: each row picks its kind via the `rowKind` select column, and the product dropdown
|
|
6
|
+
* is narrowed per row to the products permitted for that kind.
|
|
7
|
+
*/
|
|
8
|
+
import type { InlineTableConfig } from '../../../components/inline-table/inline-table.types';
|
|
9
|
+
export declare const FODDER_TABLE_CONFIG: InlineTableConfig;
|
|
@@ -25,3 +25,10 @@ export interface FodderData {
|
|
|
25
25
|
proportionStorageLoss?: number;
|
|
26
26
|
totalBalanceErrorMargin?: number;
|
|
27
27
|
}
|
|
28
|
+
/** UI-only discriminator telling which fodder collection a table row belongs to. */
|
|
29
|
+
export type FodderRowKind = 'supply' | 'dispense' | 'non_fodder_cropland';
|
|
30
|
+
/** Row shape used by the inline fodder table: a trading entry tagged with its row kind.
|
|
31
|
+
* `rowKind` is stripped again when the rows are written back to the data model. */
|
|
32
|
+
export type FodderTableRow = FodderTradingEntry & {
|
|
33
|
+
rowKind: FodderRowKind;
|
|
34
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export * from './fodder-
|
|
2
|
-
export * from './fodder-detail.component';
|
|
3
|
-
export * from './fodder-master-detail.component';
|
|
1
|
+
export * from './fodder-table/fodder-table.component';
|
|
2
|
+
export * from './fodder-master-detail/fodder-master-detail.component';
|
|
4
3
|
export * from './fodder.types';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dry matter (Trockensubstanz, T/S) is the only ingredient formula permitted for fodder
|
|
3
|
+
* entries (see `fodderMolecularFormula` in code-lists.ts) and its only allowed unit is '%'
|
|
4
|
+
* (assets/master-data/substances.json → S.1007.1). Both are imposed, never user-picked.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FODDER_INGREDIENT_FORMULA = "T/S";
|
|
7
|
+
export declare const FODDER_INGREDIENT_UNIT = "%";
|
|
8
|
+
export declare function deriveFodderIngredientUnit(): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './storage-list.component';
|
|
2
|
-
export * from './storage-detail.component';
|
|
3
|
-
export * from './storage-master-detail.component';
|
|
1
|
+
export * from './storage-list/storage-list.component';
|
|
2
|
+
export * from './storage-detail/storage-detail.component';
|
|
3
|
+
export * from './storage-master-detail/storage-master-detail.component';
|
|
4
4
|
export * from './storage.types';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JsonSchema, UISchemaElement } from '@jsonforms/core';
|
|
2
|
-
import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from '
|
|
2
|
+
import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from '../storage.types';
|
|
3
3
|
export declare class StorageDetailComponent {
|
|
4
4
|
private readonly i18n;
|
|
5
5
|
readonly type: import("@angular/core").InputSignal<StorageEntryType>;
|
|
@@ -17,7 +17,7 @@ export declare class StorageDetailComponent {
|
|
|
17
17
|
readonly jsonFormsData: import("@angular/core").Signal<(({
|
|
18
18
|
descriptor?: string;
|
|
19
19
|
cover?: number | null;
|
|
20
|
-
manureFromAnimalStockStored?: import("
|
|
20
|
+
manureFromAnimalStockStored?: import("..").ManureFromAnimalStockStored[];
|
|
21
21
|
} | {
|
|
22
22
|
descriptor?: string;
|
|
23
23
|
volumeInM3?: number | null;
|
|
@@ -25,6 +25,6 @@ export declare class StorageDetailComponent {
|
|
|
25
25
|
cover?: number | null;
|
|
26
26
|
mixingFrequency?: number | null;
|
|
27
27
|
manureDerivation?: string[];
|
|
28
|
-
}) & import("
|
|
28
|
+
}) & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
|
|
29
29
|
onDataChange(event: unknown): void;
|
|
30
30
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JsonSchema, UISchemaElement } from '@jsonforms/core';
|
|
2
|
-
import { StorageNormalized } from '
|
|
2
|
+
import { StorageNormalized } from '../storage.types';
|
|
3
3
|
type StorageSection = 'manure' | 'slurry' | 'slurryFacilityToggle' | 'general';
|
|
4
4
|
export declare class StorageGeneralComponent {
|
|
5
5
|
private readonly i18n;
|
|
@@ -17,13 +17,13 @@ export declare class StorageGeneralComponent {
|
|
|
17
17
|
stableStrawLitter: number | null;
|
|
18
18
|
manureSupplyProportionStored: number | null;
|
|
19
19
|
createFacilitySpecificManureProduct: boolean;
|
|
20
|
-
} & import("
|
|
20
|
+
} & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | ({
|
|
21
21
|
createFacilitySpecificSlurryProduct: boolean;
|
|
22
|
-
} & import("
|
|
22
|
+
} & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | ({
|
|
23
23
|
slurrySupplyProportionStored: number | null;
|
|
24
24
|
slurryTankQuantity: number | null;
|
|
25
25
|
dilutionRatio: number | null;
|
|
26
|
-
} & import("
|
|
26
|
+
} & import("../../../core/schemas/ui-helper-registry").UiHelperDefinitions) | null>;
|
|
27
27
|
onDataChange(event: unknown): void;
|
|
28
28
|
}
|
|
29
29
|
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from '
|
|
1
|
+
import { ManurePitEntry, SlurryTankEntry, StorageEntryType } from '../storage.types';
|
|
2
2
|
export declare class StorageListComponent {
|
|
3
3
|
private readonly i18n;
|
|
4
4
|
private readonly masterData;
|
|
5
5
|
readonly rows: import("@angular/core").InputSignal<(ManurePitEntry | SlurryTankEntry)[]>;
|
|
6
6
|
readonly selectedIndex: import("@angular/core").InputSignal<number | null>;
|
|
7
7
|
readonly type: import("@angular/core").InputSignal<StorageEntryType>;
|
|
8
|
+
readonly errorIndices: import("@angular/core").InputSignal<ReadonlySet<number>>;
|
|
8
9
|
readonly select: import("@angular/core").OutputEmitterRef<number>;
|
|
9
10
|
readonly add: import("@angular/core").OutputEmitterRef<void>;
|
|
10
11
|
readonly delete: import("@angular/core").OutputEmitterRef<number>;
|
|
@@ -12,6 +13,8 @@ export declare class StorageListComponent {
|
|
|
12
13
|
readonly headerName: import("@angular/core").Signal<string>;
|
|
13
14
|
readonly headerMeta: import("@angular/core").Signal<string>;
|
|
14
15
|
resolveName(row: ManurePitEntry | SlurryTankEntry, index: number): string;
|
|
16
|
+
rowHasError(index: number): boolean;
|
|
17
|
+
rowErrorLabel(): string;
|
|
15
18
|
resolveMeta(row: ManurePitEntry | SlurryTankEntry): string;
|
|
16
19
|
emptyLabel(): string;
|
|
17
20
|
emptyHintLabel(): string;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { StorageTab } from '
|
|
2
|
-
import { ManurePitEntry, SlurryTankEntry, StorageEntryType, StorageNormalized } from '
|
|
1
|
+
import { StorageTab } from '../../../core/navigation/navigation.service';
|
|
2
|
+
import { ManurePitEntry, SlurryTankEntry, StorageEntryType, StorageNormalized } from '../storage.types';
|
|
3
3
|
export declare class StorageMasterDetailComponent {
|
|
4
4
|
private readonly dataSvc;
|
|
5
5
|
private readonly navigationSvc;
|
|
6
|
+
private readonly globalValidation;
|
|
6
7
|
constructor();
|
|
7
8
|
readonly storage: import("@angular/core").Signal<StorageNormalized>;
|
|
8
9
|
readonly manurePitRows: import("@angular/core").Signal<ManurePitEntry[]>;
|
|
@@ -11,6 +12,8 @@ export declare class StorageMasterDetailComponent {
|
|
|
11
12
|
readonly selectedIndex: import("@angular/core").WritableSignal<number | null>;
|
|
12
13
|
readonly manureFacilitySpecificEnabled: import("@angular/core").Signal<boolean>;
|
|
13
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>>;
|
|
14
17
|
readonly detailOpen: import("@angular/core").Signal<boolean>;
|
|
15
18
|
readonly detailType: import("@angular/core").Signal<StorageEntryType>;
|
|
16
19
|
readonly currentDetail: import("@angular/core").Signal<ManurePitEntry | SlurryTankEntry | null>;
|