Skip to content

Commit d3c212e

Browse files
committed
fix: display pin reason and clean image/tag in updates page
Return pin_reason from list and detail API endpoints. Change reason input to multiline textarea. Show full reason in version card and truncated in pinned list. Strip digest from image display and truncate hex-only tags (commit hashes, checksums) to 12 chars.
1 parent 37567ca commit d3c212e

File tree

4 files changed

+26
-6
lines changed

4 files changed

+26
-6
lines changed

frontend/src/components/UpdateDetailPanel.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ onMounted(loadDetail)
121121
<Pin :size="8" class="inline mr-0.5" /> Pinned
122122
</span>
123123
</div>
124+
<p v-if="detail.pinned && detail.pin_reason" class="mt-2 text-xs text-slate-400 italic">
125+
{{ detail.pin_reason }}
126+
</p>
124127
</div>
125128

126129
<!-- Risk Score (Pro) -->
@@ -191,11 +194,11 @@ onMounted(loadDetail)
191194
{{ detail.pinned ? 'Unpin this version' : 'Pin this version' }}
192195
</button>
193196
<div v-if="showPinInput && !detail.pinned" class="mt-2">
194-
<input
197+
<textarea
195198
v-model="pinReason"
196-
type="text"
199+
rows="2"
197200
placeholder="Reason (optional)"
198-
class="w-full px-3 py-2 bg-[#0B0E13] border border-slate-700 rounded-lg text-xs text-slate-300 placeholder-slate-600 focus:border-pb-green-500 focus:outline-none"
201+
class="w-full px-3 py-2 bg-[#0B0E13] border border-slate-700 rounded-lg text-xs text-slate-300 placeholder-slate-600 focus:border-pb-green-500 focus:outline-none resize-none"
199202
/>
200203
<button
201204
@click="handlePin"

frontend/src/pages/UpdatesPage.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ function updateTypeColor(type_: string): string {
6868
}
6969
}
7070
71+
function shortTag(tag: string): string {
72+
if (/^(sha-|sha256:)?[0-9a-f]{12,}$/i.test(tag)) return tag.slice(0, 12)
73+
return tag
74+
}
75+
7176
const formatTime = timeAgo
7277
7378
onMounted(() => {
@@ -187,11 +192,12 @@ onUnmounted(() => {
187192
</p>
188193
<UpdateBadge :update="u" />
189194
</div>
190-
<p class="text-[10px] text-slate-600 mt-0.5 truncate">{{ u.image }}</p>
195+
<p class="text-[10px] text-slate-600 mt-0.5 truncate">{{ u.image.split('@')[0] }}</p>
196+
<p v-if="u.status === 'pinned' && u.pin_reason" class="text-[10px] text-slate-500 mt-0.5 truncate italic">{{ u.pin_reason }}</p>
191197
</div>
192198
<div class="text-right shrink-0">
193199
<p :class="['text-xs font-bold', updateTypeColor(u.update_type)]">
194-
{{ u.current_tag }} → {{ u.latest_tag }}
200+
{{ shortTag(u.current_tag) }} → {{ shortTag(u.latest_tag) }}
195201
</p>
196202
<p class="text-[10px] text-slate-600 mt-0.5">{{ formatTime(u.detected_at) }}</p>
197203
</div>

frontend/src/services/updateApi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface ImageUpdate {
2929
risk_score: number
3030
status: string
3131
detected_at: string
32+
pin_reason?: string
3233
}
3334

3435
export interface UpdateSummary {
@@ -64,6 +65,7 @@ export interface ContainerUpdateDetail {
6465
risk_score: number
6566
active_cves: CVEInfo[]
6667
pinned: boolean
68+
pin_reason?: string
6769
source_url: string
6870
previous_digest: string
6971
update_command: string

internal/api/v1/updates.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ func (h *UpdateHandler) HandleListUpdates(w http.ResponseWriter, r *http.Request
4747

4848
updateMaps := make([]map[string]interface{}, 0, len(updates))
4949
for _, u := range updates {
50-
updateMaps = append(updateMaps, imageUpdateToMap(u))
50+
m := imageUpdateToMap(u)
51+
if u.Status == update.StatusPinned {
52+
if pin, _ := h.store.GetVersionPin(r.Context(), u.ContainerID); pin != nil {
53+
m["pin_reason"] = pin.Reason
54+
}
55+
}
56+
updateMaps = append(updateMaps, m)
5157
}
5258

5359
WriteJSON(w, http.StatusOK, map[string]interface{}{
@@ -116,6 +122,9 @@ func (h *UpdateHandler) HandleGetContainerUpdate(w http.ResponseWriter, r *http.
116122

117123
resp := imageUpdateToMap(u)
118124
resp["pinned"] = pin != nil
125+
if pin != nil {
126+
resp["pin_reason"] = pin.Reason
127+
}
119128

120129
if extension.CurrentEdition() == extension.Enterprise {
121130
if cves, err := h.store.ListContainerCVEs(r.Context(), containerID); err == nil {

0 commit comments

Comments
 (0)