mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-11-04 13:31:45 +03:00
API: Re-ordered routes, Improved navigation
Updated route order to follow some kind of logic. Updated scrolling sidebar to not be so cut-off in various scenarios. Added new nav helper to quick jump to specific API models. Closes #5865
This commit is contained in:
32
resources/js/components/api-nav.ts
Normal file
32
resources/js/components/api-nav.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import {Component} from "./component";
|
||||
|
||||
export class ApiNav extends Component {
|
||||
private select!: HTMLSelectElement;
|
||||
private sidebar!: HTMLElement;
|
||||
private body!: HTMLElement;
|
||||
|
||||
setup() {
|
||||
this.select = this.$refs.select as HTMLSelectElement;
|
||||
this.sidebar = this.$refs.sidebar;
|
||||
this.body = this.$el.ownerDocument.documentElement;
|
||||
this.select.addEventListener('change', () => {
|
||||
const section = this.select.value;
|
||||
const sidebarTarget = document.getElementById(`sidebar-header-${section}`);
|
||||
const contentTarget = document.getElementById(`section-${section}`);
|
||||
if (sidebarTarget && contentTarget) {
|
||||
|
||||
const sidebarPos = sidebarTarget.getBoundingClientRect().top - this.sidebar.getBoundingClientRect().top + this.sidebar.scrollTop;
|
||||
this.sidebar.scrollTo({
|
||||
top: sidebarPos - 120,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
|
||||
const bodyPos = contentTarget.getBoundingClientRect().top + this.body.scrollTop;
|
||||
this.body.scrollTo({
|
||||
top: bodyPos - 20,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export {AddRemoveRows} from './add-remove-rows';
|
||||
export {AjaxDeleteRow} from './ajax-delete-row';
|
||||
export {AjaxForm} from './ajax-form';
|
||||
export {ApiNav} from './api-nav';
|
||||
export {Attachments} from './attachments';
|
||||
export {AttachmentsList} from './attachments-list';
|
||||
export {AutoSuggest} from './auto-suggest';
|
||||
|
||||
@@ -274,7 +274,19 @@
|
||||
|
||||
.sticky-sidebar {
|
||||
position: sticky;
|
||||
top: vars.$m;
|
||||
max-height: calc(100vh - #{vars.$m});
|
||||
top: 0;
|
||||
padding-left: 2px;
|
||||
max-height: calc(100vh);
|
||||
overflow-y: auto;
|
||||
.sticky-sidebar-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: #F2F2F2;
|
||||
background: linear-gradient(180deg,rgba(242, 242, 242, 1) 66%, rgba(242, 242, 242, 0) 100%);
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
.dark-mode .sticky-sidebar-header {
|
||||
background: #111;
|
||||
background: linear-gradient(180deg,rgba(17, 17, 17, 1) 66%, rgba(17, 17, 17, 0) 100%);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,28 @@
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="container pt-xl">
|
||||
<div component="api-nav" class="container">
|
||||
|
||||
<div class="grid right-focus reverse-collapse">
|
||||
<div>
|
||||
|
||||
<div class="sticky-sidebar">
|
||||
<p class="text-uppercase text-muted mb-xm mt-l"><strong>Getting Started</strong></p>
|
||||
<div refs="api-nav@sidebar" class="sticky-sidebar">
|
||||
|
||||
<div class="sticky-sidebar-header py-xl">
|
||||
<select refs="api-nav@select" name="navigation" id="navigation">
|
||||
<option value="getting-started" selected>Jump To Section</option>
|
||||
<option value="getting-started">Getting Started</option>
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<option value="{{ str_replace(' ', '-', $model) }}">{{ ucfirst($model) }}</option>
|
||||
@if($model === 'docs' || $model === 'shelves')
|
||||
<hr>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-xl">
|
||||
<p id="sidebar-header-getting-started" class="text-uppercase text-muted mb-xm"><strong>Getting Started</strong></p>
|
||||
<div class="text-mono">
|
||||
<div class="mb-xs"><a href="#authentication">Authentication</a></div>
|
||||
<div class="mb-xs"><a href="#request-format">Request Format</a></div>
|
||||
@@ -18,9 +32,11 @@
|
||||
<div class="mb-xs"><a href="#rate-limits">Rate Limits</a></div>
|
||||
<div class="mb-xs"><a href="#content-security">Content Security</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<p class="text-uppercase text-muted mb-xm mt-l"><strong>{{ $model }}</strong></p>
|
||||
<div class="mb-xl">
|
||||
<p id="sidebar-header-{{ str_replace(' ', '-', $model) }}" class="text-uppercase text-muted mb-xm"><strong>{{ $model }}</strong></p>
|
||||
|
||||
@foreach($endpoints as $endpoint)
|
||||
<div class="mb-xs">
|
||||
@@ -32,18 +48,19 @@
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="overflow: auto;">
|
||||
<div class="pt-xl" style="overflow: auto;">
|
||||
|
||||
<section component="code-highlighter" class="card content-wrap auto-height">
|
||||
<section id="section-getting-started" component="code-highlighter" class="card content-wrap auto-height">
|
||||
@include('api-docs.parts.getting-started')
|
||||
</section>
|
||||
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<section class="card content-wrap auto-height">
|
||||
<section id="section-{{ str_replace(' ', '-', $model) }}" class="card content-wrap auto-height">
|
||||
<h1 class="list-heading text-capitals">{{ $model }}</h1>
|
||||
@if($endpoints[0]['model_description'])
|
||||
<p>{{ $endpoints[0]['model_description'] }}</p>
|
||||
|
||||
118
routes/api.php
118
routes/api.php
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* Routes for the BookStack API.
|
||||
* Routes have a uri prefix of /api/.
|
||||
* Routes have a URI prefix of /api/.
|
||||
* Controllers all end with "ApiController"
|
||||
*/
|
||||
|
||||
@@ -19,25 +19,18 @@ use BookStack\Users\Controllers\RoleApiController;
|
||||
use BookStack\Users\Controllers\UserApiController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('docs.json', [ApiDocsController::class, 'json']);
|
||||
// Main Entity Routes
|
||||
|
||||
Route::get('attachments', [AttachmentApiController::class, 'list']);
|
||||
Route::post('attachments', [AttachmentApiController::class, 'create']);
|
||||
Route::get('attachments/{id}', [AttachmentApiController::class, 'read']);
|
||||
Route::put('attachments/{id}', [AttachmentApiController::class, 'update']);
|
||||
Route::delete('attachments/{id}', [AttachmentApiController::class, 'delete']);
|
||||
|
||||
Route::get('books', [EntityControllers\BookApiController::class, 'list']);
|
||||
Route::post('books', [EntityControllers\BookApiController::class, 'create']);
|
||||
Route::get('books/{id}', [EntityControllers\BookApiController::class, 'read']);
|
||||
Route::put('books/{id}', [EntityControllers\BookApiController::class, 'update']);
|
||||
Route::delete('books/{id}', [EntityControllers\BookApiController::class, 'delete']);
|
||||
|
||||
Route::get('books/{id}/export/html', [ExportControllers\BookExportApiController::class, 'exportHtml']);
|
||||
Route::get('books/{id}/export/pdf', [ExportControllers\BookExportApiController::class, 'exportPdf']);
|
||||
Route::get('books/{id}/export/plaintext', [ExportControllers\BookExportApiController::class, 'exportPlainText']);
|
||||
Route::get('books/{id}/export/markdown', [ExportControllers\BookExportApiController::class, 'exportMarkdown']);
|
||||
Route::get('books/{id}/export/zip', [ExportControllers\BookExportApiController::class, 'exportZip']);
|
||||
Route::get('pages', [EntityControllers\PageApiController::class, 'list']);
|
||||
Route::post('pages', [EntityControllers\PageApiController::class, 'create']);
|
||||
Route::get('pages/{id}', [EntityControllers\PageApiController::class, 'read']);
|
||||
Route::put('pages/{id}', [EntityControllers\PageApiController::class, 'update']);
|
||||
Route::delete('pages/{id}', [EntityControllers\PageApiController::class, 'delete']);
|
||||
Route::get('pages/{id}/export/html', [ExportControllers\PageExportApiController::class, 'exportHtml']);
|
||||
Route::get('pages/{id}/export/pdf', [ExportControllers\PageExportApiController::class, 'exportPdf']);
|
||||
Route::get('pages/{id}/export/plaintext', [ExportControllers\PageExportApiController::class, 'exportPlainText']);
|
||||
Route::get('pages/{id}/export/markdown', [ExportControllers\PageExportApiController::class, 'exportMarkdown']);
|
||||
Route::get('pages/{id}/export/zip', [ExportControllers\PageExportApiController::class, 'exportZip']);
|
||||
|
||||
Route::get('chapters', [EntityControllers\ChapterApiController::class, 'list']);
|
||||
Route::post('chapters', [EntityControllers\ChapterApiController::class, 'create']);
|
||||
@@ -50,17 +43,43 @@ Route::get('chapters/{id}/export/plaintext', [ExportControllers\ChapterExportApi
|
||||
Route::get('chapters/{id}/export/markdown', [ExportControllers\ChapterExportApiController::class, 'exportMarkdown']);
|
||||
Route::get('chapters/{id}/export/zip', [ExportControllers\ChapterExportApiController::class, 'exportZip']);
|
||||
|
||||
Route::get('pages', [EntityControllers\PageApiController::class, 'list']);
|
||||
Route::post('pages', [EntityControllers\PageApiController::class, 'create']);
|
||||
Route::get('pages/{id}', [EntityControllers\PageApiController::class, 'read']);
|
||||
Route::put('pages/{id}', [EntityControllers\PageApiController::class, 'update']);
|
||||
Route::delete('pages/{id}', [EntityControllers\PageApiController::class, 'delete']);
|
||||
Route::get('books', [EntityControllers\BookApiController::class, 'list']);
|
||||
Route::post('books', [EntityControllers\BookApiController::class, 'create']);
|
||||
Route::get('books/{id}', [EntityControllers\BookApiController::class, 'read']);
|
||||
Route::put('books/{id}', [EntityControllers\BookApiController::class, 'update']);
|
||||
Route::delete('books/{id}', [EntityControllers\BookApiController::class, 'delete']);
|
||||
Route::get('books/{id}/export/html', [ExportControllers\BookExportApiController::class, 'exportHtml']);
|
||||
Route::get('books/{id}/export/pdf', [ExportControllers\BookExportApiController::class, 'exportPdf']);
|
||||
Route::get('books/{id}/export/plaintext', [ExportControllers\BookExportApiController::class, 'exportPlainText']);
|
||||
Route::get('books/{id}/export/markdown', [ExportControllers\BookExportApiController::class, 'exportMarkdown']);
|
||||
Route::get('books/{id}/export/zip', [ExportControllers\BookExportApiController::class, 'exportZip']);
|
||||
|
||||
Route::get('pages/{id}/export/html', [ExportControllers\PageExportApiController::class, 'exportHtml']);
|
||||
Route::get('pages/{id}/export/pdf', [ExportControllers\PageExportApiController::class, 'exportPdf']);
|
||||
Route::get('pages/{id}/export/plaintext', [ExportControllers\PageExportApiController::class, 'exportPlainText']);
|
||||
Route::get('pages/{id}/export/markdown', [ExportControllers\PageExportApiController::class, 'exportMarkdown']);
|
||||
Route::get('pages/{id}/export/zip', [ExportControllers\PageExportApiController::class, 'exportZip']);
|
||||
Route::get('shelves', [EntityControllers\BookshelfApiController::class, 'list']);
|
||||
Route::post('shelves', [EntityControllers\BookshelfApiController::class, 'create']);
|
||||
Route::get('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'read']);
|
||||
Route::put('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'update']);
|
||||
Route::delete('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'delete']);
|
||||
|
||||
// Additional Model Routes, in alphabetical order
|
||||
|
||||
Route::get('attachments', [AttachmentApiController::class, 'list']);
|
||||
Route::post('attachments', [AttachmentApiController::class, 'create']);
|
||||
Route::get('attachments/{id}', [AttachmentApiController::class, 'read']);
|
||||
Route::put('attachments/{id}', [AttachmentApiController::class, 'update']);
|
||||
Route::delete('attachments/{id}', [AttachmentApiController::class, 'delete']);
|
||||
|
||||
Route::get('audit-log', [ActivityControllers\AuditLogApiController::class, 'list']);
|
||||
|
||||
Route::get('comments', [ActivityControllers\CommentApiController::class, 'list']);
|
||||
Route::post('comments', [ActivityControllers\CommentApiController::class, 'create']);
|
||||
Route::get('comments/{id}', [ActivityControllers\CommentApiController::class, 'read']);
|
||||
Route::put('comments/{id}', [ActivityControllers\CommentApiController::class, 'update']);
|
||||
Route::delete('comments/{id}', [ActivityControllers\CommentApiController::class, 'delete']);
|
||||
|
||||
Route::get('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'read']);
|
||||
Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
|
||||
|
||||
Route::get('docs.json', [ApiDocsController::class, 'json']);
|
||||
|
||||
Route::get('image-gallery', [ImageGalleryApiController::class, 'list']);
|
||||
Route::post('image-gallery', [ImageGalleryApiController::class, 'create']);
|
||||
@@ -70,32 +89,6 @@ Route::get('image-gallery/{id}/data', [ImageGalleryApiController::class, 'readDa
|
||||
Route::put('image-gallery/{id}', [ImageGalleryApiController::class, 'update']);
|
||||
Route::delete('image-gallery/{id}', [ImageGalleryApiController::class, 'delete']);
|
||||
|
||||
Route::get('search', [SearchApiController::class, 'all']);
|
||||
|
||||
Route::get('comments', [ActivityControllers\CommentApiController::class, 'list']);
|
||||
Route::post('comments', [ActivityControllers\CommentApiController::class, 'create']);
|
||||
Route::get('comments/{id}', [ActivityControllers\CommentApiController::class, 'read']);
|
||||
Route::put('comments/{id}', [ActivityControllers\CommentApiController::class, 'update']);
|
||||
Route::delete('comments/{id}', [ActivityControllers\CommentApiController::class, 'delete']);
|
||||
|
||||
Route::get('shelves', [EntityControllers\BookshelfApiController::class, 'list']);
|
||||
Route::post('shelves', [EntityControllers\BookshelfApiController::class, 'create']);
|
||||
Route::get('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'read']);
|
||||
Route::put('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'update']);
|
||||
Route::delete('shelves/{id}', [EntityControllers\BookshelfApiController::class, 'delete']);
|
||||
|
||||
Route::get('users', [UserApiController::class, 'list']);
|
||||
Route::post('users', [UserApiController::class, 'create']);
|
||||
Route::get('users/{id}', [UserApiController::class, 'read']);
|
||||
Route::put('users/{id}', [UserApiController::class, 'update']);
|
||||
Route::delete('users/{id}', [UserApiController::class, 'delete']);
|
||||
|
||||
Route::get('roles', [RoleApiController::class, 'list']);
|
||||
Route::post('roles', [RoleApiController::class, 'create']);
|
||||
Route::get('roles/{id}', [RoleApiController::class, 'read']);
|
||||
Route::put('roles/{id}', [RoleApiController::class, 'update']);
|
||||
Route::delete('roles/{id}', [RoleApiController::class, 'delete']);
|
||||
|
||||
Route::get('imports', [ExportControllers\ImportApiController::class, 'list']);
|
||||
Route::post('imports', [ExportControllers\ImportApiController::class, 'create']);
|
||||
Route::get('imports/{id}', [ExportControllers\ImportApiController::class, 'read']);
|
||||
@@ -106,9 +99,18 @@ Route::get('recycle-bin', [EntityControllers\RecycleBinApiController::class, 'li
|
||||
Route::put('recycle-bin/{deletionId}', [EntityControllers\RecycleBinApiController::class, 'restore']);
|
||||
Route::delete('recycle-bin/{deletionId}', [EntityControllers\RecycleBinApiController::class, 'destroy']);
|
||||
|
||||
Route::get('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'read']);
|
||||
Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
|
||||
Route::get('roles', [RoleApiController::class, 'list']);
|
||||
Route::post('roles', [RoleApiController::class, 'create']);
|
||||
Route::get('roles/{id}', [RoleApiController::class, 'read']);
|
||||
Route::put('roles/{id}', [RoleApiController::class, 'update']);
|
||||
Route::delete('roles/{id}', [RoleApiController::class, 'delete']);
|
||||
|
||||
Route::get('audit-log', [ActivityControllers\AuditLogApiController::class, 'list']);
|
||||
Route::get('search', [SearchApiController::class, 'all']);
|
||||
|
||||
Route::get('system', [SystemApiController::class, 'read']);
|
||||
|
||||
Route::get('users', [UserApiController::class, 'list']);
|
||||
Route::post('users', [UserApiController::class, 'create']);
|
||||
Route::get('users/{id}', [UserApiController::class, 'read']);
|
||||
Route::put('users/{id}', [UserApiController::class, 'update']);
|
||||
Route::delete('users/{id}', [UserApiController::class, 'delete']);
|
||||
|
||||
Reference in New Issue
Block a user