@if($item->getIcon())
diff --git a/resources/views/components/page.blade.php b/resources/views/components/page.blade.php
index cba9536b4..830ae3849 100644
--- a/resources/views/components/page.blade.php
+++ b/resources/views/components/page.blade.php
@@ -1,5 +1,5 @@
-
+
@if(trim($slot))
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
index 59c027689..cf171b6a1 100644
--- a/resources/views/layouts/app.blade.php
+++ b/resources/views/layouts/app.blade.php
@@ -25,6 +25,7 @@
@vite('resources/assets/js/client-api.js', '/vendor/sharp')
+ {{ $head ?? null }}
@vite('resources/assets/js/sharp.js', '/vendor/sharp')
diff --git a/src/Http/DashboardController.php b/src/Http/DashboardController.php
index 8b5745e47..906068174 100644
--- a/src/Http/DashboardController.php
+++ b/src/Http/DashboardController.php
@@ -2,10 +2,37 @@
namespace Code16\Sharp\Http;
+use Code16\Sharp\Auth\SharpAuthorizationManager;
+use Code16\Sharp\Utils\Entities\SharpEntityManager;
+use Inertia\Inertia;
+
class DashboardController extends SharpProtectedController
{
+ public function __construct(
+ private SharpAuthorizationManager $sharpAuthorizationManager,
+ private SharpEntityManager $entityManager,
+ ) {
+ parent::__construct();
+ }
+
public function show(string $dashboardKey)
{
- return view('sharp::dashboard', compact('dashboardKey'));
+ sharp_check_ability('entity', $dashboardKey);
+
+ $dashboard = $this->entityManager->entityFor($dashboardKey)->getViewOrFail();
+ $dashboard->buildDashboardConfig();
+ $dashboard->init();
+
+ $data = [
+ 'widgets' => $dashboard->widgets(),
+ 'config' => $dashboard->dashboardConfig(),
+ 'layout' => $dashboard->widgetsLayout(),
+ 'data' => $dashboard->data(),
+ 'fields' => $dashboard->dashboardMetaFields(),
+ ];
+
+ return Inertia::render('Dashboard', [
+ 'dashboard' => $data,
+ ]);
}
}
diff --git a/src/Http/EntityListController.php b/src/Http/EntityListController.php
new file mode 100644
index 000000000..a30f16df3
--- /dev/null
+++ b/src/Http/EntityListController.php
@@ -0,0 +1,122 @@
+entityManager->entityFor($entityKey)->getListOrFail();
+ $list->buildListConfig();
+ $list->initQueryParams();
+
+ $data = [
+ 'containers' => $list->fields(),
+ 'layout' => $list->listLayout(),
+ 'data' => $list->data(),
+ 'fields' => $list->listMetaFields(),
+ 'config' => $list->listConfig(
+ $this->entityManager->entityFor($entityKey)->hasShow(),
+ ),
+ 'notifications' => $this->getSharpNotifications(),
+ ];
+
+ $data['authorizations'] = $this->getAuthorizationsForEntityList(
+ $entityKey,
+ $data['data']['list']['items'],
+ $data['config'],
+ );
+
+ $data['forms'] = $this->getMultiformDataForEntityList(
+ $entityKey,
+ $data['data']['list']['items'],
+ $data['config'],
+ );
+
+ // TODO handle breadcrumb
+
+ return Inertia::render('List', [
+ 'entityList' => $data,
+ ]);
+ }
+
+ private function getAuthorizationsForEntityList(string $entityKey, array $listItems, array $listConfig): array
+ {
+ $authorizations = [
+ 'view' => [],
+ 'update' => [],
+ 'create' => $this->sharpAuthorizationManager->isAllowed('create', $entityKey),
+ ];
+
+ // Collect instanceIds from response
+ collect($listItems)
+ ->pluck($listConfig['instanceIdAttribute'])
+ ->each(function ($instanceId) use (&$authorizations, $entityKey) {
+ if ($this->sharpAuthorizationManager->isAllowed('view', $entityKey, $instanceId)) {
+ $authorizations['view'][] = $instanceId;
+ }
+ if ($this->sharpAuthorizationManager->isAllowed('update', $entityKey, $instanceId)) {
+ $authorizations['update'][] = $instanceId;
+ }
+ });
+
+ return $authorizations;
+ }
+
+ private function getMultiformDataForEntityList(string $entityKey, array $listItems, array $listConfig): array
+ {
+ if ($listConfig['multiformAttribute'] === null) {
+ return [];
+ }
+
+ if (! $forms = $this->entityManager->entityFor($entityKey)->getMultiforms()) {
+ throw new SharpInvalidConfigException(
+ 'The list for the entity '.$entityKey.' defines a multiform attribute ['
+ .$listConfig['multiformAttribute']
+ .' but the entity is not configured as multiform.'
+ );
+ }
+
+ return collect($forms)
+ ->map(function ($value, $key) use ($listConfig, $listItems) {
+ $instanceIds = collect($listItems)
+ ->where($listConfig['multiformAttribute'], $key)
+ ->pluck($listConfig['instanceIdAttribute']);
+
+ return [
+ 'key' => $key,
+ 'label' => is_array($value) && sizeof($value) > 1 ? $value[1] : $key,
+ 'instances' => $instanceIds,
+ ];
+ })
+ ->keyBy('key')
+ ->all();
+ }
+
+ private function getSharpNotifications(): array
+ {
+ if ($notifications = session('sharp_notifications')) {
+ session()->forget('sharp_notifications');
+
+ return array_values($notifications);
+ }
+
+ return [];
+ }
+}
diff --git a/src/Http/FormController.php b/src/Http/FormController.php
new file mode 100644
index 000000000..f7fb5b71c
--- /dev/null
+++ b/src/Http/FormController.php
@@ -0,0 +1,61 @@
+entityManager->entityFor($entityKey)->hasShow() ? 'update' : 'view',
+ $entityKey,
+ $instanceId
+ );
+
+ $form = $this->entityManager->entityFor($entityKey)->getFormOrFail();
+
+ abort_if(
+ (! $instanceId && ! $form instanceof SharpSingleForm)
+ || ($instanceId && $form instanceof SharpSingleForm),
+ 404,
+ );
+
+ $form->buildFormConfig();
+
+ $data = [
+ 'fields' => $form->fields(),
+ 'layout' => $form->formLayout(),
+ 'config' => $form->formConfig(),
+ 'data' => $form->instance($instanceId),
+ 'locales' => $form->hasDataLocalizations()
+ ? $form->getDataLocalizations()
+ : null,
+ 'authorizations' => [
+ 'create' => $this->sharpAuthorizationManager->isAllowed('create', $entityKey),
+ 'view' => $this->sharpAuthorizationManager->isAllowed('view', $entityKey, $instanceId),
+ 'update' => $this->sharpAuthorizationManager->isAllowed('update', $entityKey, $instanceId),
+ 'delete' => $this->sharpAuthorizationManager->isAllowed('delete', $entityKey, $instanceId),
+ ],
+ ];
+
+ // TODO handle breadcrumb
+
+ return Inertia::render('Form', [
+ 'form' => $data,
+ ]);
+ }
+}
diff --git a/src/Http/HandlesSharpNotificationsInRequest.php b/src/Http/HandlesSharpNotificationsInRequest.php
new file mode 100644
index 000000000..d08b37dfc
--- /dev/null
+++ b/src/Http/HandlesSharpNotificationsInRequest.php
@@ -0,0 +1,17 @@
+forget('sharp_notifications');
+
+ return array_values($notifications);
+ }
+
+ return [];
+ }
+}
diff --git a/src/Http/ListController.php b/src/Http/ListController.php
deleted file mode 100644
index 8d5150bb3..000000000
--- a/src/Http/ListController.php
+++ /dev/null
@@ -1,11 +0,0 @@
-set('ziggy', [
+ 'only' => ['code16.sharp.*'],
+ ]);
+
+ return $next($request);
+ }
+}
diff --git a/src/Http/Middleware/HandleInertiaRequests.php b/src/Http/Middleware/HandleInertiaRequests.php
new file mode 100644
index 000000000..b92b34803
--- /dev/null
+++ b/src/Http/Middleware/HandleInertiaRequests.php
@@ -0,0 +1,38 @@
+user()) {
+ return parent::share($request);
+ }
+
+ $currentEntityKey = currentSharpRequest()->breadcrumb()->first()->key ?? null;
+ $currentEntityItem = $currentEntityKey ? app(SharpMenuManager::class)->getEntityMenuItem($currentEntityKey) : null;
+
+ return array_merge(
+ parent::share($request),
+ [
+ 'config' => [
+ 'search' => [
+ 'placeholder' => config('sharp.search.placeholder'),
+ ]
+ ],
+ 'currentEntity' => $currentEntityItem ? [
+ 'key' => $currentEntityItem->getEntityKey(),
+ 'label' => $currentEntityItem->getLabel(),
+ 'icon' => $currentEntityItem->getIcon(),
+ ] : null,
+ ]
+ );
+ }
+}
diff --git a/src/Http/ShowController.php b/src/Http/ShowController.php
new file mode 100644
index 000000000..ce07508e9
--- /dev/null
+++ b/src/Http/ShowController.php
@@ -0,0 +1,59 @@
+entityManager->entityFor($entityKey)->getShowOrFail();
+
+ abort_if(
+ (! $instanceId && ! $show instanceof SharpSingleShow)
+ || ($instanceId && $show instanceof SharpSingleShow),
+ 404,
+ );
+
+ $show->buildShowConfig();
+
+ $data = [
+ 'config' => $show->showConfig($instanceId),
+ 'fields' => $show->fields(),
+ 'layout' => $show->showLayout(),
+ 'data' => $show->instance($instanceId),
+ 'locales' => $show->hasDataLocalizations()
+ ? $show->getDataLocalizations()
+ : null,
+ 'authorizations' => [
+ 'create' => $this->sharpAuthorizationManager->isAllowed('create', $entityKey),
+ 'view' => $this->sharpAuthorizationManager->isAllowed('view', $entityKey, $instanceId),
+ 'update' => $this->sharpAuthorizationManager->isAllowed('update', $entityKey, $instanceId),
+ 'delete' => $this->sharpAuthorizationManager->isAllowed('delete', $entityKey, $instanceId),
+ ],
+ 'notifications' => $this->getSharpNotifications(),
+ 'breadcrumb' => ['items' => []],
+ ];
+
+ // TODO handle breadcrumb
+
+ return Inertia::render('Show', [
+ 'show' => $data,
+ ]);
+ }
+}
diff --git a/src/SharpServiceProvider.php b/src/SharpServiceProvider.php
index 7b77c1ec1..18c93ca28 100644
--- a/src/SharpServiceProvider.php
+++ b/src/SharpServiceProvider.php
@@ -26,6 +26,8 @@
use Code16\Sharp\Http\Middleware\Api\AppendListAuthorizations;
use Code16\Sharp\Http\Middleware\Api\AppendMultiformInEntityList;
use Code16\Sharp\Http\Middleware\Api\AppendNotifications;
+use Code16\Sharp\Http\Middleware\ConfigureZiggy;
+use Code16\Sharp\Http\Middleware\HandleInertiaRequests;
use Code16\Sharp\Http\Middleware\SharpAuthenticate;
use Code16\Sharp\Http\Middleware\SharpRedirectIfAuthenticated;
use Code16\Sharp\Utils\Menu\SharpMenuManager;
@@ -140,5 +142,8 @@ protected function registerMiddleware(): void
->aliasMiddleware('sharp_api_append_breadcrumb', AppendBreadcrumb::class)
->aliasMiddleware('sharp_auth', SharpAuthenticate::class)
->aliasMiddleware('sharp_guest', SharpRedirectIfAuthenticated::class);
+
+ $this->app['router']->pushMiddlewareToGroup('sharp_web', HandleInertiaRequests::class);
+ $this->app['router']->pushMiddlewareToGroup('sharp_web', ConfigureZiggy::class);
}
}
diff --git a/src/Utils/Links/LinkToShowPage.php b/src/Utils/Links/LinkToShowPage.php
index 0d307f01e..91f00fa8f 100644
--- a/src/Utils/Links/LinkToShowPage.php
+++ b/src/Utils/Links/LinkToShowPage.php
@@ -26,6 +26,9 @@ public function withBreadcrumb(Closure $closure): self
public function renderAsUrl(): string
{
+ // TODO refactor this
+ return '';
+
if (isset($this->breadcrumbBuilder)) {
return url(
sprintf(
@@ -37,7 +40,7 @@ public function renderAsUrl(): string
);
}
- return route('code16.sharp.list.subpage', [
+ return route('code16.sharp.show', [
'entityKey' => $this->entityKey,
'uri' => $this->generateUri(),
]);
diff --git a/src/routes.php b/src/routes.php
index 76313006c..cd680bc38 100644
--- a/src/routes.php
+++ b/src/routes.php
@@ -9,19 +9,21 @@
use Code16\Sharp\Http\Api\DownloadController;
use Code16\Sharp\Http\Api\Embeds\EmbedsController;
use Code16\Sharp\Http\Api\Embeds\EmbedsFormController;
-use Code16\Sharp\Http\Api\EntityListController;
+use Code16\Sharp\Http\Api\EntityListController as ApiEntityListController;
use Code16\Sharp\Http\Api\FilesController;
-use Code16\Sharp\Http\Api\FormController;
+use Code16\Sharp\Http\Api\FormController as ApiFormController;
use Code16\Sharp\Http\Api\FormUploadController;
use Code16\Sharp\Http\Api\GlobalFilterController;
use Code16\Sharp\Http\Api\SearchController;
-use Code16\Sharp\Http\Api\ShowController;
use Code16\Sharp\Http\DashboardController;
+use Code16\Sharp\Http\EntityListController;
+use Code16\Sharp\Http\FormController;
use Code16\Sharp\Http\HomeController;
use Code16\Sharp\Http\LangController;
use Code16\Sharp\Http\ListController;
use Code16\Sharp\Http\Login2faController;
use Code16\Sharp\Http\LoginController;
+use Code16\Sharp\Http\ShowController;
use Code16\Sharp\Http\SingleShowController;
use Code16\Sharp\Http\WebDispatchController;
use Illuminate\Support\Facades\Route;
@@ -41,11 +43,11 @@
Route::post('/dashboard/{dashboardKey}/command/{commandKey}', [DashboardCommandController::class, 'update'])
->name('code16.sharp.api.dashboard.command');
- Route::get('/list/{entityKey}', [EntityListController::class, 'show'])
+ Route::get('/list/{entityKey}', [ApiEntityListController::class, 'show'])
->name('code16.sharp.api.list')
->middleware(['sharp_api_append_list_authorizations', 'sharp_api_append_multiform_in_list', 'sharp_api_append_notifications', 'sharp_api_append_breadcrumb']);
- Route::post('/list/{entityKey}/reorder', [EntityListController::class, 'update'])
+ Route::post('/list/{entityKey}/reorder', [ApiEntityListController::class, 'update'])
->name('code16.sharp.api.list.reorder');
Route::delete('/list/{entityKey}/{instanceId}', [EntityListController::class, 'delete'])
@@ -66,9 +68,9 @@
Route::get('/list/{entityKey}/command/{commandKey}/{instanceId}/form', [EntityListInstanceCommandController::class, 'show'])
->name('code16.sharp.api.list.command.instance.form');
- Route::get('/show/{entityKey}/{instanceId?}', [ShowController::class, 'show'])
- ->name('code16.sharp.api.show.show')
- ->middleware(['sharp_api_append_instance_authorizations', 'sharp_api_append_notifications', 'sharp_api_append_breadcrumb']);
+// Route::get('/show/{entityKey}/{instanceId?}', [ShowController::class, 'show'])
+// ->name('code16.sharp.api.show.show')
+// ->middleware(['sharp_api_append_instance_authorizations', 'sharp_api_append_notifications', 'sharp_api_append_breadcrumb']);
Route::post('/show/{entityKey}/command/{commandKey}/{instanceId?}', [ShowInstanceCommandController::class, 'update'])
->name('code16.sharp.api.show.command.instance');
@@ -87,18 +89,18 @@
Route::delete('/show/{entityKey}/{instanceId}', [ShowController::class, 'delete'])
->name('code16.sharp.api.show.delete');
- Route::get('/form/{entityKey}', [FormController::class, 'create'])
- ->name('code16.sharp.api.form.create')
- ->middleware(['sharp_api_append_instance_authorizations', 'sharp_api_append_breadcrumb']);
+// Route::get('/form/{entityKey}', [FormController::class, 'create'])
+// ->name('code16.sharp.api.form.create')
+// ->middleware(['sharp_api_append_instance_authorizations', 'sharp_api_append_breadcrumb']);
- Route::post('/form/{entityKey}', [FormController::class, 'store'])
+ Route::post('/form/{entityKey}', [ApiFormController::class, 'store'])
->name('code16.sharp.api.form.store');
- Route::get('/form/{entityKey}/{instanceId?}', [FormController::class, 'edit'])
+ Route::get('/form/{entityKey}/{instanceId?}', [ApiFormController::class, 'edit'])
->name('code16.sharp.api.form.edit')
->middleware(['sharp_api_append_instance_authorizations', 'sharp_api_append_breadcrumb']);
- Route::post('/form/{entityKey}/{instanceId?}', [FormController::class, 'update'])
+ Route::post('/form/{entityKey}/{instanceId?}', [ApiFormController::class, 'update'])
->name('code16.sharp.api.form.update');
Route::get('/filters', [GlobalFilterController::class, 'index'])
@@ -158,15 +160,30 @@
Route::post('/logout', [LoginController::class, 'destroy'])
->name('code16.sharp.logout');
- Route::get('/s-list/{entityKey}', [ListController::class, 'show'])
+ Route::get('/s-list/{entityKey}', [EntityListController::class, 'show'])
->name('code16.sharp.list');
Route::get('/s-show/{entityKey}', [SingleShowController::class, 'show'])
->name('code16.sharp.single-show');
- Route::get('/s-list/{entityKey}/{uri}', [WebDispatchController::class, 'index'])
- ->where('uri', '.*')
- ->name('code16.sharp.list.subpage');
+ Route::group([
+ 'prefix' => '/s-list/{uri}',
+ 'where' => ['uri' => '.*'],
+ ], function () {
+ Route::get('/s-show/{entityKey}/{instanceId}', [ShowController::class, 'show'])
+ ->name('code16.sharp.show');
+
+ Route::get('/s-form/{entityKey}/{instanceId}', [FormController::class, 'show'])
+ ->name('code16.sharp.form');
+ });
+
+// Route::get('/s-list/{uri}/s-show/{entityKey}/{instanceId}', [ShowController::class, 'show'])
+// ->where('uri', '.*')
+// ->name('code16.sharp.show');
+
+// Route::get('/s-list/{listEntityKey}/{uri}s-form/{entityKey}/{instanceId}', [FormController::class, 'show'])
+// ->where('uri', '.*')
+// ->name('code16.sharp.form');
Route::get('/s-show/{entityKey}/{uri}', [WebDispatchController::class, 'index'])
->where('uri', '.*')