Wire relationship directionality and dualpath controls propagation
All checks were successful
CI / backend (push) Successful in 1m13s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s

Symmetric relationship types (isdirectional flag, migration 7d19) show
one entry per peer on the relationships card - a Dualpath pair no
longer lists its partner twice - and directional types read naturally
instead of Outgoing/Incoming. Deleting a collapsed entry removes every
underlying direction row.

Propagation is now real (migration 7d20): relationship types declare
propagation-through pairs in relationshiptypepropagations (M:N,
replacing the never-consumed single column); creating a controls link
on either bay of a Dualpath pair auto-creates it on the partner,
mirrored across both endpoints because live data stores controls as
bay -> PC. flask relationships propagate backfills existing data (29
rows fanned out on the WJ dataset, idempotent).

This also completes the tree that commit 1d21bf0 accidentally split
(core/models/__init__ imported RelationshipTypePropagation ahead of the
file that defines it), returning CI to green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-12 06:07:36 -04:00
parent 1d21bf0206
commit 4fd110a33d
10 changed files with 1023 additions and 76 deletions

View File

@@ -16,6 +16,7 @@
<th>Relationship Type</th>
<th>Description</th>
<th>Color</th>
<th>Directional</th>
<th>Actions</th>
</tr>
</thead>
@@ -24,6 +25,7 @@
<td><span class="badge" :style="colorStyle(t.color)">{{ t.relationshiptype }}</span></td>
<td class="cell-truncate" :title="t.description">{{ t.description || '-' }}</td>
<td><span class="mono">{{ t.color || 'auto' }}</span></td>
<td>{{ t.isdirectional === false ? 'connection' : 'yes' }}</td>
<td class="actions">
<span v-if="t.isactive === false" class="badge badge-secondary" style="margin-right:6px;">inactive</span>
<button class="btn btn-secondary btn-sm" @click="openModal(t)">Edit</button>
@@ -31,7 +33,7 @@
</td>
</tr>
<tr v-if="visibleItems.length === 0">
<td colspan="4" style="text-align: center; color: var(--text-light);">No relationship types found</td>
<td colspan="5" style="text-align: center; color: var(--text-light);">No relationship types found</td>
</tr>
</tbody>
</table>
@@ -56,6 +58,10 @@
<label>Color <span class="hint">(relationship badges; blank = auto)</span></label>
<ColorSwatchPicker v-model="form.color" />
</div>
<div class="form-group">
<label class="checkbox-label"><input type="checkbox" v-model="form.isdirectional" /> Directional</label>
<span class="hint">off = shown as a plain connection, no direction</span>
</div>
<div class="form-group">
<label class="checkbox-label"><input type="checkbox" v-model="form.isactive" /> Active</label>
</div>
@@ -88,7 +94,7 @@ const showModal = ref(false)
const editing = ref(null)
const saving = ref(false)
const error = ref('')
const form = ref({ relationshiptype: '', description: '', color: '', isactive: true })
const form = ref({ relationshiptype: '', description: '', color: '', isactive: true, isdirectional: true })
onMounted(loadData)
@@ -107,8 +113,8 @@ async function loadData() {
function openModal(item = null) {
editing.value = item
form.value = item
? { relationshiptype: item.relationshiptype || '', description: item.description || '', color: item.color || '', isactive: item.isactive !== false }
: { relationshiptype: '', description: '', color: '', isactive: true }
? { relationshiptype: item.relationshiptype || '', description: item.description || '', color: item.color || '', isactive: item.isactive !== false, isdirectional: item.isdirectional !== false }
: { relationshiptype: '', description: '', color: '', isactive: true, isdirectional: true }
error.value = ''
showModal.value = true
}