diff --git a/app/app.js b/app/app.js index 45290a9775a490fb86d8dc7dace4af561ba294df..a6a2cdc843beef7d0a8bbd1a4a84ffc1f0dc3aa8 100644 --- a/app/app.js +++ b/app/app.js @@ -3,7 +3,7 @@ import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from 'papermerge/config/environment'; import '@popperjs/core'; -import 'bootstrap'; +import bootstrap from 'bootstrap'; export default class App extends Application { @@ -27,6 +27,13 @@ export default class App extends Application { if (divs.length > 0) { divs[0].style.display = 'None'; } + + /*Initializer bootstrap toasts*/ + let toastElList = [].slice.call(document.querySelectorAll('.toast')) + toastElList.map(function (toastEl) { + return new bootstrap.Toast(toastEl) + }) + } } diff --git a/app/components/notifications/index.hbs b/app/components/notifications/index.hbs new file mode 100644 index 0000000000000000000000000000000000000000..f6cc4c69f44c38490d03ac23a263d5254611dbdc --- /dev/null +++ b/app/components/notifications/index.hbs @@ -0,0 +1,5 @@ +<div class="toast-container position-fixed top-0 end-0 p-3"> + {{#each this.notifications as |notification|}} + <Notifications::Toast @notification={{notification}} /> + {{/each}} +</div> diff --git a/app/components/notifications/index.js b/app/components/notifications/index.js new file mode 100644 index 0000000000000000000000000000000000000000..e025c2d2c79ad692421a2e0a94bd4f21ed6c182b --- /dev/null +++ b/app/components/notifications/index.js @@ -0,0 +1,11 @@ +import Component from '@glimmer/component'; +import { service } from '@ember/service'; + + +export default class NotificationsComponent extends Component { + @service notify; + + get notifications() { + return this.notify.notifications; + } +} \ No newline at end of file diff --git a/app/components/notifications/toast/index.hbs b/app/components/notifications/toast/index.hbs new file mode 100644 index 0000000000000000000000000000000000000000..ac470689bd7cc5d9c3796f3dbc9e643b1882edea --- /dev/null +++ b/app/components/notifications/toast/index.hbs @@ -0,0 +1,21 @@ +<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true"> + <div class="toast-header"> + {{#if (is_equal this.type 'info') }} + <strong class="me-auto text-primary"> + <i class='bi bi-info-circle mx-2'></i>Info + </strong> + {{else if (is_equal this.type 'error')}} + <strong class="me-auto text-danger"> + <i class='bi bi-info-circle mx-2'></i>Error + </strong> + {{else}} + <strong class="me-auto text-warning"> + <i class='bi bi-info-circle mx-2'></i>Warning + </strong> + {{/if}} + <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> + </div> + <div class="toast-body"> + {{this.message}} + </div> +</div> diff --git a/app/components/notifications/toast/index.js b/app/components/notifications/toast/index.js new file mode 100644 index 0000000000000000000000000000000000000000..03f0ff49e29048be635cb7386473bc835477b2ab --- /dev/null +++ b/app/components/notifications/toast/index.js @@ -0,0 +1,12 @@ +import Component from '@glimmer/component'; + + +export default class ToastComponent extends Component { + get type() { + return this.args.notification.type; + } + + get message() { + return this.args.notification.message; + } +} \ No newline at end of file diff --git a/app/components/role/edit.js b/app/components/role/edit.js index 4096a3660ddff7ef63ccbe8b4ea8507450529868..2ff0d1c002f4963aa219588288d977565da59c92 100644 --- a/app/components/role/edit.js +++ b/app/components/role/edit.js @@ -1,6 +1,5 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; -import { tracked } from '@glimmer/tracking'; import { inject as service } from '@ember/service'; import { group_perms_by_model } from 'papermerge/utils'; diff --git a/app/components/viewer/action_buttons/index.hbs b/app/components/viewer/action_buttons/index.hbs index e52acb690179ea7adbedebeed4564624a35f91eb..67102cdac9e54c41f1e9c3476b5236b5c6936db8 100644 --- a/app/components/viewer/action_buttons/index.hbs +++ b/app/components/viewer/action_buttons/index.hbs @@ -31,10 +31,11 @@ {{#if @page_order_changed }} Page order changed. <button - class="btn btn-success" + class="btn btn-success pe-4" type="button" {{on "click" @onPageOrderApply}}> - Apply Changes + <Spinner @inProgress={{@apply_page_order_changes_in_progress}} /> + Apply Changes </button> <button class="btn btn-secondary" diff --git a/app/components/viewer/index.hbs b/app/components/viewer/index.hbs index 1925961bb7d809f71d10d11cc373c90fb5b96709..87dccdc290adcba37ec032396da02a2071b5f3e4 100644 --- a/app/components/viewer/index.hbs +++ b/app/components/viewer/index.hbs @@ -6,6 +6,7 @@ @ocrStatus={{this.ocrStatus}} @selectedPages={{this.selected_pages}} @page_order_changed={{this.page_order_changed}} + @apply_page_order_changes_in_progress={{this.apply_page_order_changes_in_progress}} @onPageOrderApply={{this.onPageOrderApply}} @onPageOrderDiscard={{this.onPageOrderDiscard}} @openConfirmDeletionModal={{this.openConfirmDeletionModal}} diff --git a/app/components/viewer/index.js b/app/components/viewer/index.js index 3afae65deb38ea79b212693c65b9f392ee01e9b1..ec2e4a26c4d574f1821b168f5b3e46388b25605f 100644 --- a/app/components/viewer/index.js +++ b/app/components/viewer/index.js @@ -23,6 +23,7 @@ export default class ViewerComponent extends Component { @service websockets; @service store; @service requests; + @service notify; @service router; @tracked ocr_status = null; @@ -38,6 +39,7 @@ export default class ViewerComponent extends Component { @tracked show_confirm_pages_deletion_modal = false; @tracked show_rename_node_modal = false; @tracked page_order_changed = false; + @tracked apply_page_order_changes_in_progress = false; initial_pages_memo = A([]); @@ -254,11 +256,26 @@ export default class ViewerComponent extends Component { @action async onPageOrderApply() { - await this.requests.reorderPagesApply({ + this.apply_page_order_changes_in_progress = true; + this.requests.reorderPagesApply({ old_items: this.initial_pages_memo, new_items: this.pages - }); - this.router.refresh(); + }).then( + () => { // on success + this.apply_page_order_changes_in_progress = false; + this.notify.info( + 'New page order successfully applied' + ); + this.page_order_changed = false; + }, + () => { // on failure + this.apply_page_order_changes_in_progress = false; + this.notify.error( + 'There was a problem while saving new page order' + ); + this.page_order_changed = false; + } + ); } @action diff --git a/app/services/notify.js b/app/services/notify.js new file mode 100644 index 0000000000000000000000000000000000000000..0c8df9b6e2cfe6205bb025809ec8f501e64c8ff0 --- /dev/null +++ b/app/services/notify.js @@ -0,0 +1,29 @@ +import Service from '@ember/service'; +import { tracked } from 'tracked-built-ins'; +import { TrackedArray } from 'tracked-built-ins'; + + +export default class Notify extends Service { + /* + Push notifications to your visitors with a toast, a lightweight and easily customizable alert message. + */ + @tracked notifications = new TrackedArray([]); + + info(message) { + let type = 'info'; + + this.notifications.push({message, type}); + } + + warning(message) { + let type = 'warning'; + + this.notifications.push({message, type}); + } + + error(message) { + let type = 'error'; + + this.notifications.push({message, type}); + } +} diff --git a/app/styles/app.scss b/app/styles/app.scss index 62e279daba65ce75b68079c2ac613aacd6eec65b..3bd27afe138dadb007d0555eda0abf8f70fb8302 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -73,3 +73,7 @@ main { .droparea { outline: 1px solid green; } + +.toast-container { + z-index: 1000; +} \ No newline at end of file diff --git a/app/templates/authenticated.hbs b/app/templates/authenticated.hbs index 56b274ac94251b0209ea59891ac0ccdead9420e7..a28f426d8d8d9b86fcf07bf1e338a16b40f08a9a 100644 --- a/app/templates/authenticated.hbs +++ b/app/templates/authenticated.hbs @@ -6,6 +6,7 @@ @pinned_tags={{@model.pinned_tags}} @expanded={{this.expanded_sidebar}} /> <div class="w-100 central-bar"> + <Notifications /> <Nav::Topbar @onSidebarToggle={{this.onSidebarToggle}} /> <div class="container-fluid mx-2 my-1"> diff --git a/package.json b/package.json index f208e376e7f1da7925e8aebfca9e729139121789..d26c93661dcea294a92a141312d3e38d1024e1da 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,8 @@ "prettier": "^2.5.1", "qunit": "^2.17.2", "qunit-dom": "^2.0.0", - "sass": "^1.47.0" + "sass": "^1.47.0", + "tracked-built-ins": "^2.0.1" }, "engines": { "node": "12.* || 14.* || >= 16" @@ -78,7 +79,6 @@ "edition": "octane" }, "devDependencies": { - "tracked-built-ins": "^2.0.1", "webpack": "^5.65.0" } }