feat: T4 waves 1-2 - rule configs, schema, suggestions core, season, rule forms
- Rule configs with typed parsers and registry; Berlin day helpers - Schema: T4 enums, Suggestion table, feed vocabulary (feedStatus as ColonyCondition with legacy text mapping), split queen source, varroa sample size; migration harness for data migrations - SuggestionsService: propose/refresh/resolve/obsolete/expire, accept/dismiss/reopen incl. bulk, lock order, concurrency e2e - SeasonService: phenology-based segments, inspection/varroa due dates, queen age; TimeEventsStep with JobPartialFailure - Frontend: per-rule settings forms with visible value sources Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
7097fcd97c
commit
d99a697739
116 files changed
+11239
-801
No files matched your search
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
childScope,
|
||||
has,
|
||||
makeParser,
|
||||
numberIn,
|
||||
optionalNumberIn,
|
||||
report,
|
||||
type Scope,
|
||||
} from './parse-helpers';
|
||||
import type { WaterContentConfig } from './rule-config.types';
|
||||
|
||||
const MIN_WATER_PERCENT = 10;
|
||||
const MAX_WATER_PERCENT = 30;
|
||||
const MAX_HONEY_TYPES = 50;
|
||||
const MAX_HONEY_TYPE_LENGTH = 100;
|
||||
|
||||
export const DEFAULT_WATER_CONTENT_CONFIG: WaterContentConfig = {
|
||||
warnAbovePercent: 18,
|
||||
confirmAbovePercent: 20,
|
||||
byHoneyType: {},
|
||||
};
|
||||
|
||||
function percent(scope: Scope, key: string, fallback: number): number {
|
||||
return numberIn(scope, key, fallback, MIN_WATER_PERCENT, MAX_WATER_PERCENT);
|
||||
}
|
||||
|
||||
const ORDER_MESSAGE =
|
||||
'Die Warnschwelle darf nicht über der Bestätigungsschwelle liegen.';
|
||||
|
||||
function readHoneyTypes(scope: Scope): WaterContentConfig['byHoneyType'] {
|
||||
const types = childScope(scope, 'byHoneyType');
|
||||
const names = Object.keys(types.raw);
|
||||
if (names.length > MAX_HONEY_TYPES) {
|
||||
report(scope, 'byHoneyType', `Höchstens ${MAX_HONEY_TYPES} Sorten.`);
|
||||
return {};
|
||||
}
|
||||
const entries: [
|
||||
string,
|
||||
{ warnAbovePercent?: number; confirmAbovePercent?: number },
|
||||
][] = [];
|
||||
for (const name of names) {
|
||||
if (name.length === 0 || name.length > MAX_HONEY_TYPE_LENGTH) {
|
||||
report(types, name.slice(0, 30), 'Der Sortenname ist ungültig.');
|
||||
continue;
|
||||
}
|
||||
const entry = childScope(types, name);
|
||||
const before = entry.issues.length;
|
||||
const value: { warnAbovePercent?: number; confirmAbovePercent?: number } =
|
||||
{};
|
||||
const warn = optionalNumberIn(
|
||||
entry,
|
||||
'warnAbovePercent',
|
||||
MIN_WATER_PERCENT,
|
||||
MAX_WATER_PERCENT,
|
||||
);
|
||||
const confirm = optionalNumberIn(
|
||||
entry,
|
||||
'confirmAbovePercent',
|
||||
MIN_WATER_PERCENT,
|
||||
MAX_WATER_PERCENT,
|
||||
);
|
||||
if (warn !== undefined && confirm !== undefined && warn > confirm) {
|
||||
report(entry, 'warnAbovePercent', ORDER_MESSAGE);
|
||||
}
|
||||
if (entry.issues.length > before) {
|
||||
continue;
|
||||
}
|
||||
if (warn !== undefined) {
|
||||
value.warnAbovePercent = warn;
|
||||
}
|
||||
if (confirm !== undefined) {
|
||||
value.confirmAbovePercent = confirm;
|
||||
}
|
||||
entries.push([name, value]);
|
||||
}
|
||||
// fromEntries defines own properties, so a name like "__proto__" is harmless.
|
||||
return Object.fromEntries(entries);
|
||||
}
|
||||
|
||||
export const waterContentParser = makeParser<WaterContentConfig>(
|
||||
'HONEY_WATER_CONTENT',
|
||||
DEFAULT_WATER_CONTENT_CONFIG,
|
||||
(scope) => {
|
||||
const d = DEFAULT_WATER_CONTENT_CONFIG;
|
||||
let warnAbovePercent = percent(
|
||||
scope,
|
||||
'warnAbovePercent',
|
||||
d.warnAbovePercent,
|
||||
);
|
||||
let confirmAbovePercent = percent(
|
||||
scope,
|
||||
'confirmAbovePercent',
|
||||
d.confirmAbovePercent,
|
||||
);
|
||||
if (warnAbovePercent > confirmAbovePercent) {
|
||||
report(
|
||||
scope,
|
||||
has(scope, 'warnAbovePercent')
|
||||
? 'warnAbovePercent'
|
||||
: 'confirmAbovePercent',
|
||||
ORDER_MESSAGE,
|
||||
);
|
||||
warnAbovePercent = d.warnAbovePercent;
|
||||
confirmAbovePercent = d.confirmAbovePercent;
|
||||
}
|
||||
return {
|
||||
warnAbovePercent,
|
||||
confirmAbovePercent,
|
||||
byHoneyType: readHoneyTypes(scope),
|
||||
};
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user