forked from jappel/leistungsbilanz-ts
Extract circuit grid projection
This commit is contained in:
parent
009152b406
commit
6c45c97ffd
5 changed files with 343 additions and 171 deletions
186
src/frontend/utils/circuit-grid-projection.ts
Normal file
186
src/frontend/utils/circuit-grid-projection.ts
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
import type {
|
||||
CircuitTreeCircuitDto,
|
||||
CircuitTreeDeviceRowDto,
|
||||
CircuitTreeSectionDto,
|
||||
} from "../types.js";
|
||||
import {
|
||||
allColumns,
|
||||
circuitOnlyColumns,
|
||||
compareSortValues,
|
||||
deviceFieldKeys,
|
||||
getBlockSortValue,
|
||||
getCellKind,
|
||||
getCircuitValue,
|
||||
getDeviceValue,
|
||||
normalizeFilterValue,
|
||||
} from "./circuit-grid-model";
|
||||
import type {
|
||||
CellKey,
|
||||
CellKind,
|
||||
ColumnDef,
|
||||
GridValue,
|
||||
RowType,
|
||||
} from "./circuit-grid-model";
|
||||
|
||||
export type ColumnFilters = Partial<Record<CellKey, string[]>>;
|
||||
|
||||
export interface GridSortState {
|
||||
key: CellKey;
|
||||
direction: "asc" | "desc";
|
||||
}
|
||||
|
||||
export interface VisibleGridCell {
|
||||
cellKey: CellKey;
|
||||
editable: boolean;
|
||||
kind: CellKind;
|
||||
value: GridValue;
|
||||
}
|
||||
|
||||
export interface VisibleGridRow {
|
||||
rowKey: string;
|
||||
rowType: RowType;
|
||||
sectionId: string;
|
||||
circuit?: CircuitTreeCircuitDto;
|
||||
device?: CircuitTreeDeviceRowDto;
|
||||
cells: VisibleGridCell[];
|
||||
}
|
||||
|
||||
function getCircuitBlockFilterValues(circuit: CircuitTreeCircuitDto, key: CellKey): Set<string> {
|
||||
const values = new Set<string>();
|
||||
if (circuitOnlyColumns.has(key) || key === "displayName" || key === "remark") {
|
||||
values.add(normalizeFilterValue(getCircuitValue(circuit, key)));
|
||||
}
|
||||
if (!circuitOnlyColumns.has(key)) {
|
||||
for (const device of circuit.deviceRows) {
|
||||
values.add(normalizeFilterValue(getDeviceValue(device, key)));
|
||||
}
|
||||
}
|
||||
if (values.size === 0 && deviceFieldKeys.has(key)) {
|
||||
values.add(normalizeFilterValue(undefined));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
export function getDistinctFilterValues(
|
||||
sections: readonly CircuitTreeSectionDto[],
|
||||
columns: readonly ColumnDef[]
|
||||
): Record<CellKey, string[]> {
|
||||
const result = {} as Record<CellKey, string[]>;
|
||||
for (const column of columns) {
|
||||
const values = new Set<string>();
|
||||
for (const section of sections) {
|
||||
for (const circuit of section.circuits) {
|
||||
for (const value of getCircuitBlockFilterValues(circuit, column.key)) {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
result[column.key] = [...values].sort((left, right) =>
|
||||
left.localeCompare(right, undefined, { numeric: true })
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filterAndSortCircuitSections(
|
||||
sections: readonly CircuitTreeSectionDto[],
|
||||
columnFilters: ColumnFilters,
|
||||
sortState: GridSortState | null
|
||||
): CircuitTreeSectionDto[] {
|
||||
const activeFilters = Object.entries(columnFilters).filter(([, values]) => (values?.length ?? 0) > 0) as Array<
|
||||
[CellKey, string[]]
|
||||
>;
|
||||
|
||||
return sections
|
||||
.map((section) => {
|
||||
let circuits = section.circuits.filter((circuit) =>
|
||||
activeFilters.every(([key, selectedValues]) => {
|
||||
const blockValues = getCircuitBlockFilterValues(circuit, key);
|
||||
return selectedValues.some((selectedValue) => blockValues.has(selectedValue));
|
||||
})
|
||||
);
|
||||
|
||||
if (sortState) {
|
||||
// Circuit blocks are sorted as units; their device row membership/order is untouched.
|
||||
circuits = [...circuits].sort((left, right) => {
|
||||
const comparison = compareSortValues(
|
||||
getBlockSortValue(left, sortState.key),
|
||||
getBlockSortValue(right, sortState.key)
|
||||
);
|
||||
return sortState.direction === "asc" ? comparison : -comparison;
|
||||
});
|
||||
}
|
||||
|
||||
return { ...section, circuits };
|
||||
})
|
||||
.filter((section) => section.circuits.length > 0);
|
||||
}
|
||||
|
||||
function makeVisibleGridRow(
|
||||
rowType: RowType,
|
||||
sectionId: string,
|
||||
circuit?: CircuitTreeCircuitDto,
|
||||
device?: CircuitTreeDeviceRowDto
|
||||
): VisibleGridRow {
|
||||
const rowKey =
|
||||
rowType === "placeholder"
|
||||
? `placeholder:${sectionId}`
|
||||
: rowType === "deviceRow" && device
|
||||
? `device:${device.id}`
|
||||
: `${rowType}:${circuit?.id ?? sectionId}`;
|
||||
|
||||
const cells = allColumns.map((column): VisibleGridCell => {
|
||||
const kind = getCellKind(rowType, column.key);
|
||||
const editable = kind === "circuitField" || kind === "deviceField";
|
||||
let value: GridValue;
|
||||
|
||||
if (rowType === "placeholder") {
|
||||
value = column.key === "equipmentIdentifier" ? "-frei-" : undefined;
|
||||
} else if (kind === "deviceField" && device) {
|
||||
value = getDeviceValue(device, column.key);
|
||||
} else if (kind === "circuitField" && circuit) {
|
||||
value = getCircuitValue(circuit, column.key);
|
||||
} else if (column.key === "circuitTotalPower" && circuit) {
|
||||
value = circuit.circuitTotalPower;
|
||||
} else if (column.key === "rowTotalPower" && device) {
|
||||
value = device.rowTotalPower;
|
||||
}
|
||||
|
||||
return { cellKey: column.key, editable, kind, value };
|
||||
});
|
||||
|
||||
return { rowKey, rowType, sectionId, circuit, device, cells };
|
||||
}
|
||||
|
||||
export function buildVisibleGridRows(sections: readonly CircuitTreeSectionDto[]): VisibleGridRow[] {
|
||||
const rows: VisibleGridRow[] = [];
|
||||
for (const section of sections) {
|
||||
rows.push({
|
||||
rowKey: `section:${section.id}`,
|
||||
rowType: "section",
|
||||
sectionId: section.id,
|
||||
cells: allColumns.map((column) => ({
|
||||
cellKey: column.key,
|
||||
editable: false,
|
||||
kind: "readonly",
|
||||
value: undefined,
|
||||
})),
|
||||
});
|
||||
|
||||
for (const circuit of section.circuits) {
|
||||
if (circuit.deviceRows.length === 0) {
|
||||
rows.push(makeVisibleGridRow("reserveCircuit", section.id, circuit));
|
||||
} else if (circuit.deviceRows.length === 1) {
|
||||
rows.push(makeVisibleGridRow("circuitCompact", section.id, circuit, circuit.deviceRows[0]));
|
||||
} else {
|
||||
rows.push(makeVisibleGridRow("circuitSummary", section.id, circuit));
|
||||
for (const device of circuit.deviceRows) {
|
||||
rows.push(makeVisibleGridRow("deviceRow", section.id, circuit, device));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows.push(makeVisibleGridRow("placeholder", section.id));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue