mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 18:17:36 +00:00
* Allow worktree parentage across projects on one host * Keep sidebar placement and project ownership consistent * Keep project labels on phone rows outside their own section * Derive sidebar placement and reveal from shared occurrences * Preserve project text across workspace card styles * Resolve saved lineage peers without rebuilding host projects * fix: preserve independent project deletion progress * fix: satisfy mobile formatting and test lint checks * test: declare project fixture arrays without assertions * Align reveal fixtures with rendered workspace occurrences * fix: reuse project name for cross-repo child cards * fix: satisfy mobile section lint after main merge * fix: retain project label for nested mobile rows * test: keep nested card owner assertion resilient * test: assert project badge visibility across card styles * test: drop lineage tests already covered by the whole-flow suites The host-peer projection is exercised by the runtime and SSH listing integration tests, and the simple phone nesting case is covered by the deep-chain, Pinned and hidden-project flow test.
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
export function getVisibleLineagePlacement<Row>(
|
|
visibleRows: readonly Row[],
|
|
roots: readonly Row[],
|
|
childrenByParentIdentity: ReadonlyMap<string, readonly Row[]>,
|
|
identityOf: (row: Row) => string,
|
|
bridgeHidden = false
|
|
): Map<string, Row> {
|
|
const visible = new Set(visibleRows.map(identityOf))
|
|
const placement = new Map<string, Row>()
|
|
const seen = new Set<string>()
|
|
for (const root of roots) {
|
|
const pending = [root]
|
|
while (pending.length > 0) {
|
|
const current = pending.pop()
|
|
if (current === undefined) {
|
|
continue
|
|
}
|
|
const identity = identityOf(current)
|
|
if (seen.has(identity)) {
|
|
continue
|
|
}
|
|
seen.add(identity)
|
|
const isVisible = visible.has(identity)
|
|
if (isVisible) {
|
|
placement.set(identity, root)
|
|
}
|
|
if (isVisible || bridgeHidden) {
|
|
for (const child of childrenByParentIdentity.get(identity) ?? []) {
|
|
pending.push(child)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return placement
|
|
}
|
|
|
|
/** A hidden parent breaks placement; a visible child starts its own section. */
|
|
export function getTopVisibleLineageRoots<Row>(
|
|
visibleRows: readonly Row[],
|
|
childrenByParentIdentity: ReadonlyMap<string, readonly Row[]>,
|
|
identityOf: (row: Row) => string
|
|
): Map<string, Row> {
|
|
const childrenOfVisibleParents = new Set<string>()
|
|
for (const row of visibleRows) {
|
|
for (const child of childrenByParentIdentity.get(identityOf(row)) ?? []) {
|
|
childrenOfVisibleParents.add(identityOf(child))
|
|
}
|
|
}
|
|
const roots = visibleRows.filter((row) => !childrenOfVisibleParents.has(identityOf(row)))
|
|
const placement = getVisibleLineagePlacement(
|
|
visibleRows,
|
|
roots,
|
|
childrenByParentIdentity,
|
|
identityOf
|
|
)
|
|
for (const row of visibleRows) {
|
|
const identity = identityOf(row)
|
|
if (!placement.has(identity)) {
|
|
placement.set(identity, row)
|
|
}
|
|
}
|
|
return placement
|
|
}
|