Collapse the relationships card by default, with an honest count
The triage band answers the common case above the fold, so the full edge list is reference rather than the first thing to read. Same caret and keyboard handling as the collapsible panels on the same page. The card stays: it is the only surface with Add and delete, and it keeps each edge's exact type where the band deduplicates by asset - on a printer, four rows collapse to two chips and which machine DEFAULTS to it is lost. The header count is of RENDERED items, not raw edges: a symmetric Dualpath link is stored in both directions, so counting edges read 3 above a card showing 2. Frontend 280 passed.
This commit is contained in:
@@ -1,16 +1,32 @@
|
||||
<template>
|
||||
<div class="relationships-section">
|
||||
<div class="section-header">
|
||||
<h3 class="section-title">Relationships</h3>
|
||||
<h3
|
||||
class="section-title rel-header"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
:aria-expanded="!collapsed"
|
||||
@click="collapsed = !collapsed"
|
||||
@keydown.enter.prevent="collapsed = !collapsed"
|
||||
@keydown.space.prevent="collapsed = !collapsed"
|
||||
>
|
||||
<span class="rel-caret" :class="{ collapsed }" aria-hidden="true">▾</span>
|
||||
<span>Relationships</span>
|
||||
<!-- The count is what makes a collapsed card honest: without it, "no
|
||||
relationships" and "four relationships you cannot see" look the
|
||||
same from the outside. -->
|
||||
<span v-if="!loading && relationshipCount" class="rel-count">{{ relationshipCount }}</span>
|
||||
</h3>
|
||||
<button
|
||||
v-if="authStore.isAuthenticated"
|
||||
class="btn btn-sm btn-primary"
|
||||
@click="showAddModal = true"
|
||||
@click.stop="openAdd"
|
||||
>
|
||||
Add Relationship
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-show="!collapsed">
|
||||
<div v-if="loading" class="loading">Loading relationships...</div>
|
||||
|
||||
<div v-else-if="!hasRelationships" class="empty-state">
|
||||
@@ -96,6 +112,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Add Relationship Modal -->
|
||||
<div v-if="showAddModal" class="modal-overlay">
|
||||
@@ -225,6 +242,22 @@ function colorForType(name) {
|
||||
}
|
||||
const showAddModal = ref(false)
|
||||
|
||||
// Collapsed by default. The triage band above answers the common case - what
|
||||
// this asset serves or is driven by - so the full edge list is reference rather
|
||||
// than the first thing to read. It is NOT redundant with the band and is not
|
||||
// removed: it is the only surface with Add and delete, and it keeps each edge's
|
||||
// exact type where the band deduplicates by asset. On a printer, four rows
|
||||
// (usesprinter and defaultprinter, per machine) collapse to two band chips, and
|
||||
// which machine DEFAULTS to it is a distinction the band deliberately drops.
|
||||
const collapsed = ref(true)
|
||||
|
||||
function openAdd() {
|
||||
// Adding from a collapsed card would otherwise drop the new row behind the
|
||||
// caret, which reads as the add having failed.
|
||||
collapsed.value = false
|
||||
showAddModal.value = true
|
||||
}
|
||||
|
||||
// New relationship form
|
||||
const newRel = ref({
|
||||
direction: 'outgoing',
|
||||
@@ -305,6 +338,14 @@ const directionalItems = computed(() => {
|
||||
return items
|
||||
})
|
||||
|
||||
// Counts what the card RENDERS, not raw edges. A symmetric link (Dualpath) is
|
||||
// stored in both directions in the legacy shape, so it is two rows in
|
||||
// outgoing+incoming and one "Connected" entry on screen. Counting edges
|
||||
// displayed 3 on a machine that shows 2 when you expand it, which is precisely
|
||||
// the mismatch this badge exists to avoid.
|
||||
const relationshipCount = computed(
|
||||
() => connectedItems.value.length + directionalItems.value.length)
|
||||
|
||||
const canSave = computed(() => {
|
||||
return newRel.value.relationshiptypeid && newRel.value.targetAssetId && resolvedAssetId.value
|
||||
})
|
||||
@@ -502,6 +543,38 @@ const getAssetRoute = assetRoute
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Matches the collapsible panels on the same page (PluginAssetPanels) so a
|
||||
card does not gain a second, slightly different caret. */
|
||||
.rel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.rel-caret {
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-light);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.rel-caret.collapsed { transform: rotate(-90deg); }
|
||||
|
||||
.rel-count {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-light);
|
||||
background: var(--bg-hover, rgba(127, 127, 127, 0.14));
|
||||
border-radius: 999px;
|
||||
padding: 0.05rem 0.45rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.rel-caret { transition: none; }
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: var(--text-light);
|
||||
font-style: italic;
|
||||
|
||||
Reference in New Issue
Block a user