Skip to content

Commit

Permalink
Page Drafts: Added new "Delete Draft" action to draft menu
Browse files Browse the repository at this point in the history
Provides a way for users to actually delte their user drafts where
required.
For #3927

Added test to cover new endpoint.

Makes update to MD editor #setText so that new selection is within new
range, otherwise it errors and fails operation.
  • Loading branch information
ssddanbrown committed Jun 13, 2023
1 parent f39938c commit b01bbf9
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 14 deletions.
15 changes: 14 additions & 1 deletion app/Entities/Controllers/PageRevisionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use BookStack\Activity\ActivityType;
use BookStack\Entities\Models\PageRevision;
use BookStack\Entities\Repos\PageRepo;
use BookStack\Entities\Repos\RevisionRepo;
use BookStack\Entities\Tools\PageContent;
use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity;
Expand All @@ -16,7 +17,8 @@
class PageRevisionController extends Controller
{
public function __construct(
protected PageRepo $pageRepo
protected PageRepo $pageRepo,
protected RevisionRepo $revisionRepo,
) {
}

Expand Down Expand Up @@ -154,4 +156,15 @@ public function destroy(string $bookSlug, string $pageSlug, int $revId)

return redirect($page->getUrl('/revisions'));
}

/**
* Destroys existing drafts, belonging to the current user, for the given page.
*/
public function destroyUserDraft(string $pageId)
{
$page = $this->pageRepo->getById($pageId);
$this->revisionRepo->deleteDraftsForCurrentUser($page);

return response('', 200);
}
}
4 changes: 3 additions & 1 deletion lang/en/entities.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@
'pages_editing_page' => 'Editing Page',
'pages_edit_draft_save_at' => 'Draft saved at ',
'pages_edit_delete_draft' => 'Delete Draft',
'pages_edit_delete_draft_confirm' => 'Are you sure you want to delete your draft page changes? All of your changes, since the last full save, will be lost and the editor will be updated with the latest page non-draft save state.',
'pages_edit_discard_draft' => 'Discard Draft',
'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
Expand Down Expand Up @@ -285,7 +286,8 @@
'time_b' => 'in the last :minCount minutes',
'message' => ':start :time. Take care not to overwrite each other\'s updates!',
],
'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content',
'pages_draft_discarded' => 'Draft discarded! The editor has been updated with the current page content',
'pages_draft_deleted' => 'Draft deleted! The editor has been updated with the current page content',
'pages_specific' => 'Specific Page',
'pages_is_template' => 'Page Template',

Expand Down
1 change: 1 addition & 0 deletions lang/en/errors.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@

// Pages
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content',
'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage',

// Entities
Expand Down
42 changes: 34 additions & 8 deletions resources/js/components/page-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ export class PageEditor extends Component {
this.saveDraftButton = this.$refs.saveDraft;
this.discardDraftButton = this.$refs.discardDraft;
this.discardDraftWrap = this.$refs.discardDraftWrap;
this.deleteDraftButton = this.$refs.deleteDraft;
this.deleteDraftWrap = this.$refs.deleteDraftWrap;
this.draftDisplay = this.$refs.draftDisplay;
this.draftDisplayIcon = this.$refs.draftDisplayIcon;
this.changelogInput = this.$refs.changelogInput;
this.changelogDisplay = this.$refs.changelogDisplay;
this.changeEditorButtons = this.$manyRefs.changeEditor || [];
this.switchDialogContainer = this.$refs.switchDialog;
this.deleteDraftDialogContainer = this.$refs.deleteDraftDialog;

// Translations
this.draftText = this.$opts.draftText;
this.autosaveFailText = this.$opts.autosaveFailText;
this.editingPageText = this.$opts.editingPageText;
this.draftDiscardedText = this.$opts.draftDiscardedText;
this.draftDeleteText = this.$opts.draftDeleteText;
this.draftDeleteFailText = this.$opts.draftDeleteFailText;
this.setChangelogText = this.$opts.setChangelogText;

// State data
Expand Down Expand Up @@ -75,6 +80,7 @@ export class PageEditor extends Component {
// Draft Controls
onSelect(this.saveDraftButton, this.saveDraft.bind(this));
onSelect(this.discardDraftButton, this.discardDraft.bind(this));
onSelect(this.deleteDraftButton, this.deleteDraft.bind(this));

// Change editor controls
onSelect(this.changeEditorButtons, this.changeEditor.bind(this));
Expand Down Expand Up @@ -119,7 +125,8 @@ export class PageEditor extends Component {
try {
const resp = await window.$http.put(`/ajax/page/${this.pageId}/save-draft`, data);
if (!this.isNewDraft) {
this.toggleDiscardDraftVisibility(true);
this.discardDraftWrap.toggleAttribute('hidden', false);
this.deleteDraftWrap.toggleAttribute('hidden', false);
}

this.draftNotifyChange(`${resp.data.message} ${Dates.utcTimeStampToLocalTime(resp.data.timestamp)}`);
Expand Down Expand Up @@ -154,7 +161,7 @@ export class PageEditor extends Component {
}, 2000);
}

async discardDraft() {
async discardDraft(notify = true) {
let response;
try {
response = await window.$http.get(`/ajax/page/${this.pageId}`);
Expand All @@ -168,7 +175,7 @@ export class PageEditor extends Component {
}

this.draftDisplay.innerText = this.editingPageText;
this.toggleDiscardDraftVisibility(false);
this.discardDraftWrap.toggleAttribute('hidden', true);
window.$events.emit('editor::replace', {
html: response.data.html,
markdown: response.data.markdown,
Expand All @@ -178,7 +185,30 @@ export class PageEditor extends Component {
window.setTimeout(() => {
this.startAutoSave();
}, 1000);
window.$events.emit('success', this.draftDiscardedText);

if (notify) {
window.$events.success(this.draftDiscardedText);
}
}

async deleteDraft() {
/** @var {ConfirmDialog} * */
const dialog = window.$components.firstOnElement(this.deleteDraftDialogContainer, 'confirm-dialog');
const confirmed = await dialog.show();
if (!confirmed) {
return;
}

try {
const discard = this.discardDraft(false);
const draftDelete = window.$http.delete(`/page-revisions/user-drafts/${this.pageId}`);
await Promise.all([discard, draftDelete]);
window.$events.success(this.draftDeleteText);
this.deleteDraftWrap.toggleAttribute('hidden', true);
} catch (err) {
console.error(err);
window.$events.error(this.draftDeleteFailText);
}
}

updateChangelogDisplay() {
Expand All @@ -191,10 +221,6 @@ export class PageEditor extends Component {
this.changelogDisplay.innerText = summary;
}

toggleDiscardDraftVisibility(show) {
this.discardDraftWrap.classList.toggle('hidden', !show);
}

async changeEditor(event) {
event.preventDefault();

Expand Down
4 changes: 3 additions & 1 deletion resources/js/markdown/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,9 @@ export class Actions {
*/
#setText(text, selectionRange = null) {
selectionRange = selectionRange || this.#getSelectionRange();
this.#dispatchChange(0, this.editor.cm.state.doc.length, text, selectionRange.from);
const newDoc = this.editor.cm.state.toText(text);
const newSelectFrom = Math.min(selectionRange.from, newDoc.length);
this.#dispatchChange(0, this.editor.cm.state.doc.length, text, newSelectFrom);
this.focus();
}

Expand Down
13 changes: 11 additions & 2 deletions resources/views/pages/parts/editor-toolbar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,22 @@ class="dropdown-container draft-display text {{ $draftsEnabled ? '' : 'hidden' }
</a>
</li>
@endif
<li refs="page-editor@discardDraftWrap" class="{{ $isDraftRevision ? '' : 'hidden' }}">
<button refs="page-editor@discardDraft" type="button" class="text-neg icon-item">
<li refs="page-editor@discard-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@discard-draft" type="button" class="text-warn icon-item">
@icon('cancel')
<div>{{ trans('entities.pages_edit_discard_draft') }}</div>
</button>
</li>
<li refs="page-editor@delete-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@delete-draft" type="button" class="text-neg icon-item">
@icon('delete')
<div>{{ trans('entities.pages_edit_delete_draft') }}</div>
</button>
</li>
@if(userCan('editor-change'))
<li>
<hr>
</li>
<li>
@if($editor === 'wysiwyg')
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=markdown-clean" refs="page-editor@changeEditor" class="icon-item">
Expand Down
11 changes: 10 additions & 1 deletion resources/views/pages/parts/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
option:page-editor:autosave-fail-text="{{ trans('errors.page_draft_autosave_fail') }}"
option:page-editor:editing-page-text="{{ trans('entities.pages_editing_page') }}"
option:page-editor:draft-discarded-text="{{ trans('entities.pages_draft_discarded') }}"
option:page-editor:draft-delete-text="{{ trans('entities.pages_draft_deleted') }}"
option:page-editor:draft-delete-fail-text="{{ trans('errors.page_draft_delete_fail') }}"
option:page-editor:set-changelog-text="{{ trans('entities.pages_edit_set_changelog') }}">

{{--Header Toolbar--}}
Expand Down Expand Up @@ -47,7 +49,7 @@
class="text-link text-button hide-over-m page-save-mobile-button">@icon('save')</button>

{{--Editor Change Dialog--}}
@component('common.confirm-dialog', ['title' => trans('entities.pages_editor_switch_title'), 'ref' => 'page-editor@switchDialog'])
@component('common.confirm-dialog', ['title' => trans('entities.pages_editor_switch_title'), 'ref' => 'page-editor@switch-dialog'])
<p>
{{ trans('entities.pages_editor_switch_are_you_sure') }}
<br>
Expand All @@ -60,4 +62,11 @@ class="text-link text-button hide-over-m page-save-mobile-button">@icon('save')<
<li>{{ trans('entities.pages_editor_switch_consideration_c') }}</li>
</ul>
@endcomponent

{{--Delete Draft Dialog--}}
@component('common.confirm-dialog', ['title' => trans('entities.pages_edit_delete_draft'), 'ref' => 'page-editor@delete-draft-dialog'])
<p>
{{ trans('entities.pages_edit_delete_draft_confirm') }}
</p>
@endcomponent
</div>
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
Route::get('/books/{bookSlug}/page/{pageSlug}/revisions/{revId}/changes', [EntityControllers\PageRevisionController::class, 'changes']);
Route::put('/books/{bookSlug}/page/{pageSlug}/revisions/{revId}/restore', [EntityControllers\PageRevisionController::class, 'restore']);
Route::delete('/books/{bookSlug}/page/{pageSlug}/revisions/{revId}/delete', [EntityControllers\PageRevisionController::class, 'destroy']);
Route::delete('/page-revisions/user-drafts/{pageId}', [EntityControllers\PageRevisionController::class, 'destroyUserDraft']);

// Chapters
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/create-page', [EntityControllers\PageController::class, 'create']);
Expand Down
24 changes: 24 additions & 0 deletions tests/Entity/PageDraftTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ public function test_page_html_in_ajax_fetch_response()
]);
}

public function test_user_draft_removed_on_user_drafts_delete_call()
{
$editor = $this->users->editor();
$page = $this->entities->page();

$this->actingAs($editor)->put('/ajax/page/' . $page->id . '/save-draft', [
'name' => $page->name,
'html' => '<p>updated draft again</p>',
]);

$revisionData = [
'type' => 'update_draft',
'created_by' => $editor->id,
'page_id' => $page->id,
];

$this->assertDatabaseHas('page_revisions', $revisionData);

$resp = $this->delete("/page-revisions/user-drafts/{$page->id}");

$resp->assertOk();
$this->assertDatabaseMissing('page_revisions', $revisionData);
}

public function test_updating_page_draft_with_markdown_retains_markdown_content()
{
$book = $this->entities->book();
Expand Down

0 comments on commit b01bbf9

Please sign in to comment.