Gesamte Mono-Repo des Baukastens (alle apps/clients, examples/tests und packages)
dh_heyart
vor 5 Std. 96438053d50d33b24c946cd290d57356b4a80b73
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import type {
    ConfigurationEntry,
    ConfigurationReference,
    CustomerNumber,
} from "@dh-software/baukasten-types";
 
/** Stable identity for a reference (customer + key, key carries the subfolder path). */
export function referenceKey(reference: { customerNumber: CustomerNumber; key: string }): string {
    return `${reference.customerNumber} ${reference.key}`;
}
 
/** A right-side row: a reference resolved against the available catalog for display. */
export interface SelectedRow {
    reference: ConfigurationReference;
    displayName: string;
    /** false when the ref is no longer in `available` (permission lost / file removed). */
    isAvailable: boolean;
}
 
/** Available entries not yet chosen, in catalog order (the left list). */
export function availableEntries(
    available: ConfigurationEntry[],
    selected: ConfigurationReference[],
): ConfigurationEntry[] {
    const chosen = new Set(selected.map(referenceKey));
    return available.filter((entry) => !chosen.has(referenceKey(entry)));
}
 
/** Chosen references resolved to display rows, top -> bottom (the right list). */
export function selectedRows(
    available: ConfigurationEntry[],
    selected: ConfigurationReference[],
): SelectedRow[] {
    const byKey = new Map(available.map((entry) => [referenceKey(entry), entry]));
    return selected.map((reference) => {
        const match = byKey.get(referenceKey(reference));
        return {
            reference,
            displayName: match ? match.displayName : reference.key,
            isAvailable: match !== undefined,
        };
    });
}
 
/** Appends entries (as references) that are not already chosen, preserving their order. */
export function addReferences(
    selected: ConfigurationReference[],
    entries: ReadonlyArray<{ customerNumber: CustomerNumber; key: string }>,
): ConfigurationReference[] {
    const present = new Set(selected.map(referenceKey));
    const additions = entries
        .map((entry) => ({ customerNumber: entry.customerNumber, key: entry.key }))
        .filter((reference) => !present.has(referenceKey(reference)));
    return additions.length === 0 ? selected : [...selected, ...additions];
}
 
/** Removes all chosen references whose key is in `keys`. */
export function removeByKeys(
    selected: ConfigurationReference[],
    keys: ReadonlySet<string>,
): ConfigurationReference[] {
    return selected.filter((reference) => !keys.has(referenceKey(reference)));
}
 
/** Moves the item at `index` by `delta` (clamped); returns a new array. */
export function moveByOffset(
    selected: ConfigurationReference[],
    index: number,
    delta: number,
): ConfigurationReference[] {
    const target = index + delta;
    if (index < 0 || index >= selected.length || target < 0 || target >= selected.length) {
        return selected;
    }
    const next = selected.slice();
    const [moved] = next.splice(index, 1);
    next.splice(target, 0, moved);
    return next;
}
 
/** Drag-and-drop reorder: move `fromIndex` to sit at the drop target `toIndex`. */
export function reorder(
    selected: ConfigurationReference[],
    fromIndex: number,
    toIndex: number,
): ConfigurationReference[] {
    if (
        fromIndex === toIndex ||
        fromIndex < 0 ||
        fromIndex >= selected.length ||
        toIndex < 0 ||
        toIndex >= selected.length
    ) {
        return selected;
    }
    const next = selected.slice();
    const [moved] = next.splice(fromIndex, 1);
    const target = fromIndex < toIndex ? toIndex - 1 : toIndex;
    next.splice(target, 0, moved);
    return next;
}