feature: add Livewire configuration and extend ConnectedApp management with delete, create, and enhanced UI integration
- Introduced `livewire.php` for customizable Livewire configuration. - Enhanced ConnectedApp management by adding delete functionality and dynamic navigation handling (`goBack()`). - Updated forms (`create`, `edit`) with `maryUI` components (`mary-form`, `mary-button`, `mary-input`, `mary-choices`). - Consolidated provider imports and refactored UI for reusability and improved styling. - Improved exception handling and validation rules in `ConnectedAppService` and Livewire components.
This commit is contained in:
parent
c0086ddb6a
commit
092ee0083e
@ -7,9 +7,9 @@
|
||||
use App\Data\ConnectedApp\{ConnectAppRequest, ConnectedAppData};
|
||||
use App\Data\Ui\ConnectedApps\ConnectedAppData as UiConnectedAppData;
|
||||
use App\Models\ConnectedApp;
|
||||
use http\Exception\InvalidArgumentException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use InvalidArgumentException;
|
||||
use Spatie\LaravelData\PaginatedDataCollection;
|
||||
use Throwable;
|
||||
|
||||
@ -18,7 +18,7 @@ final class ConnectedAppService
|
||||
/**
|
||||
* Create a new connected app.
|
||||
*
|
||||
* @throws Throwable
|
||||
* @throws Throwable when an error occurs during the creation.
|
||||
*/
|
||||
public function create(ConnectAppRequest $data): void
|
||||
{
|
||||
@ -29,9 +29,13 @@ public function create(ConnectAppRequest $data): void
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException when id is invalid
|
||||
* @throws Throwable when an error occurs during the update.
|
||||
*/
|
||||
public function update(int $id, ConnectAppRequest $data): void
|
||||
{
|
||||
if (0 === $id) {
|
||||
if ($id <= 0) {
|
||||
throw new InvalidArgumentException('Invalid id');
|
||||
}
|
||||
DB::transaction(
|
||||
@ -41,6 +45,23 @@ public function update(int $id, ConnectAppRequest $data): void
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Throwable when an error occurs during the deletion.
|
||||
* @throws InvalidArgumentException when id is invalid
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
if ($id <= 0) {
|
||||
throw new InvalidArgumentException('Invalid id');
|
||||
}
|
||||
|
||||
DB::transaction(
|
||||
fn () => ConnectedApp::query()
|
||||
->where('id', $id)
|
||||
->delete()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PaginatedDataCollection<int, UiConnectedAppData>
|
||||
*/
|
||||
@ -53,10 +74,14 @@ public function getAll(): PaginatedDataCollection
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ModelNotFoundException<ConnectedApp>
|
||||
* @throws ModelNotFoundException<ConnectedApp> when the connected app is not found.
|
||||
* @throws InvalidArgumentException when id is invalid.
|
||||
*/
|
||||
public function getConnectedApp(int $id): ConnectedAppData
|
||||
{
|
||||
if ($id <= 0) {
|
||||
throw new InvalidArgumentException('Invalid id');
|
||||
}
|
||||
$data = ConnectedApp::with('provider:id', 'protocol:id', 'status:id')
|
||||
->findOrFail($id);
|
||||
|
||||
|
||||
284
config/livewire.php
Normal file
284
config/livewire.php
Normal file
@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Component Locations
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value sets the root directories that'll be used to resolve view-based
|
||||
| components like single and multi-file components. The make command will
|
||||
| use the first directory in this array to add new component files to.
|
||||
|
|
||||
*/
|
||||
|
||||
'component_locations' => [
|
||||
resource_path('views/components'),
|
||||
resource_path('views/livewire'),
|
||||
],
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Component Namespaces
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value sets default namespaces that will be used to resolve view-based
|
||||
| components like single-file and multi-file components. These folders'll
|
||||
| also be referenced when creating new components via the make command.
|
||||
|
|
||||
*/
|
||||
|
||||
'component_namespaces' => [
|
||||
'layouts' => resource_path('views/layouts'),
|
||||
'pages' => resource_path('views/pages'),
|
||||
],
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Page Layout
|
||||
|---------------------------------------------------------------------------
|
||||
| The view that will be used as the layout when rendering a single component as
|
||||
| an entire page via `Route::livewire('/post/create', 'pages::create-post')`.
|
||||
| In this case, the content of pages::create-post will render into $slot.
|
||||
|
|
||||
*/
|
||||
|
||||
'component_layout' => 'layouts::app.sidebar',
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Lazy Loading Placeholder
|
||||
|---------------------------------------------------------------------------
|
||||
| Livewire allows you to lazy load components that would otherwise slow down
|
||||
| the initial page load. Every component can have a custom placeholder or
|
||||
| you can define the default placeholder view for all components below.
|
||||
|
|
||||
*/
|
||||
|
||||
'component_placeholder' => null, // Example: 'placeholders::skeleton'
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Make Command
|
||||
|---------------------------------------------------------------------------
|
||||
| This value determines the default configuration for the artisan make command
|
||||
| You can configure the component type (sfc, mfc, class) and whether to use
|
||||
| the high-voltage (⚡) emoji as a prefix in the sfc|mfc component names.
|
||||
|
|
||||
*/
|
||||
|
||||
'make_command' => [
|
||||
'type' => 'sfc', // Options: 'sfc', 'mfc', 'class'
|
||||
'emoji' => true, // Options: true, false
|
||||
'with' => [
|
||||
'js' => false,
|
||||
'css' => false,
|
||||
'test' => false,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Class Namespace
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value sets the root class namespace for Livewire component classes in
|
||||
| your application. This value will change where component auto-discovery
|
||||
| finds components. It's also referenced by the file creation commands.
|
||||
|
|
||||
*/
|
||||
|
||||
'class_namespace' => 'App\\Livewire',
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Class Path
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value is used to specify the path where Livewire component class files
|
||||
| are created when running creation commands like `artisan make:livewire`.
|
||||
| This path is customizable to match your projects directory structure.
|
||||
|
|
||||
*/
|
||||
|
||||
'class_path' => app_path('Livewire'),
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| View Path
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value is used to specify where Livewire component Blade templates are
|
||||
| stored when running file creation commands like `artisan make:livewire`.
|
||||
| It is also used if you choose to omit a component's render() method.
|
||||
|
|
||||
*/
|
||||
|
||||
'view_path' => resource_path('views/livewire'),
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Temporary File Uploads
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| Livewire handles file uploads by storing uploads in a temporary directory
|
||||
| before the file is stored permanently. All file uploads are directed to
|
||||
| a global endpoint for temporary storage. You may configure this below:
|
||||
|
|
||||
*/
|
||||
|
||||
'temporary_file_upload' => [
|
||||
'disk' => env('LIVEWIRE_TEMPORARY_FILE_UPLOAD_DISK'), // Example: 'local', 's3' | Default: 'default'
|
||||
'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
|
||||
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
|
||||
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
|
||||
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
|
||||
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
|
||||
'mov', 'avi', 'wmv', 'mp3', 'm4a',
|
||||
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
|
||||
],
|
||||
'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
|
||||
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
|
||||
],
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Render On Redirect
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines if Livewire will run a component's `render()` method
|
||||
| after a redirect has been triggered using something like `redirect(...)`
|
||||
| Setting this to true will render the view once more before redirecting
|
||||
|
|
||||
*/
|
||||
|
||||
'render_on_redirect' => false,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Eloquent Model Binding
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| Previous versions of Livewire supported binding directly to eloquent model
|
||||
| properties using wire:model by default. However, this behavior has been
|
||||
| deemed too "magical" and has therefore been put under a feature flag.
|
||||
|
|
||||
*/
|
||||
|
||||
'legacy_model_binding' => false,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Auto-inject Frontend Assets
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| By default, Livewire automatically injects its JavaScript and CSS into the
|
||||
| <head> and <body> of pages containing Livewire components. By disabling
|
||||
| this behavior, you need to use @livewireStyles and @livewireScripts.
|
||||
|
|
||||
*/
|
||||
|
||||
'inject_assets' => true,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Navigate (SPA mode)
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| By adding `wire:navigate` to links in your Livewire application, Livewire
|
||||
| will prevent the default link handling and instead request those pages
|
||||
| via AJAX, creating an SPA-like effect. Configure this behavior here.
|
||||
|
|
||||
*/
|
||||
|
||||
'navigate' => [
|
||||
'show_progress_bar' => true,
|
||||
'progress_bar_color' => '#2299dd',
|
||||
],
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| HTML Morph Markers
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| Livewire intelligently "morphs" existing HTML into the newly rendered HTML
|
||||
| after each update. To make this process more reliable, Livewire injects
|
||||
| "markers" into the rendered Blade surrounding @if, @class & @foreach.
|
||||
|
|
||||
*/
|
||||
|
||||
'inject_morph_markers' => true,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Smart Wire Keys
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| Livewire uses loops and keys used within loops to generate smart keys that
|
||||
| are applied to nested components that don't have them. This makes using
|
||||
| nested components more reliable by ensuring that they all have keys.
|
||||
|
|
||||
*/
|
||||
|
||||
'smart_wire_keys' => true,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Pagination Theme
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| When enabling Livewire's pagination feature by using the `WithPagination`
|
||||
| trait, Livewire will use Tailwind templates to render pagination views
|
||||
| on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
|
||||
|
|
||||
*/
|
||||
|
||||
'pagination_theme' => 'tailwind',
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Release Token
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This token is stored client-side and sent along with each request to check
|
||||
| a users session to see if a new release has invalidated it. If there is
|
||||
| a mismatch it will throw an error and prompt for a browser refresh.
|
||||
|
|
||||
*/
|
||||
|
||||
'release_token' => 'a',
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| CSP Safe
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| This config is used to determine if Livewire will use the CSP-safe version
|
||||
| of Alpine in its bundle. This is useful for applications that are using
|
||||
| strict Content Security Policy (CSP) to protect against XSS attacks.
|
||||
|
|
||||
*/
|
||||
|
||||
'csp_safe' => false,
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Payload Guards
|
||||
|---------------------------------------------------------------------------
|
||||
|
|
||||
| These settings protect against malicious or oversized payloads that could
|
||||
| cause denial of service. The default values should feel reasonable for
|
||||
| most web applications. Each can be set to null to disable the limit.
|
||||
|
|
||||
*/
|
||||
|
||||
'payload' => [
|
||||
'max_size' => 1024 * 1024, // 1MB - maximum request payload size in bytes
|
||||
'max_nesting_depth' => 10, // Maximum depth of dot-notation property paths
|
||||
'max_calls' => 50, // Maximum method calls per request
|
||||
'max_components' => 200, // Maximum components per batch request
|
||||
],
|
||||
];
|
||||
@ -1,27 +1,30 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Data\ConnectedApp\ConnectAppRequest;
|
||||
use App\Data\ConnectedApp\ConnectionStatusData;
|
||||
use App\Enums\ConnectionStatusEnum;
|
||||
use App\Livewire\Forms\StoreConnectedAppFrom;
|
||||
use App\Models\ConnectionProtocol;
|
||||
use App\Models\ConnectionProvider;
|
||||
use App\Models\ConnectionStatus;
|
||||
use App\Services\ConnectionProtocolService;
|
||||
use App\Services\ConnectionProviderService;
|
||||
use App\Services\ConnectionStatusService;
|
||||
use App\Models\{ConnectionProtocol, ConnectionProvider, ConnectionStatus};
|
||||
use App\Services\{ConnectedAppService, ConnectionProtocolService, ConnectionProviderService, ConnectionStatusService};
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\{Computed, Title};
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\Title;
|
||||
use Mary\Traits\Toast;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
new
|
||||
#[Title('Create a service')]
|
||||
class extends Component {
|
||||
use Toast;
|
||||
use HandlesOperations;
|
||||
|
||||
public StoreConnectedAppFrom $form;
|
||||
protected ConnectedAppService $appService;
|
||||
|
||||
public function boot(ConnectedAppService $appService): void
|
||||
{
|
||||
$this->appService = $appService;
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function providers()
|
||||
@ -63,25 +66,44 @@ public function searchProvider(string $name)
|
||||
$this->providers = $providerService->search($name);
|
||||
}
|
||||
|
||||
public function save()
|
||||
public function save(bool $goBack = true): void
|
||||
{
|
||||
try {
|
||||
$this->form->save();
|
||||
$this->success('New App connected ');
|
||||
return to_route('dashboard');
|
||||
} catch (Throwable $e) {
|
||||
$this->error('Something gone wrong. Try again');
|
||||
\Illuminate\Support\Facades\Log::error('Error while submitting Create a connected app', [$e->getMessage()]);
|
||||
}
|
||||
$this->form->validate();
|
||||
$data = new ConnectAppRequest(
|
||||
name: $this->form->name,
|
||||
connectionProviderId: $this->form->providerId,
|
||||
connectionProtocolId: $this->form->protocolId,
|
||||
slug: str($this->form->name)->slug()->toString(),
|
||||
connectionStatusId: $this->form->statusId
|
||||
);
|
||||
$this->attempt(
|
||||
action: function () use ($data, $goBack) {
|
||||
$this->appService->create($data);
|
||||
$this->form->reset();
|
||||
if ($goBack) {
|
||||
$this->goBack();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function goBack(): void
|
||||
{
|
||||
$this->redirectRoute('connected-apps.index', navigate: true);
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
<x-shared.card :title="__('Create a service')" class="">
|
||||
<form wire:submit="save" class="p-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<x-input wire:model.live.blur="form.name" required :label="__('Name')"/>
|
||||
<x-choices
|
||||
<x-mary-form wire:submit="save" class="p-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<x-mary-input wire:model.live.blur="form.name" required :label="__('Name')"/>
|
||||
<x-mary-choices
|
||||
required
|
||||
wire:model="form.protocolId"
|
||||
:label="__('Protocol')"
|
||||
@ -89,17 +111,17 @@ public function save()
|
||||
:options="$this->protocols"
|
||||
placeholder="Select"
|
||||
/>
|
||||
<x-choices required
|
||||
wire:model="form.providerId"
|
||||
:label="__('Provider')"
|
||||
placeholder="Search ..."
|
||||
:single="true"
|
||||
:options="$this->providers"
|
||||
searchable
|
||||
search-function="searchProvider"
|
||||
debounce="300"
|
||||
<x-mary-choices required
|
||||
wire:model="form.providerId"
|
||||
:label="__('Provider')"
|
||||
placeholder="Search ..."
|
||||
:single="true"
|
||||
:options="$this->providers"
|
||||
searchable
|
||||
search-function="searchProvider"
|
||||
debounce="300"
|
||||
/>
|
||||
<x-choices
|
||||
<x-mary-choices
|
||||
required
|
||||
wire:model="form.statusId"
|
||||
:label="__('Status')"
|
||||
@ -108,13 +130,13 @@ public function save()
|
||||
placeholder="Select"
|
||||
/>
|
||||
<div class="md:col-span-2 flex gap-x-4 font-medium justify-end">
|
||||
<x-shared.button>Cancel</x-shared.button>
|
||||
<x-shared.button type="submit">Save & Add Another</x-shared.button>
|
||||
<x-shared.button type="submit"
|
||||
class="bg-blue-600 text-blue-50 hover:bg-blue-700 border-blue-600 min-w-20 flex justify-center items-center">
|
||||
<x-mary-button wire:click.prevent="goBack" spinner="goBack">Cancel</x-mary-button>
|
||||
<x-mary-button wire:click.prevent="save(false)">Save & Add Another</x-mary-button>
|
||||
<x-mary-button type="submit"
|
||||
class="btn-primary">
|
||||
Save
|
||||
</x-shared.button>
|
||||
</x-mary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-mary-form>
|
||||
</x-shared.card>
|
||||
</div>
|
||||
|
||||
@ -106,42 +106,46 @@ public function save(): void
|
||||
?>
|
||||
|
||||
<div>
|
||||
<x-shared.card :title="__('Edit an connected app')" class="">
|
||||
<form wire:submit="save" class="p-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<x-input wire:model.live.blur="form.name" required :label="__('Name')"/>
|
||||
<x-choices
|
||||
required
|
||||
wire:model="form.protocolId"
|
||||
:label="__('Protocol')"
|
||||
:single="true"
|
||||
:options="$this->protocols"
|
||||
placeholder="Select"
|
||||
/>
|
||||
<x-choices required
|
||||
wire:model="form.providerId"
|
||||
:label="__('Provider')"
|
||||
placeholder="Search ..."
|
||||
:single="true"
|
||||
:options="$this->providers"
|
||||
searchable
|
||||
search-function="searchProvider"
|
||||
debounce="300"
|
||||
/>
|
||||
<x-choices
|
||||
required
|
||||
wire:model="form.statusId"
|
||||
:label="__('Status')"
|
||||
:single="true"
|
||||
:options="$this->connectionStatuses->toArray()"
|
||||
placeholder="Select"
|
||||
/>
|
||||
<div class="md:col-span-2 flex gap-x-4 font-medium justify-end">
|
||||
<x-shared.button>Cancel</x-shared.button>
|
||||
<x-shared.button type="submit"
|
||||
class="bg-blue-600 text-blue-50 hover:bg-blue-700 border-blue-600 min-w-20 flex justify-center items-center">
|
||||
Save
|
||||
</x-shared.button>
|
||||
<x-shared.card :title="__('Edit an connected app')">
|
||||
<x-mary-form wire:submit="save" class="pb-2">
|
||||
<div class="px-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
|
||||
<x-mary-input wire:model.live.blur="form.name" required :label="__('Name')"/>
|
||||
<x-mary-choices
|
||||
required
|
||||
wire:model="form.protocolId"
|
||||
:label="__('Protocol')"
|
||||
:single="true"
|
||||
:options="$this->protocols"
|
||||
placeholder="Select"
|
||||
/>
|
||||
<x-mary-choices required
|
||||
wire:model="form.providerId"
|
||||
:label="__('Provider')"
|
||||
placeholder="Search ..."
|
||||
:single="true"
|
||||
:options="$this->providers"
|
||||
searchable
|
||||
search-function="searchProvider"
|
||||
debounce="300"
|
||||
/>
|
||||
<x-mary-choices
|
||||
required
|
||||
wire:model="form.statusId"
|
||||
:label="__('Status')"
|
||||
:single="true"
|
||||
:options="$this->connectionStatuses->toArray()"
|
||||
placeholder="Select"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<x-slot:actions class="pr-2">
|
||||
<x-mary-button :link="route('connected-apps.index')" wire:navigate>
|
||||
{{ __('Cancel') }}
|
||||
</x-mary-button>
|
||||
<x-mary-button type="submit" spinner="save" class="btn-primary">
|
||||
{{ __('Save') }}
|
||||
</x-mary-button>
|
||||
</x-slot:actions>
|
||||
</x-mary-form>
|
||||
</x-shared.card>
|
||||
</div>
|
||||
|
||||
@ -1,21 +1,32 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Data\Ui\ConnectedApps\ConnectedAppData;
|
||||
use App\Data\Ui\TableHeader;
|
||||
use App\Services\ConnectedAppService;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
use Spatie\LaravelData\PaginatedDataCollection;
|
||||
|
||||
new class extends Component {
|
||||
use WithPagination;
|
||||
new
|
||||
#[Title('Connected Apps')]
|
||||
class extends Component {
|
||||
use WithPagination, HandlesOperations;
|
||||
|
||||
protected ConnectedAppService $service;
|
||||
|
||||
#[DataCollectionOf(TableHeader::class)]
|
||||
public DataCollection $headers;
|
||||
|
||||
public function boot(ConnectedAppService $service): void
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->initTableHeaders();
|
||||
@ -37,21 +48,29 @@ private function initTableHeaders(): void
|
||||
#[Computed]
|
||||
public function getConnectedApps(): PaginatedDataCollection
|
||||
{
|
||||
$service = app(ConnectedAppService::class);
|
||||
return $service->getAll();
|
||||
return $this->service->getAll();
|
||||
}
|
||||
|
||||
public function edit(int $appId): void
|
||||
{
|
||||
$this->redirectRoute('connected-apps.edit', ['id' => $appId], navigate: true);
|
||||
}
|
||||
|
||||
public function delete(int $appId): void
|
||||
{
|
||||
$this->attempt(
|
||||
action: fn() => $this->service->delete($appId),
|
||||
successMessage: 'The app has been deleted !'
|
||||
);
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
<x-shared.card title="Connected Apps" class="pb-2">
|
||||
<x-slot:actions>
|
||||
<x-mary-button icon="lucide.plus">Add App</x-mary-button>
|
||||
<x-mary-button :link="route('connected-apps.create')" wire:navigate icon="lucide.plus">Add App
|
||||
</x-mary-button>
|
||||
</x-slot:actions>
|
||||
<x-mary-table
|
||||
:headers="$headers->toArray()"
|
||||
@ -67,8 +86,10 @@ public function edit(int $appId): void
|
||||
@endscope
|
||||
@scope('actions', $row)
|
||||
<div class="flex">
|
||||
<x-mary-button icon="lucide.edit" wire:click="edit({{$row->id}})" class="mr-2 btn-sm text-gray-500"/>
|
||||
<x-mary-button icon="lucide.trash" variant="danger" class="btn-sm btn-error btn-soft"/>
|
||||
<x-mary-button icon="lucide.edit" wire:click="edit({{$row->id}})" spinner="edit"
|
||||
class="mr-2 btn-sm text-gray-500"/>
|
||||
<x-mary-button icon="lucide.trash" wire:click="delete({{$row->id}})" spinner="delete" variant="danger"
|
||||
class="btn-sm btn-error btn-soft"/>
|
||||
</div>
|
||||
@endscope
|
||||
</x-mary-table>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
use Livewire\Component;
|
||||
|
||||
new
|
||||
#[Layout('layouts.app')]
|
||||
#[Layout('layouts.app.sidebar')]
|
||||
#[Title('Dashboard')]
|
||||
class extends Component {
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user