mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
fix: preserve wall-hosted openings in static view
Issue: #282 User-Visible: yes
This commit is contained in:
+3
-1
@@ -23,7 +23,9 @@
|
||||
valid when it becomes a room or independent walls, while a rejected
|
||||
transaction stores no partial result and no longer reports false success.
|
||||
An invalid open passage also retains its specific actionable error instead
|
||||
of being masked by the generic wall-model migration blocker.
|
||||
of being masked by the generic wall-model migration blocker. The compact
|
||||
space card keeps wall-hosted doors, windows, gates and passages visible after
|
||||
the migration as well.
|
||||
Ambiguous legacy geometry is
|
||||
left unchanged with a recovery prompt. No Plan editor controls or
|
||||
zero-thickness-wall behaviour changed
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
в комнату или независимые стены, а отклонённая транзакция не записывает
|
||||
частичный результат и не показывает ложное сообщение об успехе. Невалидный
|
||||
открытый проход по-прежнему получает своё точное сообщение об ошибке, а не
|
||||
общий блокер миграции стен.
|
||||
общий блокер миграции стен. Компактная карточка пространства также не теряет
|
||||
после миграции двери, окна, ворота и проходы, привязанные к стенам.
|
||||
Неоднозначная старая геометрия остаётся без изменений с подсказкой по
|
||||
восстановлению. Кнопки редактора плана и поведение стен нулевой толщины не
|
||||
менялись
|
||||
|
||||
+5
-2
@@ -215,7 +215,10 @@ export function renderSpaceStatic(o: StaticRenderOpts): TemplateResult | null {
|
||||
const walls: WallEntry[] = Array.isArray(spCfg.walls) ? spCfg.walls : [];
|
||||
const cellCm = Number(spCfg.cell_cm) > 0 ? Number(spCfg.cell_cm) : 5;
|
||||
const resolvedHosted = (spCfg.openings || []).flatMap((opening: OpeningCfg) => {
|
||||
if (!opening.host) return [];
|
||||
// Contour-wall hosts keep the same saved x/y/angle projection as legacy
|
||||
// room openings. Only independent partitions need to be materialised from
|
||||
// their host because that geometry is stored separately from the opening.
|
||||
if (opening.host?.kind !== 'partition') return [];
|
||||
const resolved = resolvePartitionOpeningCompat(
|
||||
opening, space.partitions, NORM_W, cellCm, GRID_PITCH,
|
||||
).resolved;
|
||||
@@ -273,7 +276,7 @@ export function renderSpaceStatic(o: StaticRenderOpts): TemplateResult | null {
|
||||
// Static intentionally keeps the historical door/window/gate wall output.
|
||||
// Only the new negative-space type participates in its masonry fingerprint.
|
||||
const resolvedRawOpenings = (spCfg.openings || []).flatMap((opening: OpeningCfg) => {
|
||||
if (!opening.host) return [opening];
|
||||
if (!opening.host || opening.host.kind === 'wall') return [opening];
|
||||
const resolved = resolvedHosted.find((item) => item.opening.id === opening.id);
|
||||
return resolved ? [materializePartitionOpening(opening, resolved, NORM_W)] : [];
|
||||
});
|
||||
|
||||
@@ -47,6 +47,10 @@ test('passage bindings cannot reach subscriptions, locks or the info card', () =
|
||||
|
||||
test('static passage cuts and tunnels are passage-only additions', () => {
|
||||
assert.match(staticRender, /staticPassageOpenings\(resolvedRawOpenings, NORM_W\)/);
|
||||
assert.match(staticRender, /opening\.host\?\.kind !== 'partition'/,
|
||||
'only independent-wall hosts go through the partition resolver');
|
||||
assert.match(staticRender, /!opening\.host \|\| opening\.host\.kind === 'wall'/,
|
||||
'stable contour-wall hosts retain the legacy raw-opening projection');
|
||||
assert.match(staticRender, /passages: staticPassages\.map/);
|
||||
assert.match(staticRender, /renderOpeningTunnelFills/);
|
||||
assert.match(staticRender, /passageDataTunnels/);
|
||||
@@ -69,7 +73,11 @@ test('placement preview adds passage-only cut geometry without changing saved sy
|
||||
});
|
||||
|
||||
test('all write/import paths invoke the semantic passage validator', () => {
|
||||
assert.equal((backend.match(/validate_opening_passages\(/g) || []).length, 2);
|
||||
assert.equal((backend.match(/validate_opening_passages\(/g) || []).length, 3);
|
||||
assert.match(backend, /validate_opening_passages\(candidate_config, config_data\.get\("config"\)\)/,
|
||||
'Optimize validates the submitted v7 model before the identity barrier');
|
||||
assert.match(backend, /validate_opening_passages\(msg\["config"\], config_data\.get\("config"\)\)/,
|
||||
'Optimize validates the committed v8 model before persistence');
|
||||
assert.match(importer, /validate_opening_passages\(merged_config, current_config\)/);
|
||||
assert.match(importer, /validate_opening_passages\(incoming_config, validate_all=True\)/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user