From c3ab5b96bb97a549092b3ea8e799389bf5af720c Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Tue, 31 Aug 2021 09:08:27 +0100 Subject: [PATCH] feat: NoJs Admin View (#3059) Adds a nojs blade template to be able to enable/disable extensions when one of them misbehaves. --- framework/core/less/admin.less | 1 + framework/core/less/admin/NoJs.less | 17 +++++ framework/core/less/common/Table.less | 69 ++++++++++++++++++ framework/core/less/common/common.less | 1 + .../core/less/forum/NotificationGrid.less | 51 +------------- framework/core/locale/core.yml | 15 ++++ framework/core/src/Admin/Content/Index.php | 60 ++++++++++++++++ .../Controller/UpdateExtensionController.php | 55 +++++++++++++++ framework/core/src/Admin/routes.php | 10 ++- .../Controller/UpdateExtensionController.php | 27 +++---- .../src/Extension/Command/ToggleExtension.php | 37 ++++++++++ .../Command/ToggleExtensionHandler.php | 41 +++++++++++ framework/core/src/Extension/Extension.php | 13 ++++ framework/core/views/frontend/admin.blade.php | 6 +- .../views/frontend/content/admin.blade.php | 70 +++++++++++++++++++ 15 files changed, 403 insertions(+), 70 deletions(-) create mode 100644 framework/core/less/admin/NoJs.less create mode 100644 framework/core/less/common/Table.less create mode 100644 framework/core/src/Admin/Content/Index.php create mode 100644 framework/core/src/Admin/Controller/UpdateExtensionController.php create mode 100644 framework/core/src/Extension/Command/ToggleExtension.php create mode 100644 framework/core/src/Extension/Command/ToggleExtensionHandler.php create mode 100644 framework/core/views/frontend/content/admin.blade.php diff --git a/framework/core/less/admin.less b/framework/core/less/admin.less index 772207002..07f528fc0 100644 --- a/framework/core/less/admin.less +++ b/framework/core/less/admin.less @@ -10,4 +10,5 @@ @import "admin/ExtensionWidget"; @import "admin/AppearancePage"; @import "admin/MailPage"; +@import "admin/NoJs"; @import "admin/UsersListPage.less"; diff --git a/framework/core/less/admin/NoJs.less b/framework/core/less/admin/NoJs.less new file mode 100644 index 000000000..b89082bd4 --- /dev/null +++ b/framework/core/less/admin/NoJs.less @@ -0,0 +1,17 @@ +// Minimal NoJs specific styles +.NoJs-ExtensionsTable { + td&-icon { + padding-top: 0; + padding-bottom: 0; + } + + .ExtensionListItem-Dot { + position: relative; + right: 0; + margin: 0; + } + + .ExtensionIcon { + --size: 25px; + } +} diff --git a/framework/core/less/common/Table.less b/framework/core/less/common/Table.less new file mode 100644 index 000000000..dbcb52c8a --- /dev/null +++ b/framework/core/less/common/Table.less @@ -0,0 +1,69 @@ +.Table { + background: @control-bg; + border-radius: @border-radius; + border-collapse: collapse; + border-spacing: 0; + + caption { + text-align: start; + } + + td, th { + border-bottom: 1px solid @body-bg; + color: @control-color; + } + + td, th, .Checkbox, &-controls-item { + padding: 10px 15px; + } + + & &-checkbox, & &-controls { + padding: 0; + } + + thead { + th { + text-align: center; + padding: 15px 25px; + } + + .icon { + display: block; + font-size: 14px; + width: auto; + margin-bottom: 5px; + } + } + + &-groupToggle { + cursor: pointer; + + .icon { + font-size: 14px; + margin-right: 2px; + .fa-fw(); + } + } + + &-checkbox { + .Checkbox { + display: block; + } + + .Checkbox-display { + text-align: center; + cursor: pointer; + } + + &.highlighted .Checkbox, .Checkbox:hover { + &:not(.disabled) { + background: darken(@control-bg, 4%); + } + } + } + + &-controls-item { + width: 100%; + border-radius: 0; + } +} diff --git a/framework/core/less/common/common.less b/framework/core/less/common/common.less index 39b6bbb79..b141aaec1 100644 --- a/framework/core/less/common/common.less +++ b/framework/core/less/common/common.less @@ -27,6 +27,7 @@ @import "Placeholder"; @import "Search"; @import "Select"; +@import "Table"; @import "TextEditor"; @import "Tooltip"; @import "ValidationError"; diff --git a/framework/core/less/forum/NotificationGrid.less b/framework/core/less/forum/NotificationGrid.less index 4691be78c..bfea1992c 100644 --- a/framework/core/less/forum/NotificationGrid.less +++ b/framework/core/less/forum/NotificationGrid.less @@ -1,52 +1,3 @@ .NotificationGrid { - background: @control-bg; - border-radius: @border-radius; - border-collapse: collapse; - border-spacing: 0; - - td, th { - border-bottom: 1px solid @body-bg; - color: @control-color; - } - td, th, .Checkbox { - padding: 10px 15px; - } - .NotificationGrid-checkbox { - padding: 0; - } - thead { - th { - text-align: center; - padding: 15px 25px; - } - .icon { - display: block; - font-size: 14px; - width: auto; - margin-bottom: 5px; - } - } -} -.NotificationGrid-groupToggle { - cursor: pointer; - - .icon { - font-size: 14px; - margin-right: 2px; - .fa-fw(); - } -} -.NotificationGrid-checkbox { - .Checkbox { - display: block; - } - .Checkbox-display { - text-align: center; - cursor: pointer; - } - &.highlighted .Checkbox, .Checkbox:hover { - &:not(.disabled) { - background: darken(@control-bg, 4%); - } - } + .Table(); } diff --git a/framework/core/locale/core.yml b/framework/core/locale/core.yml index 7f4f0cf81..79660abf5 100644 --- a/framework/core/locale/core.yml +++ b/framework/core/locale/core.yml @@ -545,6 +545,20 @@ core: # Translations in this namespace are used in views other than Flarum's normal JS client. views: + # Translations in this namespace are displayed by the basic HTML admin index. + admin: + extensions: + caption: => core.ref.extensions + disable: Disable + empty: No installed extensions + enable: Enable + name: Extension Name + package_name: Package Name + version: Version + info: + caption: Application Info + title: Administration + # Translations in this namespace are displayed by the Confirm Email interface. confirm_email: submit_button: => core.ref.confirm_email @@ -673,6 +687,7 @@ core: edit: Edit edit_user: Edit User email: Email + extensions: Extensions icon: Icon icon_text: "Enter the name of any FontAwesome icon class, including the fas fa- prefix." load_more: Load More diff --git a/framework/core/src/Admin/Content/Index.php b/framework/core/src/Admin/Content/Index.php new file mode 100644 index 000000000..2060955cb --- /dev/null +++ b/framework/core/src/Admin/Content/Index.php @@ -0,0 +1,60 @@ +view = $view; + $this->extensions = $extensions; + $this->settings = $settings; + } + + public function __invoke(Document $document, Request $request): Document + { + $extensions = $this->extensions->getExtensions(); + $extensionsEnabled = json_decode($this->settings->get('extensions_enabled', '{}'), true); + $csrfToken = $request->getAttribute('session')->token(); + + $mysqlVersion = $document->payload['mysqlVersion']; + $phpVersion = $document->payload['phpVersion']; + $flarumVersion = Application::VERSION; + + $document->content = $this->view->make( + 'flarum.admin::frontend.content.admin', + compact('extensions', 'extensionsEnabled', 'csrfToken', 'flarumVersion', 'phpVersion', 'mysqlVersion') + ); + + return $document; + } +} diff --git a/framework/core/src/Admin/Controller/UpdateExtensionController.php b/framework/core/src/Admin/Controller/UpdateExtensionController.php new file mode 100644 index 000000000..61db18a59 --- /dev/null +++ b/framework/core/src/Admin/Controller/UpdateExtensionController.php @@ -0,0 +1,55 @@ +url = $url; + $this->bus = $bus; + } + + /** + * {@inheritdoc} + */ + public function handle(Request $request): ResponseInterface + { + $actor = RequestUtil::getActor($request); + $enabled = (bool) (int) Arr::get($request->getParsedBody(), 'enabled'); + $name = Arr::get($request->getQueryParams(), 'name'); + + $this->bus->dispatch( + new ToggleExtension($actor, $name, $enabled) + ); + + return new RedirectResponse($this->url->to('admin')->base()); + } +} diff --git a/framework/core/src/Admin/routes.php b/framework/core/src/Admin/routes.php index 66ae2e85b..d81517dfb 100644 --- a/framework/core/src/Admin/routes.php +++ b/framework/core/src/Admin/routes.php @@ -7,6 +7,8 @@ * LICENSE file that was distributed with this source code. */ +use Flarum\Admin\Content\Index; +use Flarum\Admin\Controller\UpdateExtensionController; use Flarum\Http\RouteCollection; use Flarum\Http\RouteHandlerFactory; @@ -14,6 +16,12 @@ return function (RouteCollection $map, RouteHandlerFactory $route) { $map->get( '/', 'index', - $route->toAdmin() + $route->toAdmin(Index::class) + ); + + $map->post( + '/extensions/{name}', + 'extensions.update', + $route->toController(UpdateExtensionController::class) ); }; diff --git a/framework/core/src/Api/Controller/UpdateExtensionController.php b/framework/core/src/Api/Controller/UpdateExtensionController.php index 35cf3939a..0a9e4e59e 100644 --- a/framework/core/src/Api/Controller/UpdateExtensionController.php +++ b/framework/core/src/Api/Controller/UpdateExtensionController.php @@ -9,7 +9,8 @@ namespace Flarum\Api\Controller; -use Flarum\Extension\ExtensionManager; +use Flarum\Bus\Dispatcher; +use Flarum\Extension\Command\ToggleExtension; use Flarum\Http\RequestUtil; use Illuminate\Support\Arr; use Laminas\Diactoros\Response\EmptyResponse; @@ -20,16 +21,13 @@ use Psr\Http\Server\RequestHandlerInterface; class UpdateExtensionController implements RequestHandlerInterface { /** - * @var ExtensionManager + * @var Dispatcher */ - protected $extensions; + protected $bus; - /** - * @param ExtensionManager $extensions - */ - public function __construct(ExtensionManager $extensions) + public function __construct(Dispatcher $bus) { - $this->extensions = $extensions; + $this->bus = $bus; } /** @@ -37,16 +35,13 @@ class UpdateExtensionController implements RequestHandlerInterface */ public function handle(ServerRequestInterface $request): ResponseInterface { - RequestUtil::getActor($request)->assertAdmin(); - - $enabled = Arr::get($request->getParsedBody(), 'enabled'); + $actor = RequestUtil::getActor($request); + $enabled = (bool) (int) Arr::get($request->getParsedBody(), 'enabled'); $name = Arr::get($request->getQueryParams(), 'name'); - if ($enabled === true) { - $this->extensions->enable($name); - } elseif ($enabled === false) { - $this->extensions->disable($name); - } + $this->bus->dispatch( + new ToggleExtension($actor, $name, $enabled) + ); return new EmptyResponse; } diff --git a/framework/core/src/Extension/Command/ToggleExtension.php b/framework/core/src/Extension/Command/ToggleExtension.php new file mode 100644 index 000000000..69d3060a4 --- /dev/null +++ b/framework/core/src/Extension/Command/ToggleExtension.php @@ -0,0 +1,37 @@ +actor = $actor; + $this->name = $name; + $this->enabled = $enabled; + } +} diff --git a/framework/core/src/Extension/Command/ToggleExtensionHandler.php b/framework/core/src/Extension/Command/ToggleExtensionHandler.php new file mode 100644 index 000000000..564d543df --- /dev/null +++ b/framework/core/src/Extension/Command/ToggleExtensionHandler.php @@ -0,0 +1,41 @@ +extensions = $extensions; + } + + /** + * @throws \Flarum\User\Exception\PermissionDeniedException + * @throws \Flarum\Extension\Exception\MissingDependenciesException + * @throws \Flarum\Extension\Exception\DependentExtensionsException + */ + public function handle(ToggleExtension $command) + { + $command->actor->assertAdmin(); + + if ($command->enabled) { + $this->extensions->enable($command->name); + } else { + $this->extensions->disable($command->name); + } + } +} diff --git a/framework/core/src/Extension/Extension.php b/framework/core/src/Extension/Extension.php index a705578fb..41e73482a 100644 --- a/framework/core/src/Extension/Extension.php +++ b/framework/core/src/Extension/Extension.php @@ -279,6 +279,19 @@ class Extension implements Arrayable return $icon; } + public function getIconStyles(): string + { + $properties = $this->getIcon(); + + unset($properties['name']); + + return implode(';', array_map(function (string $property, string $value) { + $property = Str::kebab($property); + + return "$property: $value"; + }, array_keys($properties), $properties)); + } + /** * @internal */ diff --git a/framework/core/views/frontend/admin.blade.php b/framework/core/views/frontend/admin.blade.php index 56a6aa2b9..351acd8cf 100644 --- a/framework/core/views/frontend/admin.blade.php +++ b/framework/core/views/frontend/admin.blade.php @@ -28,9 +28,9 @@
-
- - {!! $content !!} +
+ {!! $content !!} +
diff --git a/framework/core/views/frontend/content/admin.blade.php b/framework/core/views/frontend/content/admin.blade.php new file mode 100644 index 000000000..6f5b6ae55 --- /dev/null +++ b/framework/core/views/frontend/content/admin.blade.php @@ -0,0 +1,70 @@ +@inject('url', 'Flarum\Http\UrlGenerator') + +
+

{{ $translator->trans('core.views.admin.title') }}

+ + + + + + + + + + + + + + + + + +

{{ $translator->trans('core.views.admin.info.caption') }}

Flarum{{ $flarumVersion }}
PHP{{ $phpVersion }}
MySQL{{ $mysqlVersion }}
+ + + + + + + + + + + + + + + @forelse($extensions as $extension) + @php $isEnabled = in_array($extension->getId(), $extensionsEnabled); @endphp + + + + + + + + + + @empty + + @endforelse + +

{{ $translator->trans('core.views.admin.extensions.caption') }}

{{ $translator->trans('core.views.admin.extensions.name') }}{{ $translator->trans('core.views.admin.extensions.package_name') }}{{ $translator->trans('core.views.admin.extensions.version') }}
+
+ +
+
{{ $extension->getTitle() }}{{ $extension->name }}{{ $extension->getVersion() }} + + +
+ + + + @if($isEnabled) + + @else + + @endif +
+
{{ $translator->trans('core.views.admin.extensions.empty') }}
+