Complete training workflow and acceptance hardening
This commit is contained in:
parent
4c4b91064f
commit
7237265833
243 changed files with 17014 additions and 1500 deletions
|
|
@ -20,7 +20,9 @@ export function KioCard({ state, required = [], readOnly = false, referenceArm =
|
|||
const groups = visibleGroups(dds);
|
||||
const section = (group: FieldGroup) => (
|
||||
<section className={`kio-arm-section kio-arm-${group.area}`} key={group.title}>
|
||||
{(!referenceArm || group.area !== "header") && <div className="kio-arm-section-title">{group.title}</div>}
|
||||
{(!referenceArm || group.area !== "header") && <div className="kio-arm-section-title">
|
||||
{referenceArm && group.area === "incident" ? "Введите тип происшествия" : group.title}
|
||||
</div>}
|
||||
<div className="kio-arm-fields">
|
||||
{(referenceArm && group.area === "incident"
|
||||
? [...group.fields].sort((a, b) => Number(b.path === "incident_type") - Number(a.path === "incident_type"))
|
||||
|
|
@ -198,6 +200,7 @@ function SignsPicker({
|
|||
{levels.map((level) => (
|
||||
<SignSelect
|
||||
key={level}
|
||||
level={level}
|
||||
prefix={value.slice(0, level)}
|
||||
group={group}
|
||||
chosen={value[level] ?? ""}
|
||||
|
|
@ -218,8 +221,9 @@ function SignsPicker({
|
|||
}
|
||||
|
||||
function SignSelect({
|
||||
prefix, group, chosen, onPick,
|
||||
level, prefix, group, chosen, onPick,
|
||||
}: {
|
||||
level: number;
|
||||
prefix: string[];
|
||||
group: number | null;
|
||||
chosen: string;
|
||||
|
|
@ -230,7 +234,7 @@ function SignSelect({
|
|||
// Уровня может не быть: часть происшествий классифицируется двумя признаками.
|
||||
if (!page.isLoading && values.length === 0) return null;
|
||||
return (
|
||||
<select aria-label={`Признак происшествия ${prefix.length + 1}`} value={chosen} onChange={(e) => onPick(e.target.value)} disabled={page.isLoading}>
|
||||
<select aria-label={`Признак происшествия ${level + 1}`} value={chosen} onChange={(e) => onPick(e.target.value)} disabled={page.isLoading}>
|
||||
<option value="">—</option>
|
||||
{values.map((sign) => (
|
||||
<option key={sign} value={sign}>{sign}</option>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,24 @@ export interface CardState {
|
|||
|
||||
export const empty: CardState = { server: {}, pending: {} };
|
||||
|
||||
function sameValue(left: unknown, right: unknown): boolean {
|
||||
if (Object.is(left, right)) return true;
|
||||
if (Array.isArray(left) || Array.isArray(right)) {
|
||||
return Array.isArray(left) && Array.isArray(right)
|
||||
&& left.length === right.length
|
||||
&& left.every((item, index) => sameValue(item, right[index]));
|
||||
}
|
||||
if (left && right && typeof left === "object" && typeof right === "object") {
|
||||
const leftRecord = left as Record<string, unknown>;
|
||||
const rightRecord = right as Record<string, unknown>;
|
||||
const keys = Object.keys(leftRecord);
|
||||
return keys.length === Object.keys(rightRecord).length
|
||||
&& keys.every((key) => key in rightRecord
|
||||
&& sameValue(leftRecord[key], rightRecord[key]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function setNested(card: Record<string, unknown>, path: string, value: unknown): Record<string, unknown> {
|
||||
const [head, ...rest] = path.split(".");
|
||||
if (rest.length === 0) return { ...card, [head]: value };
|
||||
|
|
@ -42,7 +60,7 @@ export function applyPatch(
|
|||
const pending = { ...state.pending };
|
||||
for (const [path, value] of Object.entries(fields)) {
|
||||
server = setNested(server, path, value);
|
||||
if (source === "auto" || pending[path] === value) delete pending[path];
|
||||
if (source === "auto" || sameValue(pending[path], value)) delete pending[path];
|
||||
}
|
||||
return { server, pending };
|
||||
}
|
||||
|
|
@ -51,7 +69,7 @@ export function applyPatch(
|
|||
export function applyState(state: CardState, card: Record<string, unknown>): CardState {
|
||||
const pending = { ...state.pending };
|
||||
for (const path of Object.keys(pending)) {
|
||||
if (readPath(card, path) === pending[path]) delete pending[path];
|
||||
if (sameValue(readPath(card, path), pending[path])) delete pending[path];
|
||||
}
|
||||
return { server: card, pending };
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue