Skip to content

Commit 3945000

Browse files
authored
Merge branch 'master' into dev
2 parents beb014e + c6334de commit 3945000

12 files changed

Lines changed: 244 additions & 103 deletions

File tree

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,6 @@ All this made with the best technologies.
7676

7777
Full documentation can be viewed online: [Docs](https://devaslanphp.github.io/project-management)
7878

79-
## Online Demo
80-
81-
You can see the application in action here: [https://project-helper.net](https://project-helper.net)
82-
8379
## Work in progress
8480

8581
We are always working to make Project Management a better application, all contributions are welcome.
@@ -135,8 +131,8 @@ The MIT License (MIT). Please see [License File](LICENSE.md) for more informatio
135131
- Add jira integration #36
136132
- New feature: Import jira projects / tickets
137133
- **Release 1.2.2**
138-
- Add jira integration #36
139-
- New feature: Import jira projects / tickets
134+
- Dockerize application #23
135+
- PR #45
140136
- **Release 1.2.3**
141137
- Update german language #52
142138
- SSO with OpenID (OIDC) #48

app/Filament/Pages/TimesheetDashboard.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@
44

55
use App\Filament\Widgets\Timesheet\ActivitiesReport;
66
use App\Filament\Widgets\Timesheet\MonthlyReport;
7+
use App\Filament\Widgets\Timesheet\WeeklyReport;
78
use Filament\Pages\Page;
89

910
class TimesheetDashboard extends Page
1011
{
1112
protected static ?string $slug = 'timesheet-dashboard';
1213

13-
protected static ?int $navigationSort = 1;
14+
protected static ?int $navigationSort = 2;
1415

1516
protected static string $view = 'filament::pages.dashboard';
1617

17-
protected static bool $shouldRegisterNavigation = false;
18-
1918
protected function getColumns(): int | array
2019
{
2120
return 6;
@@ -31,11 +30,17 @@ protected static function getNavigationGroup(): ?string
3130
return __('Timesheet');
3231
}
3332

33+
protected static function shouldRegisterNavigation(): bool
34+
{
35+
return auth()->user()->can('View timesheet dashboard');
36+
}
37+
3438
protected function getWidgets(): array
3539
{
3640
return [
3741
MonthlyReport::class,
38-
ActivitiesReport::class
42+
ActivitiesReport::class,
43+
WeeklyReport::class
3944
];
4045
}
4146
}

app/Filament/Resources/TimesheetResource.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ class TimesheetResource extends Resource
2323

2424
protected static ?int $navigationSort = 4;
2525

26-
protected static bool $shouldRegisterNavigation = false;
27-
2826
protected static function getNavigationLabel(): string
2927
{
3028
return __('Timesheet');
@@ -40,6 +38,11 @@ protected static function getNavigationGroup(): ?string
4038
return __('Timesheet');
4139
}
4240

41+
protected static function shouldRegisterNavigation(): bool
42+
{
43+
return auth()->user()->can('List timesheet data');
44+
}
45+
4346
public static function form(Form $form): Form
4447
{
4548
return $form

app/Filament/Widgets/Timesheet/ActivitiesReport.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ActivitiesReport extends BarChartWidget
2020
];
2121

2222
public ?string $filter = '2023';
23-
23+
2424
protected function getHeading(): string
2525
{
2626
return __('Logged time by activity');
@@ -68,7 +68,7 @@ protected function getDatasets(Collection $collection): array
6868

6969
foreach ($collection as $item) {
7070
$datasets['sets'][] = $item->value;
71-
$datasets['labels'][] = $item->activity->name;
71+
$datasets['labels'][] = $item->activity?->name ?? __('No activity');
7272
}
7373

7474
return $datasets;

app/Filament/Widgets/Timesheet/MonthlyReport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ protected function filter(User $user, array $params)
7777
DB::raw("YEAR(created_at)=" . (is_null($params['year']) ? Carbon::now()->format('Y') : $params['year']))
7878
)
7979
->where('user_id', $user->id)
80-
->groupBy(DB::raw("DATE_FORMAT (created_at, '%m')"))
80+
->groupBy(DB::raw("DATE_FORMAT(created_at,'%m')"))
8181
->get();
8282
}
8383

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Filament\Widgets\Timesheet;
6+
7+
use App\Models\TicketHour;
8+
use App\Models\User;
9+
use Carbon\Carbon;
10+
use Carbon\CarbonPeriod;
11+
use Filament\Widgets\BarChartWidget;
12+
use Illuminate\Database\Eloquent\Collection;
13+
use Illuminate\Support\Facades\DB;
14+
15+
class WeeklyReport extends BarChartWidget
16+
{
17+
protected int|string|array $columnSpan = [
18+
'sm' => 1,
19+
'md' => 6,
20+
'lg' => 3
21+
];
22+
23+
protected function getData(): array
24+
{
25+
$now = Carbon::now();
26+
27+
$weekStartDate = $now->startOfWeek()->format('Y-m-d');
28+
$weekEndDate = $now->endOfWeek()->format('Y-m-d');
29+
30+
$collection = $this->filter(auth()->user(), [
31+
'year' => null,
32+
'weekStartDate' => $weekStartDate,
33+
'weekEndDate' => $weekEndDate
34+
]);
35+
36+
$dates = $this->buildDatesRange($weekStartDate, $weekEndDate);
37+
38+
$datasets = $this->buildRapport($collection, $dates);
39+
40+
return [
41+
'datasets' => [
42+
[
43+
'label' => __('Weekly time logged'),
44+
'data' => $datasets,
45+
'backgroundColor' => [
46+
'rgba(54, 162, 235, .6)'
47+
],
48+
'borderColor' => [
49+
'rgba(54, 162, 235, .8)'
50+
],
51+
],
52+
],
53+
'labels' => $dates,
54+
];
55+
}
56+
57+
protected function buildRapport(Collection $collection, array $dates): array
58+
{
59+
$template = $this->createReportTemplate($dates);
60+
foreach ($collection as $item) {
61+
$template[$item->day]['value'] = $item->value;
62+
}
63+
return collect($template)->pluck('value')->toArray();
64+
}
65+
66+
protected function filter(User $user, array $params)
67+
{
68+
return TicketHour::select([
69+
DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d') as day"),
70+
DB::raw('SUM(value) as value'),
71+
])
72+
->whereBetween('created_at', [$params['weekStartDate'], $params['weekEndDate']])
73+
->whereRaw(
74+
DB::raw("YEAR(created_at)=" . (is_null($params['year']) ? Carbon::now()->format('Y') : $params['year']))
75+
)
76+
->where('user_id', $user->id)
77+
->groupBy(DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d')"))
78+
->get();
79+
}
80+
81+
protected function buildDatesRange($weekStartDate, $weekEndDate): array
82+
{
83+
$period = CarbonPeriod::create($weekStartDate, $weekEndDate);
84+
85+
$dates = [];
86+
foreach ($period as $item) {
87+
$dates[] = $item->format('Y-m-d');
88+
}
89+
90+
return $dates;
91+
}
92+
93+
protected function createReportTemplate(array $dates): array
94+
{
95+
$template = [];
96+
foreach ($dates as $date) {
97+
$template[$date]['value'] = 0;
98+
}
99+
return $template;
100+
}
101+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Livewire\Timesheet;
6+
7+
use App\Models\Ticket;
8+
use Filament\Tables;
9+
use Filament\Tables\Concerns\InteractsWithTable;
10+
use Filament\Tables\Contracts\HasTable;
11+
use Illuminate\Database\Eloquent\Builder;
12+
use Illuminate\Database\Eloquent\Model;
13+
use Livewire\Component;
14+
15+
class TimeLogged extends Component implements HasTable
16+
{
17+
use InteractsWithTable;
18+
19+
public Ticket $ticket;
20+
21+
protected function getFormModel(): Model|string|null
22+
{
23+
return $this->ticket;
24+
}
25+
26+
protected function getTableQuery(): Builder
27+
{
28+
return $this->ticket->hours()->getQuery();
29+
}
30+
31+
protected function getTableColumns(): array
32+
{
33+
return [
34+
Tables\Columns\TextColumn::make('user.name')
35+
->label(__('Owner'))
36+
->sortable()
37+
->formatStateUsing(fn($record) => view('components.user-avatar', ['user' => $record->user]))
38+
->searchable(),
39+
40+
Tables\Columns\TextColumn::make('value')
41+
->label(__('Hours'))
42+
->sortable()
43+
->searchable(),
44+
Tables\Columns\TextColumn::make('comment')
45+
->label(__('Comment'))
46+
->limit(50)
47+
->sortable()
48+
->searchable(),
49+
50+
Tables\Columns\TextColumn::make('activity.name')
51+
->label(__('Activity'))
52+
->sortable(),
53+
54+
Tables\Columns\TextColumn::make('ticket.name')
55+
->label(__('Ticket'))
56+
->sortable(),
57+
58+
Tables\Columns\TextColumn::make('created_at')
59+
->label(__('Created at'))
60+
->dateTime()
61+
->sortable()
62+
->searchable(),
63+
];
64+
}
65+
}

database/seeders/PermissionsSeeder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ class PermissionsSeeder extends Seeder
2727
];
2828

2929
private array $extraPermissions = [
30-
'Manage general settings', 'Import from Jira'
30+
'Manage general settings', 'Import from Jira',
31+
'List timesheet data', 'View timesheet dashboard'
3132
];
3233

3334
private string $defaultRole = 'Default role';

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ services:
2323
timeout: 10s
2424
retries: 3
2525
helper:
26-
image: devaslanphp/helper:latest
26+
image: eloufirhatim/helper:latest
2727
container_name: helper-server
2828
environment:
2929
- DB_CONNECTION=mysql

0 commit comments

Comments
 (0)