-
-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add metrics components to frontend
using chartjs to render the chart
- Loading branch information
Sean Connole
committed
Feb 19, 2025
1 parent
023c332
commit 5ca40be
Showing
8 changed files
with
231 additions
and
21 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,20 @@ | ||
import Chart from 'chart.js/auto' | ||
import 'chartjs-adapter-moment' | ||
|
||
import Alpine from 'alpinejs' | ||
|
||
import Anchor from '@alpinejs/anchor' | ||
import Collapse from '@alpinejs/collapse' | ||
import Focus from '@alpinejs/focus' | ||
import Ui from '@alpinejs/ui' | ||
|
||
Chart.defaults.color = '#fff' | ||
window.Chart = Chart | ||
|
||
Alpine.plugin(Anchor) | ||
Alpine.plugin(Collapse) | ||
Alpine.plugin(Focus) | ||
Alpine.plugin(Ui) | ||
|
||
window.Alpine = Alpine | ||
Alpine.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
@props([ | ||
'metric', | ||
]) | ||
|
||
@use('\Cachet\Enums\MetricViewEnum') | ||
|
||
<div x-data="chart"> | ||
<div class="flex flex-col gap-2"> | ||
<div class="flex items-center gap-1.5"> | ||
<div class="font-semibold leading-6">{{ $metric->name }}</div> | ||
|
||
<div x-data x-popover class="flex items-center"> | ||
<button x-ref="anchor" x-popover:button> | ||
<x-heroicon-o-question-mark-circle class="size-4 text-zinc-500 dark:text-zinc-300" /> | ||
</button> | ||
<div x-popover:panel x-cloak x-transition.opacity x-anchor.right.offset.8="$refs.anchor" class="rounded bg-white px-2 py-1 text-xs font-medium text-zinc-800 drop-shadow dark:text-zinc-800"> | ||
<span class="pointer-events-none absolute -left-1 top-1.5 size-4 rotate-45 bg-white"></span> | ||
<p class="relative">{{ $metric->description }}</p> | ||
</div> | ||
</div> | ||
|
||
<!-- Period Selector --> | ||
<select x-model="period" class="ml-auto rounded-md border border-gray-300 bg-white text-sm font-medium text-gray-900 dark:border-gray-700 dark:bg-zinc-800 dark:text-gray-100"> | ||
@foreach ([MetricViewEnum::last_hour, MetricViewEnum::today, MetricViewEnum::week, MetricViewEnum::month] as $value) | ||
<option value="{{ $value }}">{{ $value->getLabel() }}</option> | ||
@endforeach | ||
</select> | ||
</div> | ||
<canvas x-ref="canvas" height="300" class="rounded-md bg-white text-white shadow-sm ring-1 ring-gray-900/5 dark:bg-zinc-800 dark:ring-gray-100/10"></canvas> | ||
</div> | ||
</div> | ||
|
||
<script> | ||
document.addEventListener('alpine:init', () => { | ||
Alpine.data('chart', () => ({ | ||
metric: {{ Js::from($metric) }}, | ||
period: {{ Js::from($metric->default_view) }}, | ||
points: [[], [], [], []], | ||
chart: null, | ||
init, | ||
})) | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<script> | ||
const now = new Date() | ||
const previousHour = new Date(now - 60 * 60 * 1000) | ||
const previous24Hours = new Date(now - 24 * 60 * 60 * 1000) | ||
const previous7Days = new Date(now - 7 * 24 * 60 * 60 * 1000) | ||
const previous30Days = new Date(now - 30 * 24 * 60 * 60 * 1000) | ||
function init() { | ||
// Parse metric points | ||
const metricPoints = this.metric.metric_points.map((point) => { | ||
return { | ||
x: new Date(point.x), | ||
y: point.y, | ||
} | ||
}) | ||
// Filter points based on the selected period | ||
this.points[0] = metricPoints.filter((point) => point.x >= previousHour) | ||
this.points[1] = metricPoints.filter((point) => point.x >= previous24Hours) | ||
this.points[2] = metricPoints.filter((point) => point.x >= previous7Days) | ||
this.points[3] = metricPoints.filter((point) => point.x >= previous30Days) | ||
// Initialize chart | ||
const chart = new Chart(this.$refs.canvas, { | ||
type: 'line', | ||
data: { | ||
datasets: [ | ||
{ | ||
label: this.metric.suffix, | ||
data: this.points[this.period], | ||
fill: false, | ||
borderColor: 'rgb(75, 192, 192)', | ||
tension: 0.1, | ||
}, | ||
], | ||
}, | ||
options: { | ||
scales: { | ||
x: { | ||
type: 'timeseries', | ||
}, | ||
}, | ||
}, | ||
}) | ||
this.$watch('period', () => { | ||
chart.data.datasets[0].data = this.points[this.period] | ||
chart.update() | ||
}) | ||
} | ||
</script> | ||
|
||
<div class="flex flex-col gap-8"> | ||
@foreach ($metrics as $metric) | ||
<x-cachet::metric :metric="$metric" /> | ||
@endforeach | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace Cachet\View\Components; | ||
|
||
use Cachet\Models\Metric; | ||
use Cachet\Settings\AppSettings; | ||
use Illuminate\Contracts\View\View; | ||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Support\Carbon; | ||
use Illuminate\Support\Collection; | ||
use Illuminate\View\Component; | ||
|
||
class Metrics extends Component | ||
{ | ||
public function __construct(private AppSettings $appSettings) | ||
Check failure on line 15 in src/View/Components/Metrics.php
|
||
{ | ||
// | ||
} | ||
|
||
public function render(): View | ||
{ | ||
$startDate = Carbon::now()->subDays(30); | ||
|
||
$metrics = $this->metrics($startDate); | ||
|
||
// Convert each metric point to Chart.js format (x, y) | ||
$metrics->each(function ($metric) { | ||
$metric->metricPoints->transform(fn ($point) => [ | ||
'x' => $point->created_at->toIso8601String(), | ||
'y' => $point->value, | ||
]); | ||
}); | ||
|
||
return view('cachet::components.metrics', [ | ||
'metrics' => $metrics | ||
]); | ||
} | ||
|
||
/** | ||
* Fetch the available metrics and their points. | ||
*/ | ||
private function metrics(Carbon $startDate): Collection | ||
{ | ||
return Metric::query() | ||
->with([ | ||
'metricPoints' => fn ($query) => $query->orderBy('created_at'), | ||
]) | ||
->where('visible', '>=', !auth()->check()) | ||
->whereHas('metricPoints', fn (Builder $query) => $query->where('created_at', '>=', $startDate)) | ||
->orderBy('places', 'asc') | ||
->get(); | ||
} | ||
} |