mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-19 21:52:15 +01:00
Updated dependencies; Added widgets and charts
This commit is contained in:
committed by
Constantin Graf
parent
b5a240cb2f
commit
2862033321
@@ -101,8 +101,7 @@ class UserResource extends Resource
|
|||||||
->boolean(),
|
->boolean(),
|
||||||
Tables\Columns\TextColumn::make('created_at')
|
Tables\Columns\TextColumn::make('created_at')
|
||||||
->dateTime()
|
->dateTime()
|
||||||
->sortable()
|
->sortable(),
|
||||||
->toggleable(isToggledHiddenByDefault: true),
|
|
||||||
Tables\Columns\TextColumn::make('updated_at')
|
Tables\Columns\TextColumn::make('updated_at')
|
||||||
->dateTime()
|
->dateTime()
|
||||||
->sortable()
|
->sortable()
|
||||||
|
|||||||
42
app/Filament/Widgets/ActiveUserOverview.php
Normal file
42
app/Filament/Widgets/ActiveUserOverview.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
||||||
|
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
class ActiveUserOverview extends BaseWidget
|
||||||
|
{
|
||||||
|
protected static ?string $heading = 'A Registrations';
|
||||||
|
|
||||||
|
protected function getCards(): array
|
||||||
|
{
|
||||||
|
$usersCount = User::query()->where('is_placeholder', '=', false)->count();
|
||||||
|
$placeholderUserCount = User::query()->where('is_placeholder', '=', true)->count();
|
||||||
|
$activeInLastWeek = User::query()
|
||||||
|
->where('is_placeholder', '=', false)
|
||||||
|
->whereHas('timeEntries', function (Builder $query) {
|
||||||
|
$query->where('created_at', '>=', now()->subWeek())
|
||||||
|
->orWhere('updated_at', '>=', now()->subWeek());
|
||||||
|
})
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return [
|
||||||
|
Stat::make('Total', $usersCount)
|
||||||
|
->color('primary')
|
||||||
|
->description('Total real users'),
|
||||||
|
|
||||||
|
Stat::make('Placeholder', $placeholderUserCount)
|
||||||
|
->color('danger')
|
||||||
|
->description('Placeholder users'),
|
||||||
|
|
||||||
|
Stat::make('Active', $activeInLastWeek)
|
||||||
|
->color('success')
|
||||||
|
->description('Active users in the last seven days'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
73
app/Filament/Widgets/TimeEntriesCreated.php
Normal file
73
app/Filament/Widgets/TimeEntriesCreated.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\TimeEntry;
|
||||||
|
use Filament\Widgets\ChartWidget;
|
||||||
|
use Flowframe\Trend\Trend;
|
||||||
|
use Flowframe\Trend\TrendValue;
|
||||||
|
|
||||||
|
class TimeEntriesCreated extends ChartWidget
|
||||||
|
{
|
||||||
|
protected static ?string $heading = 'Time Entries Created';
|
||||||
|
|
||||||
|
public ?string $filter = 'week';
|
||||||
|
|
||||||
|
protected function getData(): array
|
||||||
|
{
|
||||||
|
$filter = $this->filter;
|
||||||
|
if ($filter === 'week') {
|
||||||
|
$start = now()->subWeek();
|
||||||
|
} elseif ($filter === 'month') {
|
||||||
|
$start = now()->subMonth();
|
||||||
|
} elseif ($filter === 'year') {
|
||||||
|
$start = now()->subYear();
|
||||||
|
} else {
|
||||||
|
$start = now()->subWeek();
|
||||||
|
}
|
||||||
|
$trend = Trend::model(TimeEntry::class)
|
||||||
|
->between(
|
||||||
|
start: $start,
|
||||||
|
end: now(),
|
||||||
|
)
|
||||||
|
->perDay();
|
||||||
|
|
||||||
|
if ($filter === 'week') {
|
||||||
|
$trend->perDay();
|
||||||
|
} elseif ($filter === 'month') {
|
||||||
|
$trend->perDay();
|
||||||
|
} elseif ($filter === 'year') {
|
||||||
|
$trend->perMonth();
|
||||||
|
} else {
|
||||||
|
$trend->perDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $trend->count();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => self::$heading,
|
||||||
|
'data' => $data->map(fn (TrendValue $value) => $value->aggregate),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'labels' => $data->map(fn (TrendValue $value) => $value->date),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFilters(): ?array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'week' => 'Last week',
|
||||||
|
'month' => 'Last month',
|
||||||
|
'year' => 'Last year',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getType(): string
|
||||||
|
{
|
||||||
|
return 'line';
|
||||||
|
}
|
||||||
|
}
|
||||||
76
app/Filament/Widgets/UserRegistrations.php
Normal file
76
app/Filament/Widgets/UserRegistrations.php
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Filament\Widgets\ChartWidget;
|
||||||
|
use Flowframe\Trend\Trend;
|
||||||
|
use Flowframe\Trend\TrendValue;
|
||||||
|
|
||||||
|
class UserRegistrations extends ChartWidget
|
||||||
|
{
|
||||||
|
protected static ?string $heading = 'User Registrations';
|
||||||
|
|
||||||
|
public ?string $filter = 'week';
|
||||||
|
|
||||||
|
protected function getData(): array
|
||||||
|
{
|
||||||
|
$filter = $this->filter;
|
||||||
|
if ($filter === 'week') {
|
||||||
|
$start = now()->subWeek();
|
||||||
|
} elseif ($filter === 'month') {
|
||||||
|
$start = now()->subMonth();
|
||||||
|
} elseif ($filter === 'year') {
|
||||||
|
$start = now()->subYear();
|
||||||
|
} else {
|
||||||
|
$start = now()->subWeek();
|
||||||
|
}
|
||||||
|
$trend = Trend::query(
|
||||||
|
User::query()
|
||||||
|
->where('is_placeholder', '=', false)
|
||||||
|
)
|
||||||
|
->between(
|
||||||
|
start: $start,
|
||||||
|
end: now(),
|
||||||
|
)
|
||||||
|
->perDay();
|
||||||
|
|
||||||
|
if ($filter === 'week') {
|
||||||
|
$trend->perDay();
|
||||||
|
} elseif ($filter === 'month') {
|
||||||
|
$trend->perDay();
|
||||||
|
} elseif ($filter === 'year') {
|
||||||
|
$trend->perMonth();
|
||||||
|
} else {
|
||||||
|
$trend->perDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $trend->count();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => self::$heading,
|
||||||
|
'data' => $data->map(fn (TrendValue $value) => $value->aggregate),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'labels' => $data->map(fn (TrendValue $value) => $value->date),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFilters(): ?array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'week' => 'Last week',
|
||||||
|
'month' => 'Last month',
|
||||||
|
'year' => 'Last year',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getType(): string
|
||||||
|
{
|
||||||
|
return 'line';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Providers\Filament;
|
namespace App\Providers\Filament;
|
||||||
|
|
||||||
|
use App\Filament\Widgets\ActiveUserOverview;
|
||||||
|
use App\Filament\Widgets\TimeEntriesCreated;
|
||||||
|
use App\Filament\Widgets\UserRegistrations;
|
||||||
use Filament\Http\Middleware\Authenticate;
|
use Filament\Http\Middleware\Authenticate;
|
||||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
@@ -12,7 +15,6 @@ use Filament\Pages;
|
|||||||
use Filament\Panel;
|
use Filament\Panel;
|
||||||
use Filament\PanelProvider;
|
use Filament\PanelProvider;
|
||||||
use Filament\Support\Colors\Color;
|
use Filament\Support\Colors\Color;
|
||||||
use Filament\Widgets;
|
|
||||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||||
@@ -41,7 +43,9 @@ class AdminPanelProvider extends PanelProvider
|
|||||||
])
|
])
|
||||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
||||||
->widgets([
|
->widgets([
|
||||||
Widgets\AccountWidget::class,
|
ActiveUserOverview::class,
|
||||||
|
UserRegistrations::class,
|
||||||
|
TimeEntriesCreated::class,
|
||||||
])
|
])
|
||||||
->plugins([
|
->plugins([
|
||||||
EnvironmentIndicatorPlugin::make()
|
EnvironmentIndicatorPlugin::make()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"brick/money": "^0.8.1",
|
"brick/money": "^0.8.1",
|
||||||
"dedoc/scramble": "dev-main",
|
"dedoc/scramble": "dev-main",
|
||||||
"filament/filament": "^3.2",
|
"filament/filament": "^3.2",
|
||||||
|
"flowframe/laravel-trend": "^0.2.0",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"inertiajs/inertia-laravel": "^1.0",
|
"inertiajs/inertia-laravel": "^1.0",
|
||||||
"korridor/laravel-computed-attributes": "^3.1",
|
"korridor/laravel-computed-attributes": "^3.1",
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
"wikimedia/composer-merge-plugin": "^2.1.0"
|
"wikimedia/composer-merge-plugin": "^2.1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"barryvdh/laravel-ide-helper": "^3.0",
|
||||||
"brianium/paratest": "^7.3",
|
"brianium/paratest": "^7.3",
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
"fumeapp/modeltyper": "^2.2",
|
"fumeapp/modeltyper": "^2.2",
|
||||||
@@ -93,6 +95,10 @@
|
|||||||
],
|
],
|
||||||
"fix": [
|
"fix": [
|
||||||
"@php pint"
|
"@php pint"
|
||||||
|
],
|
||||||
|
"ide-helper": [
|
||||||
|
"@php artisan ide-helper:generate",
|
||||||
|
"@php artisan ide-helper:meta"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
|
|||||||
849
composer.lock
generated
849
composer.lock
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user