mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-10-12 02:01:37 +00:00
Layouts: Started edit form ui, added block IDs
This commit is contained in:
@@ -18,11 +18,13 @@ class LayoutController
|
||||
{
|
||||
$namedLocations = $this->viewBlocks->getNamedLocations();
|
||||
$locationName = $namedLocations[$location] ?? $location;
|
||||
$blocks = $this->viewBlocks->getForLocation($location);
|
||||
|
||||
return view('settings.layouts.edit', [
|
||||
'location' => $location,
|
||||
'locationName' => $locationName,
|
||||
'namedLocations' => $namedLocations,
|
||||
'blocks' => $blocks,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,18 @@ namespace BookStack\View;
|
||||
|
||||
abstract class ViewBlock implements ViewBlockInterface
|
||||
{
|
||||
protected string $id;
|
||||
protected string $view;
|
||||
protected string $labelTranslationKey;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -110,6 +110,7 @@ class ViewBlockDefaults
|
||||
|
||||
/**
|
||||
* Get the locations for all default blocks.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getLocations(): array
|
||||
{
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace BookStack\View;
|
||||
|
||||
interface ViewBlockInterface
|
||||
{
|
||||
/**
|
||||
* Get the unique ID for this block.
|
||||
*/
|
||||
public function getId(): string;
|
||||
|
||||
/**
|
||||
* Get the label for this block.
|
||||
*/
|
||||
|
||||
@@ -34,7 +34,7 @@ class ViewBlockManager
|
||||
* @return ViewBlockInterface[]
|
||||
* @throws BindingResolutionException
|
||||
*/
|
||||
public function getForLocation(string $location, string $position): array
|
||||
public function getForLocationAndPosition(string $location, string $position): array
|
||||
{
|
||||
$defaults = ViewBlockDefaults::getForLocation($location)[$position] ?? [];
|
||||
$registered = $this->blocksByLocationAndPosition[$location][$position] ?? [];
|
||||
@@ -45,6 +45,28 @@ class ViewBlockManager
|
||||
}, $sections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blocks registered for a given location, as sets of arrays
|
||||
* keyed by position.
|
||||
* @return array<string, ViewBlockInterface[]>
|
||||
* @throws BindingResolutionException
|
||||
*/
|
||||
public function getForLocation(string $location): array
|
||||
{
|
||||
$defaults = ViewBlockDefaults::getForLocation($location) ?? [];
|
||||
$registered = $this->blocksByLocationAndPosition[$location] ?? [];
|
||||
$sections = array_merge_recursive($defaults, $registered);
|
||||
|
||||
$instances = [];
|
||||
foreach ($sections as $position => $blocks) {
|
||||
$instances[$position] = array_map(function (string $className) {
|
||||
return app()->make($className);
|
||||
}, $blocks);
|
||||
}
|
||||
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of all locations where blocks are registered.
|
||||
* Returns an array where the keys are location strings, and the
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksIndexActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-index-actions';
|
||||
protected string $view = 'books.parts.index-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksIndexNew extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-index-new';
|
||||
protected string $view = 'books.parts.index-sidebar-section-new';
|
||||
protected string $labelTranslationKey = 'entities.books_new';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksIndexPopular extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-index-popular';
|
||||
protected string $view = 'books.parts.index-sidebar-section-popular';
|
||||
protected string $labelTranslationKey = 'entities.books_popular';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksIndexRecents extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-index-recents';
|
||||
protected string $view = 'books.parts.index-sidebar-section-recents';
|
||||
protected string $labelTranslationKey = 'entities.recently_viewed';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-actions';
|
||||
protected string $view = 'books.parts.show-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowActivity extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-activity';
|
||||
protected string $view = 'books.parts.show-sidebar-section-activity';
|
||||
protected string $labelTranslationKey = 'entities.recent_activity';
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowDetails extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-details';
|
||||
protected string $view = 'books.parts.show-sidebar-section-details';
|
||||
protected string $labelTranslationKey = 'common.details';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowSearchForm extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-search-form';
|
||||
protected string $view = 'entities.search-form';
|
||||
protected string $labelTranslationKey = 'common.search';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowShelves extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-shelves';
|
||||
protected string $view = 'books.parts.show-sidebar-section-shelves';
|
||||
protected string $labelTranslationKey = 'entities.shelves';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class BooksShowTags extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_books-show-tags';
|
||||
protected string $view = 'books.parts.show-sidebar-section-tags';
|
||||
protected string $labelTranslationKey = 'entities.tags';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ChaptersShowActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_chapters-show-actions';
|
||||
protected string $view = 'chapters.parts.show-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ChaptersShowBookTree extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_chapters-show-book-tree';
|
||||
protected string $view = 'entities.book-tree';
|
||||
protected string $labelTranslationKey = 'entities.books_navigation';
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ChaptersShowDetails extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_chapters-show-details';
|
||||
protected string $view = 'chapters.parts.show-sidebar-section-details';
|
||||
protected string $labelTranslationKey = 'common.details';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ChaptersShowSearchForm extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_chapters-show-search-form';
|
||||
protected string $view = 'entities.search-form';
|
||||
protected string $labelTranslationKey = 'common.search';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ChaptersShowTags extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_chapters-show-tags';
|
||||
protected string $view = 'chapters.parts.show-sidebar-section-tags';
|
||||
protected string $labelTranslationKey = 'entities.tags';
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use BookStack\View\ViewBlock;
|
||||
|
||||
class HomeActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_home-actions';
|
||||
protected string $view = 'home.parts.configured-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ class HomeRecentActivity implements ViewBlockInterface
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'builtin_home-recent-activity';
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return trans('entities.recent_activity');
|
||||
|
||||
@@ -12,6 +12,11 @@ class HomeRecentDrafts implements ViewBlockInterface
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'builtin_home-recent-drafts';
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return trans('entities.my_recent_drafts');
|
||||
|
||||
@@ -13,6 +13,11 @@ class HomeRecentlyUpdatedPages implements ViewBlockInterface
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'builtin_home-recently-updated-pages';
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return trans('entities.recently_updated_pages');
|
||||
|
||||
@@ -16,6 +16,11 @@ class HomeRecentlyViewedOrRecentBooks implements ViewBlockInterface
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'builtin_home-recently-viewed-or-recent-books';
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
$key = user()->isGuest() ? 'books_recent' : 'my_recently_viewed';
|
||||
|
||||
@@ -13,6 +13,11 @@ class HomeTopFavourites implements ViewBlockInterface
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'builtin_home-top-favourites';
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return trans('entities.my_most_viewed_favourites');
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-actions';
|
||||
protected string $view = 'pages.parts.show-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowAttachments extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-attachments';
|
||||
protected string $view = 'pages.parts.show-sidebar-section-attachments';
|
||||
protected string $labelTranslationKey = 'entities.pages_attachments';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowBookTree extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-book-tree';
|
||||
protected string $view = 'entities.book-tree';
|
||||
protected string $labelTranslationKey = 'entities.books_navigation';
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowDetails extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-details';
|
||||
protected string $view = 'pages.parts.show-sidebar-section-details';
|
||||
protected string $labelTranslationKey = 'common.details';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowPageNav extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-page-nav';
|
||||
protected string $view = 'pages.parts.show-sidebar-section-page-nav';
|
||||
protected string $labelTranslationKey = 'entities.pages_navigation';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PagesShowTags extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_pages-show-tags';
|
||||
protected string $view = 'pages.parts.show-sidebar-section-tags';
|
||||
protected string $labelTranslationKey = 'entities.tags';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesIndexActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-index-actions';
|
||||
protected string $view = 'shelves.parts.index-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesIndexNew extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-index-new';
|
||||
protected string $view = 'shelves.parts.index-sidebar-section-new';
|
||||
protected string $labelTranslationKey = 'entities.shelves_new';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesIndexPopular extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-index-popular';
|
||||
protected string $view = 'shelves.parts.index-sidebar-section-popular';
|
||||
protected string $labelTranslationKey = 'entities.shelves_popular';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesIndexRecents extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-index-recents';
|
||||
protected string $view = 'shelves.parts.index-sidebar-section-recents';
|
||||
protected string $labelTranslationKey = 'entities.recently_viewed';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesShowActions extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-show-actions';
|
||||
protected string $view = 'shelves.parts.show-sidebar-section-actions';
|
||||
protected string $labelTranslationKey = 'common.actions';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesShowActivity extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-show-activity';
|
||||
protected string $view = 'shelves.parts.show-sidebar-section-activity';
|
||||
protected string $labelTranslationKey = 'entities.recent_activity';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesShowDetails extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-show-details';
|
||||
protected string $view = 'shelves.parts.show-sidebar-section-details';
|
||||
protected string $labelTranslationKey = 'common.details';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class ShelvesShowTags extends ViewBlock
|
||||
{
|
||||
protected string $id = 'builtin_shelves-show-tags';
|
||||
protected string $view = 'shelves.parts.show-sidebar-section-tags';
|
||||
protected string $labelTranslationKey = 'entities.tags';
|
||||
|
||||
|
||||
@@ -31,6 +31,11 @@ return [
|
||||
'layout_edit_save' => 'Save Layout',
|
||||
'layout_edit_layouts' => 'Layouts',
|
||||
'layout_edit_back_to_preferences' => 'Back to Preferences',
|
||||
'layout_edit_left' => 'Left',
|
||||
'layout_edit_right' => 'Right',
|
||||
'layout_edit_center' => 'Center',
|
||||
'layout_edit_unused' => 'Unused',
|
||||
'layout_edit_empty' => 'No sections to display',
|
||||
|
||||
'notifications' => 'Notification Preferences',
|
||||
'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.',
|
||||
|
||||
@@ -5,6 +5,6 @@ $position - string
|
||||
@php
|
||||
$sectionVars = get_defined_vars();
|
||||
@endphp
|
||||
@foreach($viewBlocks->getForLocation($location, $position) as $section)
|
||||
@foreach($viewBlocks->getForLocationAndPosition($location, $position) as $section)
|
||||
@include($section->getView($sectionVars), $section->withData($sectionVars))
|
||||
@endforeach
|
||||
@@ -30,6 +30,16 @@
|
||||
{{ method_field('PUT') }}
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="flex-container-row gap-m">
|
||||
@include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['left'] ?? [], 'label' => trans('preferences.layout_edit_left'), 'id' => 'left'])
|
||||
@include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['center'] ?? [], 'label' => trans('preferences.layout_edit_center'), 'id' => 'center'])
|
||||
@include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['right'] ?? [], 'label' => trans('preferences.layout_edit_right'), 'id' => 'right'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['unused'] ?? [], 'label' => trans('preferences.layout_edit_unused'), 'id' => 'unused'])
|
||||
</div>
|
||||
|
||||
<div class="form-group text-right">
|
||||
<a href="{{ url('/my-account/interface') }}" class="button outline">{{ trans('common.cancel') }}</a>
|
||||
<button type="submit" class="button">{{ trans('preferences.layout_edit_save') }}</button>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{{--
|
||||
$columnBlocks - array - Blocks to list
|
||||
$label - string - Section title
|
||||
$id - string - identifier for location/column
|
||||
--}}
|
||||
<div class="form-group flex">
|
||||
<label id="layout-blocks-{{ $id }}">{{ $label }}</label>
|
||||
<ul refs="layout-editor@column"
|
||||
data-column="{{ $id }}"
|
||||
aria-labelledby="layout-blocks-{{ $id }}"
|
||||
class="scroll-box available-option-list">
|
||||
<li class="text-muted empty-state px-m py-s italic text-small">{{ trans('preferences.layout_edit_empty') }}</li>
|
||||
@foreach($columnBlocks as $block)
|
||||
@include('settings.layouts.parts.block', ['block' => $block])
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
{{--
|
||||
$block - View Block instance to show
|
||||
--}}
|
||||
<li data-id="{{ $block->getLabel() }}"
|
||||
class="scroll-box-item items-center">
|
||||
<div class="handle px-s">@icon('grip')</div>
|
||||
<div class="text-small">{{ $block->getLabel() }}</div>
|
||||
<div class="buttons flex-container-row items-center ml-auto px-xxs py-xxs">
|
||||
<button type="button" data-action="move_up" class="icon-button p-xxs"
|
||||
title="{{ trans('entities.books_sort_move_up') }}">@icon('chevron-up')</button>
|
||||
<button type="button" data-action="move_down" class="icon-button p-xxs"
|
||||
title="{{ trans('entities.books_sort_move_down') }}">@icon('chevron-down')</button>
|
||||
<button type="button" data-action="remove" class="icon-button p-xxs"
|
||||
title="{{ trans('common.remove') }}">@icon('remove')</button>
|
||||
<button type="button" data-action="add" class="icon-button p-xxs"
|
||||
title="{{ trans('common.add') }}">@icon('add-small')</button>
|
||||
</div>
|
||||
</li>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\View;
|
||||
|
||||
use BookStack\View\ViewBlockDefaults;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ViewBlockDefaultsTest extends TestCase
|
||||
{
|
||||
public function test_each_has_a_unique_id_and_non_key_label()
|
||||
{
|
||||
$locations = ViewBlockDefaults::getLocations();
|
||||
$classes = [];
|
||||
$trueById = [];
|
||||
|
||||
foreach ($locations as $location) {
|
||||
$blocksByPosition = ViewBlockDefaults::getForLocation($location);
|
||||
foreach ($blocksByPosition as $blocks) {
|
||||
array_push($classes, ...$blocks);
|
||||
}
|
||||
}
|
||||
|
||||
$blocks = array_unique($classes);
|
||||
foreach ($blocks as $block) {
|
||||
$instance = app()->make($block);
|
||||
|
||||
$id = $instance->getId();
|
||||
$this->assertArrayNotHasKey($id, $trueById);
|
||||
$trueById[$id] = true;
|
||||
|
||||
$label = $instance->getLabel();
|
||||
$this->assertIsString($label);
|
||||
$this->assertDoesNotMatchRegularExpression('/^[a-z]{1,10}\./', $label);
|
||||
}
|
||||
|
||||
$this->assertGreaterThan(10, count($trueById));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user