The project form gets «Crear en TaskStream» while the project has no board, and `taskstream: true` on a PATCH does the same through the API. A refusal leaves the edit unsaved; a project with a board keeps it, and `taskstream_key` without the flag is still ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
111 lines
4.3 KiB
PHP
111 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Resources\Projects\Pages;
|
|
|
|
use App\Actions\Projects\OpenInTaskStream;
|
|
use App\Filament\Concerns\WarnsOfConcurrentEditing;
|
|
use App\Filament\Resources\Projects\ProjectResource;
|
|
use App\Filament\Support\DuplicateAction;
|
|
use App\Filament\Support\PreviewAction;
|
|
use App\Filament\Support\TranslateAction;
|
|
use App\Services\Pireon\TokenStore;
|
|
use App\Services\TaskStream\TaskStreamClient;
|
|
use Filament\Actions\Action;
|
|
use Filament\Actions\DeleteAction;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Resources\Pages\EditRecord;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
|
|
class EditProject extends EditRecord
|
|
{
|
|
use WarnsOfConcurrentEditing;
|
|
|
|
protected static string $resource = ProjectResource::class;
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
// Seeing it on the real site without leaving the form.
|
|
PreviewAction::for('project'),
|
|
Action::make('taskstream')
|
|
->label(__('panel.projects.taskstream.open'))
|
|
->icon('heroicon-o-arrow-top-right-on-square')
|
|
->color('gray')
|
|
->url(fn () => app(TaskStreamClient::class)->projectUrl((string) $this->record->taskstream_key))
|
|
->openUrlInNewTab()
|
|
->visible(fn () => filled($this->record->taskstream_key)),
|
|
$this->createInTaskStream(),
|
|
DuplicateAction::make(),
|
|
TranslateAction::make(),
|
|
DeleteAction::make(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* For a project made without a board: opens one now, as the person
|
|
* signed in, and saves only the link (whatever is being edited in the
|
|
* form stays as it is, unsaved).
|
|
*/
|
|
protected function createInTaskStream(): Action
|
|
{
|
|
return Action::make('createInTaskStream')
|
|
->label(__('panel.projects.taskstream.create'))
|
|
->icon('heroicon-o-plus')
|
|
->color('gray')
|
|
->visible(fn () => blank($this->record->taskstream_key))
|
|
->authorize('update')
|
|
->modalHeading(__('panel.projects.taskstream.create_heading'))
|
|
->modalDescription(__('panel.projects.taskstream.section_hint'))
|
|
->modalSubmitActionLabel(__('panel.projects.taskstream.create'))
|
|
->schema([
|
|
TextInput::make('key')
|
|
->label(__('panel.projects.taskstream.key'))
|
|
->helperText(__('panel.projects.taskstream.key_hint'))
|
|
->placeholder(fn () => app(OpenInTaskStream::class)
|
|
->keyFrom((string) $this->record->getTranslation('slug', (string) config('locales.default'), false)))
|
|
->maxLength(10)
|
|
->regex('/^[A-Za-z][A-Za-z0-9]{1,9}$/'),
|
|
])
|
|
->action(function (array $data, Action $action): void {
|
|
$project = $this->record;
|
|
|
|
try {
|
|
app(OpenInTaskStream::class)->handle(
|
|
$project,
|
|
Auth::user(),
|
|
app(TokenStore::class)->accessToken(),
|
|
filled($data['key'] ?? null) ? $data['key'] : null,
|
|
);
|
|
} catch (ValidationException|HttpException $e) {
|
|
// The modal stays open, to change the key and try again.
|
|
Notification::make()
|
|
->danger()
|
|
->title($e instanceof ValidationException ? collect($e->errors())->flatten()->first() : $e->getMessage())
|
|
->send();
|
|
|
|
$action->halt();
|
|
}
|
|
|
|
$project->save();
|
|
|
|
$url = app(TaskStreamClient::class)->projectUrl((string) $project->taskstream_key);
|
|
|
|
Notification::make()
|
|
->success()
|
|
->title(__('panel.projects.taskstream.created', ['url' => $url]))
|
|
->actions([
|
|
Action::make('taskstream')
|
|
->label(__('panel.projects.taskstream.open'))
|
|
->url($url, shouldOpenInNewTab: true),
|
|
])
|
|
->persistent()
|
|
->send();
|
|
});
|
|
}
|
|
}
|