Skip to content

Commit 1393ec6

Browse files
fix(timeline): truncate long synced bucket names in sidebar (#757)
* fix(timeline): truncate long synced bucket names in sidebar (#682) Synced bucket names can exceed 137+ characters, making the timeline sidebar unusable on smaller screens. Three fixes: - CSS text-overflow ellipsis as fallback for any long label - Abbreviate synced names: show 'watcher-name (synced from host)' instead of full 'watcher_localhost-synced-from-remotehost' - Add title tooltip showing full bucket ID on hover - Fix: use group.id instead of group.content when looking up bucket ID for event editing (content now contains display HTML, not raw ID) * fix(timeline): add proper HTML escaping in abbreviateBucketName to prevent XSS
1 parent fc5bdd9 commit 1393ec6

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

src/visualizations/VisTimeline.vue

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ div#visualization {
2828
pointer-events: none;
2929
}
3030
31+
.vis-labelset .vis-label .vis-inner {
32+
max-width: 250px;
33+
overflow: hidden;
34+
text-overflow: ellipsis;
35+
white-space: nowrap;
36+
}
37+
3138
.timeline-timeline {
3239
font-family: sans-serif !important;
3340
@@ -224,6 +231,26 @@ export default {
224231
alert('selected multiple items: ' + JSON.stringify(properties.items));
225232
}
226233
},
234+
escapeHtml(str: string): string {
235+
return str
236+
.replace(/&/g, '&')
237+
.replace(/</g, '&lt;')
238+
.replace(/>/g, '&gt;')
239+
.replace(/"/g, '&quot;')
240+
.replace(/'/g, '&#39;');
241+
},
242+
abbreviateBucketName(bucketId: string): string {
243+
// Abbreviate synced bucket names which can be extremely long (#682)
244+
// e.g. "aw-watcher-window_host-synced-from-remotehost" -> "aw-watcher-window (synced from remotehost)"
245+
const escaped = this.escapeHtml(bucketId);
246+
const syncMatch = bucketId.match(/^([^_]+)_.*-synced-from-(.+)$/);
247+
if (syncMatch) {
248+
return `<span title="${escaped}">${this.escapeHtml(
249+
syncMatch[1]
250+
)} (synced from ${this.escapeHtml(syncMatch[2])})</span>`;
251+
}
252+
return `<span title="${escaped}">${escaped}</span>`;
253+
},
227254
ensureUpdate() {
228255
// Will only run update() if data available and never ran before
229256
if (!this.updateHasRun) {
@@ -248,7 +275,8 @@ export default {
248275
);
249276
}
250277
}
251-
return { id: bucket.id, content: this.showRowLabels ? bucket.id : '' };
278+
const label = this.showRowLabels ? this.abbreviateBucketName(bucket.id) : '';
279+
return { id: bucket.id, content: label };
252280
});
253281
254282
// Build items

0 commit comments

Comments
 (0)