11import Component from " @glimmer/component" ;
22import { tracked } from " @glimmer/tracking" ;
33import { fn , hash } from " @ember/helper" ;
4- import { on } from " @ember/modifier" ;
54import { action } from " @ember/object" ;
65import { LinkTo } from " @ember/routing" ;
76import { service } from " @ember/service" ;
87import { eq } from " truth-helpers" ;
8+ import DButton from " discourse/components/d-button" ;
99import DateTimeInputRange from " discourse/components/date-time-input-range" ;
1010import avatar from " discourse/helpers/avatar" ;
1111import { ajax } from " discourse/lib/ajax" ;
12+ import { number } from " discourse/lib/formatter" ;
1213import i18n from " discourse-common/helpers/i18n" ;
14+ import AdminConfigAreaCard from " admin/components/admin-config-area-card" ;
1315import Chart from " admin/components/chart" ;
1416import 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 >
0 commit comments