83 lines
2.6 KiB
Vue
83 lines
2.6 KiB
Vue
<template>
|
|
<div class="rel-graph">
|
|
<div class="rel-col rel-supersedes">
|
|
<span class="rel-col-label">Supersedes</span>
|
|
<div v-for="rel in supersedence" :key="`s-${rel.targetAppId}`" class="rel-node rel-old">
|
|
<strong>{{ rel.targetName || rel.targetAppId }}</strong>
|
|
<small>{{ rel.mode === 'replace' ? 'replace' : 'update' }}</small>
|
|
</div>
|
|
<p v-if="!supersedence.length" class="rel-empty">none</p>
|
|
</div>
|
|
|
|
<div class="rel-arrow">→</div>
|
|
|
|
<div class="rel-center">
|
|
<div class="rel-node rel-current">
|
|
<strong>{{ deployment.name }}</strong>
|
|
<small>{{ deployment.graphAppId ? 'published' : 'unpublished' }}</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rel-arrow">→</div>
|
|
|
|
<div class="rel-col rel-depends">
|
|
<span class="rel-col-label">Depends on</span>
|
|
<div v-for="rel in dependencies" :key="`d-${rel.targetAppId}`" class="rel-node rel-dep">
|
|
<strong>{{ rel.targetName || rel.targetAppId }}</strong>
|
|
<small>{{ rel.mode === 'autoInstall' ? 'auto-install' : 'detect' }}</small>
|
|
</div>
|
|
<p v-if="!dependencies.length" class="rel-empty">none</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue';
|
|
|
|
const props = defineProps({
|
|
deployment: { type: Object, required: true }
|
|
});
|
|
|
|
const relationships = computed(() => props.deployment.relationships || []);
|
|
const supersedence = computed(() => relationships.value.filter((r) => r.kind === 'supersedence'));
|
|
const dependencies = computed(() => relationships.value.filter((r) => r.kind === 'dependency'));
|
|
</script>
|
|
|
|
<style scoped>
|
|
.rel-graph {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
flex-wrap: wrap;
|
|
padding: 0.6rem 0;
|
|
}
|
|
.rel-col,
|
|
.rel-center {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
min-width: 120px;
|
|
}
|
|
.rel-col-label {
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--text-muted, #8a93a6);
|
|
}
|
|
.rel-node {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0.45rem 0.6rem;
|
|
border-radius: 10px;
|
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
background: rgba(255, 255, 255, 0.04);
|
|
}
|
|
.rel-node strong { font-size: 0.82rem; }
|
|
.rel-node small { font-size: 0.68rem; color: var(--text-muted, #8a93a6); }
|
|
.rel-current { border-color: rgba(120, 170, 255, 0.5); background: rgba(120, 170, 255, 0.12); }
|
|
.rel-old { border-color: rgba(255, 196, 120, 0.4); }
|
|
.rel-dep { border-color: rgba(140, 220, 170, 0.4); }
|
|
.rel-arrow { color: var(--text-muted, #8a93a6); font-size: 1.1rem; }
|
|
.rel-empty { font-size: 0.72rem; color: var(--text-muted, #8a93a6); margin: 0; }
|
|
</style>
|