Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 73 additions & 9 deletions app/Filament/Pages/JiraImport.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
use App\Settings\JiraSettings;

class JiraImport extends Page implements HasForms
{
Expand Down Expand Up @@ -48,10 +49,17 @@ class JiraImport extends Page implements HasForms
public $selected_tickets;
public $data = [];
public $ticketsDataApi;
public $epicKeys = [];
public $taskKeys = [];

public function mount(): void
{
$this->form->fill();
$settings = app(JiraSettings::class);
$this->form->fill([
'host' => $settings->host,
'username' => $settings->username,
'token' => $settings->token,
]);
}

public static function shouldRegisterNavigation(): bool
Expand Down Expand Up @@ -87,7 +95,7 @@ public function getFormSchema(): array
'class' => 'bg-primary-500 rounded-lg border border-primary-600 text-white font-medium text-sm py-3 px-4'
])
->hiddenLabel()
->content(__('Important: Your jira credentials are only used to communicate with jira REST API, and will not be stored in this application')),
->content(__('Your Jira credentials are used to communicate with the Jira REST API. They will be saved (with the API token encrypted) so you do not need to re-enter them each time.')),

Grid::make()
->schema([
Expand All @@ -109,8 +117,14 @@ public function getFormSchema(): array
]),
])
->afterValidation(function () {
$settings = app(JiraSettings::class);
$settings->host = $this->host;
$settings->username = $this->username;
$settings->token = $this->token;
$settings->save();

$this->loadingProjects = true;
$this->emit('updateJiraProjects');
$this->dispatch('updateJiraProjects');
}),

Wizard\Step::make(__('Jira projects'))
Expand Down Expand Up @@ -164,7 +178,7 @@ public function getFormSchema(): array
])
->afterValidation(function () {
$this->loadingTickets = true;
$this->emit('updateJiraTickets');
$this->dispatch('updateJiraTickets');
}),

Wizard\Step::make(__('Jira tickets'))
Expand All @@ -187,6 +201,18 @@ public function getFormSchema(): array
->visible(fn() => $this->loadingTickets)
->content(__('Loading tickets, please wait...'));

if (!$this->loadingTickets && $this->tickets) {
$fields[] = Placeholder::make('selection_buttons')
->hiddenLabel()
->content(new HtmlString(
"<div class='flex items-center gap-2'>"
. "<button type='button' wire:click='selectAllEpics' class='px-3 py-1.5 rounded-md text-xs font-bold bg-purple-600 text-white shadow-sm hover:bg-purple-700'>" . __('Select All Epics') . "</button>"
. "<button type='button' wire:click='selectAllTasks' class='px-3 py-1.5 rounded-md text-xs font-bold bg-primary-600 text-white shadow-sm hover:bg-primary-700'>" . __('Select All Tasks') . "</button>"
. "<button type='button' wire:click='deselectAll' class='px-3 py-1.5 rounded-md text-xs font-bold bg-gray-400 text-white shadow-sm hover:bg-gray-500'>" . __('Deselect All') . "</button>"
. "</div>"
));
}

if (!$this->loadingTickets) {
if ($this->tickets) {
foreach ($this->tickets as $projectKey => $ticket) {
Expand All @@ -201,9 +227,13 @@ public function getFormSchema(): array
foreach ($ticket['issues'] as $issue) {
$fields[] = Checkbox::make('data.' . Str::slug($projectKey) . '_' . Str::slug($issue['code']))
->label(function () use ($issue) {
$epicBadge = !empty($issue['isEpic'])
? "<span class='inline-flex items-center px-2.5 py-1 rounded-md text-xs font-bold bg-purple-600 text-white shadow-sm'>EPIC</span> "
: '';
return new HtmlString(
"<div class='w-full flex flex-col gap-1'>"
. "<div class='w-full flex items-center gap-1'>"
. $epicBadge
. "<div class='text-gray-700 text-xs font-light'><span class='font-medium uppercase'>" . $issue['code'] . "</span> " . $issue['name'] . "</div>"
. "</div>"
. "</div>"
Expand Down Expand Up @@ -239,8 +269,13 @@ public function import(): void
if ($this->data && sizeof($this->data)) {
$tickets = [];
foreach (array_keys($this->data) as $item) {
$url = $this->ticketsDataApi[$item];
$tickets[] = $this->getJiraTicketDetails($this->host, $this->username, $this->token, $url);
$url = $this->ticketsDataApi[$item] ?? null;
if ($url) {
$ticket = $this->getJiraTicketDetails($this->host, $this->username, $this->token, $url);
if ($ticket) {
$tickets[] = $ticket;
}
}
}
dispatch(new ImportJiraTicketsJob($tickets, auth()->user()));
Notification::make()
Expand All @@ -266,13 +301,42 @@ public function updateJiraProjects(): void
public function updateJiraTickets(): void
{
$this->ticketsDataApi = [];
$this->epicKeys = [];
$this->taskKeys = [];
$client = $this->connectToJira($this->host, $this->username, $this->token);
$this->tickets = $this->getJiraTicketsByProject($client, $this->selected_projects);
foreach ($this->tickets as $projectKey => $ticket) {
foreach ($ticket['issues'] as $issue) {
$this->ticketsDataApi[Str::slug($projectKey) . '_' . Str::slug($issue['code'])] = $issue['data']->self;
if ($this->tickets) {
foreach ($this->tickets as $projectKey => $ticket) {
foreach ($ticket['issues'] as $issue) {
$key = Str::slug($projectKey) . '_' . Str::slug($issue['code']);
$this->ticketsDataApi[$key] = $issue['data']->self;
if (!empty($issue['isEpic'])) {
$this->epicKeys[] = $key;
} else {
$this->taskKeys[] = $key;
}
}
}
}
$this->loadingTickets = false;
}

public function selectAllEpics(): void
{
foreach ($this->epicKeys as $key) {
$this->data[$key] = true;
}
}

public function selectAllTasks(): void
{
foreach ($this->taskKeys as $key) {
$this->data[$key] = true;
}
}

public function deselectAll(): void
{
$this->data = [];
}
}
77 changes: 77 additions & 0 deletions app/Filament/Pages/ManageJiraSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace App\Filament\Pages;
use BackedEnum;

use App\Settings\JiraSettings;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Schema;
use Filament\Forms\Components\TextInput;
use Filament\Actions\Action;
use Filament\Pages\SettingsPage;
use Filament\Support\Enums\Width;
use Illuminate\Contracts\Support\Htmlable;

class ManageJiraSettings extends SettingsPage
{
protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-cloud-arrow-up';

protected static string $settings = JiraSettings::class;

protected Width | string | null $maxContentWidth = Width::Full;

public static function shouldRegisterNavigation(): bool
{
return auth()->user()->can('Import from Jira');
}

public function getHeading(): string|Htmlable
{
return __('Manage Jira settings');
}

public static function getNavigationLabel(): string
{
return __('Jira');
}

public static function getNavigationGroup(): ?string
{
return __('Settings');
}

public function form(Schema $schema): Schema
{
return $schema->columns(1)->components([
Section::make(__('Jira credentials'))
->description(__('Configure your Jira connection credentials. The API token is stored encrypted.'))
->columnSpanFull()
->schema([
Grid::make(2)
->schema([
TextInput::make('host')
->label(__('Host'))
->helperText(__('The URL used to access your Jira account (e.g. https://yourcompany.atlassian.net)'))
->required(),

TextInput::make('username')
->label(__('Username'))
->helperText(__('Your Jira account username (email)'))
->required(),

TextInput::make('token')
->label(__('API Token'))
->helperText(__('Your Jira account API token'))
->password()
->required(),
]),
]),
]);
}

public function getSaveFormAction(): Action
{
return parent::getSaveFormAction()->label(__('Save'));
}
}
6 changes: 2 additions & 4 deletions app/Filament/Pages/TimesheetDashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@
use App\Filament\Widgets\Timesheet\ActivitiesReport;
use App\Filament\Widgets\Timesheet\MonthlyReport;
use App\Filament\Widgets\Timesheet\WeeklyReport;
use Filament\Pages\Page;
use Filament\Pages\Dashboard;

class TimesheetDashboard extends Page
class TimesheetDashboard extends Dashboard
{
protected static ?string $slug = 'timesheet-dashboard';

protected static ?int $navigationSort = 2;

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

public function getColumns(): int | array
{
return 6;
Expand Down
4 changes: 2 additions & 2 deletions app/Filament/Resources/TicketResource/Pages/ViewTicket.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ public function getHeaderActions(): array
->label(__('Activity'))
->searchable()
->live()
->options(function (\Filament\Forms\Get $get, \Filament\Forms\Set $set) {
->options(function (\Filament\Schemas\Components\Utilities\Get $get, \Filament\Schemas\Components\Utilities\Set $set) {
return Activity::all()->pluck('name', 'id')->toArray();
}),
Textarea::make('comment')
->label(__('Comment'))
->rows(3),
])
->action(function (Collection $records, array $data): void {
->action(function (array $data): void {
$value = $data['time'];
$comment = $data['comment'];
TicketHour::create([
Expand Down
25 changes: 19 additions & 6 deletions app/Filament/Widgets/Timesheet/ActivitiesReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ class ActivitiesReport extends ChartWidget
'lg' => 3
];

public ?string $filter = '2023';
public ?string $filter = null;

public function mount(): void
{
$this->filter = (string) Carbon::now()->year;
parent::mount();
}

public function getHeading(): string
{
Expand All @@ -33,16 +39,23 @@ public function getType(): string

public function getFilters(): ?array
{
return [
2022 => 2022,
2023 => 2023
];
$currentYear = (int) Carbon::now()->year;
$firstYear = (int) (TicketHour::min('created_at')
? Carbon::parse(TicketHour::min('created_at'))->year
: $currentYear);

$years = [];
for ($year = $firstYear; $year <= $currentYear; $year++) {
$years[(string) $year] = (string) $year;
}

return $years;
}

public function getData(): array
{
$collection = $this->filter(auth()->user(), [
'year' => $this->filter
'year' => $this->filter ?: Carbon::now()->year
]);

$datasets = $this->getDatasets($collection);
Expand Down
23 changes: 18 additions & 5 deletions app/Filament/Widgets/Timesheet/MonthlyReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ public function getHeading(): string
return __('Logged time monthly');
}

public ?string $filter = '2023';
public ?string $filter = null;

public function mount(): void
{
$this->filter = (string) Carbon::now()->year;
parent::mount();
}

public function getType(): string
{
Expand Down Expand Up @@ -52,10 +58,17 @@ public function getData(): array

public function getFilters(): ?array
{
return [
2022 => 2022,
2023 => 2023
];
$currentYear = (int) Carbon::now()->year;
$firstYear = (int) (TicketHour::min('created_at')
? Carbon::parse(TicketHour::min('created_at'))->year
: $currentYear);

$years = [];
for ($year = $firstYear; $year <= $currentYear; $year++) {
$years[(string) $year] = (string) $year;
}

return $years;
}

protected ?array $options = [
Expand Down
12 changes: 8 additions & 4 deletions app/Filament/Widgets/Timesheet/WeeklyReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ class WeeklyReport extends ChartWidget
'lg' => 3
];

public function __construct($id = null)
public function mount(): void
{
$weekDaysData = $this->getWeekStartAndFinishDays();
parent::mount();

$weekDaysData = $this->getWeekStartAndFinishDays();
$this->filter = $weekDaysData['weekStartDate'] . ' - ' . $weekDaysData['weekEndDate'];

parent::__construct($id);
}

public function getHeading(): string
Expand All @@ -41,6 +40,11 @@ public function getType(): string

public function getData(): array
{
if (empty($this->filter) || !str_contains($this->filter, ' - ')) {
$weekDefaults = $this->getWeekStartAndFinishDays();
$this->filter = $weekDefaults['weekStartDate'] . ' - ' . $weekDefaults['weekEndDate'];
}

$weekDaysData = explode(' - ', $this->filter);

$collection = $this->filter(auth()->user(), [
Expand Down
Loading
Loading