Skip to content

Commit 079bf30

Browse files
committed
Improve icons and tooltips on the UI
Signed-off-by: Xabier Larrakoetxea <[email protected]>
1 parent 10acd72 commit 079bf30

File tree

9 files changed

+79
-41
lines changed

9 files changed

+79
-41
lines changed

internal/http/ui/handler_select_service.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ func (u ui) handlerSelectService() http.HandlerFunc {
5252
)
5353

5454
type tplDataService struct {
55-
Name string
56-
HasWarning bool
57-
HasCritical bool
58-
DetailsURL string
55+
Name string
56+
HasWarning bool
57+
HasCritical bool
58+
DetailsURL string
59+
TotalAlertsFiring int
5960
}
6061
type tplData struct {
6162
Services []tplDataService
@@ -75,22 +76,23 @@ func (u ui) handlerSelectService() http.HandlerFunc {
7576
for _, svc := range s {
7677
hasCritical := false
7778
hasWarning := false
79+
totalAlertsFiring := 0
7880
for _, sloAlert := range svc.Alerts {
7981
if sloAlert.FiringPage != nil {
8082
hasCritical = true
83+
totalAlertsFiring++
8184
}
8285
if sloAlert.FiringWarning != nil {
8386
hasWarning = true
84-
}
85-
if hasCritical && hasWarning {
86-
break
87+
totalAlertsFiring++
8788
}
8889
}
8990
tplServices = append(tplServices, tplDataService{
90-
Name: svc.Service.ID,
91-
HasWarning: hasWarning,
92-
HasCritical: hasCritical,
93-
DetailsURL: urls.AppURL("/services/" + svc.Service.ID),
91+
Name: svc.Service.ID,
92+
HasWarning: hasWarning,
93+
HasCritical: hasCritical,
94+
DetailsURL: urls.AppURL("/services/" + svc.Service.ID),
95+
TotalAlertsFiring: totalAlertsFiring,
9496
})
9597
}
9698
return tplServices

internal/http/ui/handler_select_service_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ func TestHandlerSelectService(t *testing.T) {
7070
`<input type="search" name="service-search" value="" placeholder="Search" aria-label="Search" hx-get="/u/app/services?component=service-list&service-sort-mode=service-name-asc" hx-trigger="change, keyup changed delay:500ms, search" hx-target="#services-list" hx-include="this" />`, // We have the search bar with HTMX.
7171
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=&service-sort-mode=service-name-desc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Service ↑</div> </th>`, // We have sortable HTMX Service column.
7272
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=&service-sort-mode=status-desc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Status ⇅</div> </th>`, // We have sortable HTMX status column.
73-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
74-
`<td><a href="/u/app/services/test-svc2">test-svc2</a></td> <td> <div class="icon-triangle-alert is-warning"></div>`, // Svc2 should be warning.
75-
`<td><a href="/u/app/services/test-svc3">test-svc3</a></td> <td> <div class="icon-circle-check is-ok"></div>`, // Svc3 should be ok.
73+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 2 alerts</div>`, // Svc1 should be critical.
74+
`<td><a href="/u/app/services/test-svc2">test-svc2</a></td> <td> <div class="is-warning"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc2 should be warning.
75+
`<td><a href="/u/app/services/test-svc3">test-svc3</a></td> <td> <div class="is-ok"> <i data-lucide="circle-check"></i> No alerts firing</div>`, // Svc3 should be ok.
7676
`<button class="secondary" hx-get="/u/app/services?service-search=&service-sort-mode=service-name-asc&component=service-list&forward-cursor=test-next-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination prev.
7777
`<button class="secondary" hx-get="/u/app/services?service-search=&service-sort-mode=service-name-asc&component=service-list&backward-cursor=test-prev-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination next.
7878
},
@@ -130,7 +130,7 @@ func TestHandlerSelectService(t *testing.T) {
130130
},
131131
expCode: 200,
132132
expBody: []string{
133-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
133+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc1 should be critical.
134134
`<button class="secondary" hx-get="/u/app/services?service-search=test&service-sort-mode=service-name-asc&component=service-list&backward-cursor=test-prev-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination prev.
135135
`<button class="secondary" disabled hx-get="" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination next.
136136
},
@@ -169,7 +169,7 @@ func TestHandlerSelectService(t *testing.T) {
169169
},
170170
expCode: 200,
171171
expBody: []string{
172-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
172+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc1 should be critical.
173173
`<button class="secondary" disabled hx-get="" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination prev.
174174
`<button class="secondary" hx-get="/u/app/services?service-search=&service-sort-mode=service-name-asc&component=service-list&forward-cursor=test-next-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination next.
175175
},
@@ -210,7 +210,7 @@ func TestHandlerSelectService(t *testing.T) {
210210
},
211211
expCode: 200,
212212
expBody: []string{
213-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
213+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc1 should be critical.
214214
`<button class="secondary" hx-get="/u/app/services?service-search=test&service-sort-mode=service-name-asc&component=service-list&backward-cursor=test-prev-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination prev.
215215
`<button class="secondary" hx-get="/u/app/services?service-search=test&service-sort-mode=service-name-asc&component=service-list&forward-cursor=test-next-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination next.
216216
},
@@ -253,7 +253,7 @@ func TestHandlerSelectService(t *testing.T) {
253253
expBody: []string{
254254
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=test&service-sort-mode=service-name-asc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Service ↓</div> </th>`, //We have service name sorting column.
255255
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=test&service-sort-mode=status-desc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Status ⇅</div> </th>`, //We have status sorting column.
256-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
256+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc1 should be critical.
257257
`<button class="secondary" hx-get="/u/app/services?service-search=test&service-sort-mode=service-name-desc&component=service-list&backward-cursor=test-prev-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination prev.
258258
`<button class="secondary" hx-get="/u/app/services?service-search=test&service-sort-mode=service-name-desc&component=service-list&forward-cursor=test-next-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination next.
259259
},
@@ -295,7 +295,7 @@ func TestHandlerSelectService(t *testing.T) {
295295
expBody: []string{
296296
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=&service-sort-mode=service-name-asc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Service ⇅</div> </th>`, //We have service name sorting column.
297297
`<th scope="col"> <div hx-get="/u/app/services?component=service-list&service-search=&service-sort-mode=status-desc" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Status ↑</div> </th>`, //We have status sorting column.
298-
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="icon-triangle-alert is-critical"></div>`, // Svc1 should be critical.
298+
`<td><a href="/u/app/services/test-svc1">test-svc1</a></td> <td> <div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing 1 alerts</div>`, // Svc1 should be critical.
299299
`<button class="secondary" hx-get="/u/app/services?service-search=&service-sort-mode=status-asc&component=service-list&backward-cursor=test-prev-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> << Previous </button>`, // We have the pagination prev.
300300
`<button class="secondary" hx-get="/u/app/services?service-search=&service-sort-mode=status-asc&component=service-list&forward-cursor=test-next-cursor" hx-target="#services-list" hx-swap="innerHTML show:window:top"> Next >> </button>`, // We have the pagination next.
301301
},

internal/http/ui/handler_slo_details_test.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,11 @@ func TestHandlerSLODetails(t *testing.T) {
147147
`<div><mark>operation: <strong>create</strong></mark> <span> </span><mark>type: <strong>something</strong></mark> <span> </span></div>`,
148148

149149
// Stats.
150-
`<div class="grid stats" hx-trigger="every 30s" hx-get="/u/app/slos/slo-1?component=slo-stats" hx-swap="outerHTML">`, // Autoreload status with HTMX.
151-
`<article><header data-tooltip="The % of error budget being consumed right now">Current Burning budget</header> <div class="is-critical">101.5%</div> </article>`, // Burning budget stat.
152-
`<article><header data-tooltip="The % of error budget remaining in the period as a rolling window">Remaining budget (Window)</header> <div class="is-ok">90%</div> </article>`, // Remaining budget stat.
153-
`<article><header>Warning Alert</header> <div class="is-warning">FIRING</div> </article>`, // Warning alert stat.
154-
`<article><header>Critical Alert</header> <div class="is-critical">FIRING</div> </article>`, // Critical alert stat.
150+
`<div class="grid stats" hx-trigger="every 30s" hx-get="/u/app/slos/slo-1?component=slo-stats" hx-swap="outerHTML">`, // Autoreload status with HTMX.
151+
`<article> <header> Current Burning budget <span data-tooltip="The % of error budget being consumed now (0% means none, 100% means all, >100% more than available budget)."> <i data-lucide="info"></i> </span> </header> <div class="is-critical">101.5%</div> </article> <article>`, // Burning budget stat.
152+
`<article> <header> Remaining budget on period (Window) <span data-tooltip="The % of error budget remaining in the period as a rolling window."> <i data-lucide="info"></i> </span> </header> <div class="is-ok">90%</div> </article> <article>`, // Remaining budget stat.
153+
`<article><header>Warning Alert</header> <div class="is-warning"><i data-lucide="triangle-alert"></i>FIRING</div> </article>`, // Warning alert stat.
154+
`<article><header>Critical Alert</header> <div class="is-critical"><i data-lucide="triangle-alert"></i>FIRING</div> </article>`, // Critical alert stat.
155155

156156
// SLI chart.
157157
`<article id="sli-chart-section">`, // SLI chart section.
@@ -202,12 +202,11 @@ func TestHandlerSLODetails(t *testing.T) {
202202
expCode: 200,
203203
expBody: []string{
204204
// Stats.
205-
`<div class="grid stats" hx-trigger="every 30s" hx-get="/u/app/slos/slo-1?component=slo-stats" hx-swap="outerHTML">`, // Autoreload status with HTMX.
206-
`<article><header data-tooltip="The % of error budget being consumed right now">Current Burning budget</header> <div class="is-critical">101.5%</div> </article>`, // Burning budget stat.
207-
`<article><header data-tooltip="The % of error budget remaining in the period as a rolling window">Remaining budget (Window)</header> <div class="is-ok">90%</div> </article>`, // Remaining budget stat.
208-
`<article><header>Warning Alert</header> <div class="is-warning">FIRING</div> </article>`, // Warning alert stat.
209-
`<article><header>Critical Alert</header> <div class="is-critical">FIRING</div> </article>`, // Critical alert stat.
210-
205+
`<div class="grid stats" hx-trigger="every 30s" hx-get="/u/app/slos/slo-1?component=slo-stats" hx-swap="outerHTML">`, // Autoreload status with HTMX.
206+
`<article> <header> Current Burning budget <span data-tooltip="The % of error budget being consumed now (0% means none, 100% means all, >100% more than available budget)."> <i data-lucide="info"></i> </span> </header> <div class="is-critical">101.5%</div> </article> <article>`, // Burning budget stat.
207+
`<article> <header> Remaining budget on period (Window) <span data-tooltip="The % of error budget remaining in the period as a rolling window."> <i data-lucide="info"></i> </span> </header> <div class="is-ok">90%</div> </article> <article>`, // Remaining budget stat.
208+
`<article><header>Warning Alert</header> <div class="is-warning"><i data-lucide="triangle-alert"></i>FIRING</div> </article>`, // Warning alert stat.
209+
`<article><header>Critical Alert</header> <div class="is-critical"><i data-lucide="triangle-alert"></i>FIRING</div> </article>`, // Critical alert stat.
211210
},
212211
},
213212

internal/http/ui/static/css/main.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
--sloth-ok: rgb(58, 135, 19);
2727
--sloth-warning: rgb(253, 147, 3);
2828
--sloth-critical: rgb(197, 47, 33);
29+
--pico-mark-background-color: rgb(223, 227, 235);
2930
}
3031

3132
/* Dark color scheme (Auto) */
@@ -60,3 +61,20 @@
6061
color: var(--sloth-critical);
6162
}
6263

64+
65+
svg.lucide {
66+
display: inline-block;
67+
vertical-align: middle;
68+
margin-left: 0.25em;
69+
margin-right: 0.25em;
70+
margin-bottom: 0.15em;
71+
}
72+
73+
header svg.lucide {
74+
width: 1em;
75+
height: 1em;
76+
}
77+
78+
span[data-tooltip] {
79+
border-bottom: none !important;
80+
}

internal/http/ui/static/js/main.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function isColorThemeLight() {
1919
return true; // Default to light.
2020
}
2121

22-
// CSS utils.
22+
// --------- CSS ---------.
2323
function getCSSVariableValue(cssVar) {
2424
// Sanitize variable name.
2525
if (cssVar.startsWith("--")) {
@@ -28,6 +28,11 @@ function getCSSVariableValue(cssVar) {
2828
return getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
2929
}
3030

31+
// Re-create lucide icons after htmx content swap.
32+
document.body.addEventListener('htmx:afterSwap', function(evt) {
33+
lucide.createIcons();
34+
});
35+
3136
// --------- PLOTS ---------.
3237

3338
function renderUplotSLIChart(domElID, json) {

internal/http/ui/templates/app/services/comp_service_list.tmpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
<td><a href="{{.DetailsURL}}">{{.Name}}</a></td>
3131
<td>
3232
{{ if .HasCritical }}
33-
<div class="icon-triangle-alert is-critical"></div>
33+
<div class="is-critical"> <i data-lucide="triangle-alert"></i> Firing {{.TotalAlertsFiring}} alerts</div>
3434
{{ else if .HasWarning }}
35-
<div class="icon-triangle-alert is-warning"></div>
35+
<div class="is-warning"> <i data-lucide="triangle-alert"></i> Firing {{.TotalAlertsFiring}} alerts</div>
3636
{{ else }}
37-
<div class="icon-circle-check is-ok"></div>
37+
<div class="is-ok"> <i data-lucide="circle-check"></i> No alerts firing</div>
3838
{{ end }}
3939
</td>
4040
</tr>

0 commit comments

Comments
 (0)