Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit d8a801d

Browse files
UX: Improve rough edges of AI usage page
* Ensure all text uses I18n * Change from <button> usage to <DButton> * Use <AdminConfigAreaCard> in place of custom card styles * Format numbers nicely using our number format helper, show full values on hover using title attr
1 parent 7ca21cc commit d8a801d

File tree

4 files changed

+154
-149
lines changed

4 files changed

+154
-149
lines changed

assets/javascripts/discourse/components/ai-usage.gjs

Lines changed: 126 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import Component from "@glimmer/component";
22
import { tracked } from "@glimmer/tracking";
33
import { fn, hash } from "@ember/helper";
4-
import { on } from "@ember/modifier";
54
import { action } from "@ember/object";
65
import { LinkTo } from "@ember/routing";
76
import { service } from "@ember/service";
87
import { eq } from "truth-helpers";
8+
import DButton from "discourse/components/d-button";
99
import DateTimeInputRange from "discourse/components/date-time-input-range";
1010
import avatar from "discourse/helpers/avatar";
1111
import { ajax } from "discourse/lib/ajax";
12+
import { number } from "discourse/lib/formatter";
1213
import i18n from "discourse-common/helpers/i18n";
14+
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
1315
import Chart from "admin/components/chart";
1416
import ComboBox from "select-kit/components/combo-box";
1517

@@ -79,16 +81,16 @@ export default class AiUsage extends Component {
7981
);
8082

8183
for (
82-
let m = moment(startDate);
83-
m.isSameOrBefore(endDate);
84-
m.add(1, interval)
84+
let currentMoment = moment(startDate);
85+
currentMoment.isSameOrBefore(endDate);
86+
currentMoment.add(1, interval)
8587
) {
86-
const dateKey = m.format(format);
88+
const dateKey = currentMoment.format(format);
8789
const existingData = dataMap.get(dateKey);
8890

8991
normalized.push(
9092
existingData || {
91-
period: m.format(),
93+
period: currentMoment.format(),
9294
total_tokens: 0,
9395
total_cached_tokens: 0,
9496
total_request_tokens: 0,
@@ -131,19 +133,19 @@ export default class AiUsage extends Component {
131133
}),
132134
datasets: [
133135
{
134-
label: "Response Tokens",
136+
label: i18n("discourse_ai.usage.response_tokens"),
135137
data: normalizedData.map((row) => row.total_response_tokens),
136138
backgroundColor: colors.response,
137139
},
138140
{
139-
label: "Net Request Tokens",
141+
label: i18n("discourse_ai.usage.net_request_tokens"),
140142
data: normalizedData.map(
141143
(row) => row.total_request_tokens - row.total_cached_tokens
142144
),
143145
backgroundColor: colors.request,
144146
},
145147
{
146-
label: "Cached Request Tokens",
148+
label: i18n("discourse_ai.usage.cached_request_tokens"),
147149
data: normalizedData.map((row) => row.total_cached_tokens),
148150
backgroundColor: colors.cached,
149151
},
@@ -190,9 +192,9 @@ export default class AiUsage extends Component {
190192

191193
get periodOptions() {
192194
return [
193-
{ id: "day", name: "Last 24 Hours" },
194-
{ id: "week", name: "Last Week" },
195-
{ id: "month", name: "Last Month" },
195+
{ id: "day", name: i18n("discourse_ai.usage.periods.last_day") },
196+
{ id: "week", name: i18n("discourse_ai.usage.periods.last_week") },
197+
{ id: "month", name: i18n("discourse_ai.usage.periods.last_month") },
196198
];
197199
}
198200

@@ -259,27 +261,21 @@ export default class AiUsage extends Component {
259261
<div class="ai-usage__filters-dates">
260262
<div class="ai-usage__period-buttons">
261263
{{#each this.periodOptions as |option|}}
262-
<button
263-
type="button"
264-
class="btn
265-
{{if
264+
<DButton
265+
class="{{if
266266
(eq this.selectedPeriod option.id)
267267
'btn-primary'
268268
'btn-default'
269269
}}"
270-
{{on "click" (fn this.onPeriodSelect option.id)}}
271-
>
272-
{{option.name}}
273-
</button>
270+
@action={{fn this.onPeriodSelect option.id}}
271+
@translatedLabel={{option.name}}
272+
/>
274273
{{/each}}
275-
<button
276-
type="button"
277-
class="btn
278-
{{if this.isCustomDateActive 'btn-primary' 'btn-default'}}"
279-
{{on "click" this.onCustomDateClick}}
280-
>
281-
Custom...
282-
</button>
274+
<DButton
275+
class="{{if this.isCustomDateActive 'btn-primary' 'btn-default'}}"
276+
@action={{this.onCustomDateClick}}
277+
@label="discourse_ai.usage.periods.custom"
278+
/>
283279
</div>
284280

285281
{{#if this.isCustomDateActive}}
@@ -293,13 +289,7 @@ export default class AiUsage extends Component {
293289
@showToTime={{false}}
294290
/>
295291

296-
<button
297-
type="button"
298-
class="btn btn-default"
299-
{{on "click" this.onRefreshDateRange}}
300-
>
301-
{{i18n "refresh"}}
302-
</button>
292+
<DButton @action={{this.onRefreshDateRange}} @label="refresh" />
303293
</div>
304294
{{/if}}
305295
</div>
@@ -323,67 +313,81 @@ export default class AiUsage extends Component {
323313
</div>
324314

325315
{{#if this.data}}
326-
<div class="ai-usage__summary">
327-
<h3 class="ai-usage__summary-title">
328-
{{i18n "discourse_ai.usage.summary"}}
329-
</h3>
330-
<div class="ai-usage__summary-stats">
331-
<div class="ai-usage__summary-stat">
332-
<span class="label">{{i18n
333-
"discourse_ai.usage.total_requests"
334-
}}</span>
335-
<span class="value">{{this.data.summary.total_requests}}</span>
336-
</div>
337-
<div class="ai-usage__summary-stat">
338-
<span class="label">{{i18n
339-
"discourse_ai.usage.total_tokens"
340-
}}</span>
341-
<span class="value">{{this.data.summary.total_tokens}}</span>
342-
</div>
343-
<div class="ai-usage__summary-stat">
344-
<span class="label">{{i18n
345-
"discourse_ai.usage.request_tokens"
346-
}}</span>
347-
<span
348-
class="value"
349-
>{{this.data.summary.total_request_tokens}}</span>
350-
</div>
351-
<div class="ai-usage__summary-stat">
352-
<span class="label">{{i18n
353-
"discourse_ai.usage.response_tokens"
354-
}}</span>
355-
<span
356-
class="value"
357-
>{{this.data.summary.total_response_tokens}}</span>
316+
<AdminConfigAreaCard
317+
@heading="discourse_ai.usage.summary"
318+
class="ai-usage__summary"
319+
>
320+
<:content>
321+
<div class="ai-usage__summary-stats">
322+
<div class="ai-usage__summary-stat">
323+
<span class="label">{{i18n
324+
"discourse_ai.usage.total_requests"
325+
}}</span>
326+
<span
327+
class="value"
328+
title={{this.data.summary.total_requests}}
329+
>{{number this.data.summary.total_requests}}</span>
330+
</div>
331+
<div class="ai-usage__summary-stat">
332+
<span class="label">{{i18n
333+
"discourse_ai.usage.total_tokens"
334+
}}</span>
335+
<span
336+
class="value"
337+
title={{this.data.summary.total_tokens}}
338+
>{{number this.data.summary.total_tokens}}</span>
339+
</div>
340+
<div class="ai-usage__summary-stat">
341+
<span class="label">{{i18n
342+
"discourse_ai.usage.request_tokens"
343+
}}</span>
344+
<span
345+
class="value"
346+
title={{this.data.summary.total_request_tokens}}
347+
>{{number this.data.summary.total_request_tokens}}</span>
348+
</div>
349+
<div class="ai-usage__summary-stat">
350+
<span class="label">{{i18n
351+
"discourse_ai.usage.response_tokens"
352+
}}</span>
353+
<span
354+
class="value"
355+
title={{this.data.summary.total_response_tokens}}
356+
>{{number this.data.summary.total_response_tokens}}</span>
357+
</div>
358+
<div class="ai-usage__summary-stat">
359+
<span class="label">{{i18n
360+
"discourse_ai.usage.cached_tokens"
361+
}}</span>
362+
<span
363+
class="value"
364+
title={{this.data.summary.total_cached_tokens}}
365+
>{{number this.data.summary.total_cached_tokens}}</span>
366+
</div>
358367
</div>
359-
<div class="ai-usage__summary-stat">
360-
<span class="label">{{i18n
361-
"discourse_ai.usage.cached_tokens"
362-
}}</span>
363-
<span
364-
class="value"
365-
>{{this.data.summary.total_cached_tokens}}</span>
368+
</:content>
369+
</AdminConfigAreaCard>
370+
371+
<AdminConfigAreaCard
372+
class="ai-usage__charts"
373+
@heading="discourse_ai.usage.tokens_over_time"
374+
>
375+
<:content>
376+
<div class="ai-usage__chart-container">
377+
<Chart
378+
@chartConfig={{this.chartConfig}}
379+
class="ai-usage__chart"
380+
/>
366381
</div>
367-
</div>
368-
</div>
369-
370-
<div class="ai-usage__charts">
371-
<div class="ai-usage__chart-container">
372-
<h3 class="ai-usage__chart-title">
373-
{{i18n "discourse_ai.usage.tokens_over_time"}}
374-
</h3>
375-
<Chart
376-
@chartConfig={{this.chartConfig}}
377-
class="ai-usage__chart"
378-
/>
379-
</div>
382+
</:content>
383+
</AdminConfigAreaCard>
380384

381-
<div class="ai-usage__breakdowns">
382-
383-
<div class="ai-usage__users">
384-
<h3 class="ai-usage__users-title">
385-
{{i18n "discourse_ai.usage.users_breakdown"}}
386-
</h3>
385+
<div class="ai-usage__breakdowns">
386+
<AdminConfigAreaCard
387+
class="ai-usage__users"
388+
@heading="discourse_ai.usage.users_breakdown"
389+
>
390+
<:content>
387391
<table class="ai-usage__users-table">
388392
<thead>
389393
<tr>
@@ -408,20 +412,25 @@ export default class AiUsage extends Component {
408412
</div></td>
409413
<td
410414
class="ai-usage__users-cell"
411-
>{{user.usage_count}}</td>
415+
title={{user.usage_count}}
416+
>{{number user.usage_count}}</td>
412417
<td
413418
class="ai-usage__users-cell"
414-
>{{user.total_tokens}}</td>
419+
title={{user.total_tokens}}
420+
>{{number user.total_tokens}}</td>
415421
</tr>
416422
{{/each}}
417423
</tbody>
418424
</table>
419-
</div>
420425

421-
<div class="ai-usage__features">
422-
<h3 class="ai-usage__features-title">
423-
{{i18n "discourse_ai.usage.features_breakdown"}}
424-
</h3>
426+
</:content>
427+
</AdminConfigAreaCard>
428+
429+
<AdminConfigAreaCard
430+
class="ai-usage__features"
431+
@heading="discourse_ai.usage.features_breakdown"
432+
>
433+
<:content>
425434
<table class="ai-usage__features-table">
426435
<thead>
427436
<tr>
@@ -438,20 +447,24 @@ export default class AiUsage extends Component {
438447
>{{feature.feature_name}}</td>
439448
<td
440449
class="ai-usage__features-cell"
441-
>{{feature.usage_count}}</td>
450+
title={{feature.usage_count}}
451+
>{{number feature.usage_count}}</td>
442452
<td
443453
class="ai-usage__features-cell"
444-
>{{feature.total_tokens}}</td>
454+
title={{feature.total_tokens}}
455+
>{{number feature.total_tokens}}</td>
445456
</tr>
446457
{{/each}}
447458
</tbody>
448459
</table>
449-
</div>
460+
</:content>
461+
</AdminConfigAreaCard>
450462

451-
<div class="ai-usage__models">
452-
<h3 class="ai-usage__models-title">
453-
{{i18n "discourse_ai.usage.models_breakdown"}}
454-
</h3>
463+
<AdminConfigAreaCard
464+
class="ai-usage__models"
465+
@heading="discourse_ai.usage.models_breakdown"
466+
>
467+
<:content>
455468
<table class="ai-usage__models-table">
456469
<thead>
457470
<tr>
@@ -466,16 +479,18 @@ export default class AiUsage extends Component {
466479
<td class="ai-usage__models-cell">{{model.llm}}</td>
467480
<td
468481
class="ai-usage__models-cell"
469-
>{{model.usage_count}}</td>
482+
title={{model.usage_count}}
483+
>{{number model.usage_count}}</td>
470484
<td
471485
class="ai-usage__models-cell"
472-
>{{model.total_tokens}}</td>
486+
title={{model.total_tokens}}
487+
>{{number model.total_tokens}}</td>
473488
</tr>
474489
{{/each}}
475490
</tbody>
476491
</table>
477-
</div>
478-
</div>
492+
</:content>
493+
</AdminConfigAreaCard>
479494
</div>
480495
{{/if}}
481496
</div>

assets/stylesheets/modules/llms/common/usage.scss

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@
6060

6161
&__summary {
6262
margin: 2em 0;
63-
padding: 1.5em;
64-
background: var(--primary-very-low);
65-
border-radius: 0.5em;
6663
}
6764

6865
&__summary-title {
@@ -81,7 +78,7 @@
8178
display: flex;
8279
flex-direction: column;
8380
padding: 1em;
84-
background: var(--secondary);
81+
background: var(--primary-very-low);
8582
border-radius: 0.25em;
8683

8784
.label {
@@ -124,20 +121,6 @@
124121
}
125122
}
126123

127-
&__features,
128-
&__users,
129-
&__models {
130-
background: var(--primary-very-low);
131-
padding: 1em;
132-
border-radius: 0.5em;
133-
}
134-
135-
&__features-title,
136-
&__users-title,
137-
&__models-title {
138-
margin-bottom: 1em;
139-
}
140-
141124
&__features-table,
142125
&__users-table,
143126
&__models-table {

0 commit comments

Comments
 (0)