diff --git a/css/backoffice/components/_all.scss b/css/backoffice/components/_all.scss
index efb91bdb1..5237baeba 100644
--- a/css/backoffice/components/_all.scss
+++ b/css/backoffice/components/_all.scss
@@ -32,4 +32,5 @@
@import "search-form";
@import "field-badge";
@import "file-select";
-@import "medallion-icon";
\ No newline at end of file
+@import "medallion-icon";
+@import "toast";
\ No newline at end of file
diff --git a/css/backoffice/components/_toast.scss b/css/backoffice/components/_toast.scss
new file mode 100644
index 000000000..4f9ddf66a
--- /dev/null
+++ b/css/backoffice/components/_toast.scss
@@ -0,0 +1,62 @@
+/*
+ * @copyright Copyright (C) 2010-2024 Combodo SARL
+ * @license http://opensource.org/licenses/AGPL-3.0
+ */
+
+/* SCSS variables */
+$ibo-toast--padding-y: $ibo-spacing-400 !default;
+$ibo-toast--padding-right: $ibo-spacing-300 !default;
+$ibo-toast--padding-left: $ibo-spacing-500 !default;
+$ibo-toast--border-radius: $ibo-border-radius-300 !default;
+$ibo-toast--box-shadow: $ibo-elevation-200 !default;
+$ibo-toast--max-width: calc(50% - 20px) !default;
+
+@keyframes decreaseHighlight {
+ 0% {
+ height: 100%;
+ }
+ 8%{
+ border-radius: 0 0 0 3px;
+ }
+ 100% {
+ height: 0;
+ }
+}
+
+.ibo-toast {
+ display: inline-flex;
+ position: fixed;
+ align-items: center;
+
+ max-width: $ibo-toast--max-width ;
+ padding: $ibo-toast--padding-y $ibo-toast--padding-right $ibo-toast--padding-y $ibo-toast--padding-left;
+ border-radius: $ibo-toast--border-radius;
+
+ box-shadow: $ibo-toast--box-shadow;
+ transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
+ z-index: 2147483647;
+ &::before {
+ @include ibo-vertical-highlight;
+ top: initial;
+ bottom: 0;
+ border-radius: $ibo-toast--border-radius 0 0 $ibo-toast--border-radius;
+ }
+ &.ibo-is-auto-closeable::before{
+ animation: decreaseHighlight 5s linear forwards;
+ }
+ &:hover::before {
+ animation: none; /* Pause animation on hover */
+ }
+ &.ibo-is-error{
+ @extend .ibo-alert.ibo-is-danger;
+ }
+ &.ibo-is-warning{
+ @extend .ibo-alert.ibo-is-warning;
+ }
+ &.ibo-is-success{
+ @extend .ibo-alert.ibo-is-success;
+ }
+ &.ibo-is-information{
+ @extend .ibo-alert.ibo-is-information;
+ }
+}
\ No newline at end of file
diff --git a/css/backoffice/vendors/_all.scss b/css/backoffice/vendors/_all.scss
index 81603f943..58e188c19 100644
--- a/css/backoffice/vendors/_all.scss
+++ b/css/backoffice/vendors/_all.scss
@@ -17,4 +17,5 @@
@import "jquery-treeview";
@import "jquery-blockui";
@import "magnific-popup";
-@import "selectize";
\ No newline at end of file
+@import "selectize";
+@import "toastify";
\ No newline at end of file
diff --git a/css/backoffice/vendors/_toastify.scss b/css/backoffice/vendors/_toastify.scss
new file mode 100644
index 000000000..b3678af4d
--- /dev/null
+++ b/css/backoffice/vendors/_toastify.scss
@@ -0,0 +1,76 @@
+/*
+ * @copyright Copyright (C) 2010-2024 Combodo SARL
+ * @license http://opensource.org/licenses/AGPL-3.0
+ */
+
+/* SCSS variables */
+
+$ibo-vendors-toastify--right--right: $ibo-spacing-500 !default;
+$ibo-vendors-toastify--left--left: $ibo-spacing-500 !default;
+$ibo-vendors-toastify--top--top: -150px !default;
+$ibo-vendors-toastify--bottom--bottom: -150px !default;
+
+$ibo-vendors-toastify--close--background: transparent !default;
+$ibo-vendors-toastify--close--padding: 0 !default;
+$ibo-vendors-toastify--close--margin-left: $ibo-spacing-300 !default;
+
+.toastify.on {
+ opacity: 1;
+}
+
+.toast-close {
+ background: $ibo-vendors-toastify--close--background;
+ border: 0;
+ color: inherit;
+ cursor: pointer;
+ font-family: inherit;
+ padding: $ibo-vendors-toastify--close--padding;
+ margin-left: $ibo-vendors-toastify--close--margin-left;
+}
+
+.toastify-right {
+ right: $ibo-vendors-toastify--right--right;
+}
+
+.toastify-left {
+ left: $ibo-vendors-toastify--left--left;
+}
+
+.toastify-top {
+ top: $ibo-vendors-toastify--top--top;
+}
+
+.toastify-bottom {
+ bottom: $ibo-vendors-toastify--bottom--bottom;
+}
+
+.toastify-rounded {
+ border-radius: 25px;
+}
+
+.toastify-avatar {
+ width: 1.5em;
+ height: 1.5em;
+ margin: -7px 5px;
+ border-radius: 2px;
+}
+
+.toastify-center {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ max-width: -moz-fit-content;
+}
+
+@media only screen and (max-width: 360px) {
+ .toastify-right, .toastify-left {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ }
+}
+
diff --git a/dictionaries/ui/pages/preferences/en.dictionary.itop.preferences.php b/dictionaries/ui/pages/preferences/en.dictionary.itop.preferences.php
index 3a552b8ba..6c24e4672 100644
--- a/dictionaries/ui/pages/preferences/en.dictionary.itop.preferences.php
+++ b/dictionaries/ui/pages/preferences/en.dictionary.itop.preferences.php
@@ -46,6 +46,9 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Preferences:Tabs:Scrollable:Label' => 'Navigation',
'UI:Preferences:Tabs:Scrollable:Classic' => 'Classic',
'UI:Preferences:Tabs:Scrollable:Scrollable' => 'Scrollable',
+ 'UI:Preferences:General:Toasts' => 'Toast notifications position',
+ 'UI:Preferences:General:Toasts:Bottom' => 'Bottom',
+ 'UI:Preferences:General:Toasts:Top' => 'Top',
'UI:Preferences:ChooseAPlaceholder' => 'User placeholder image',
'UI:Preferences:ChooseAPlaceholder+' => 'Choose a placeholder image that will be displayed if the contact linked to your user doesn\'t have one',
));
diff --git a/js/pages/backoffice/toolbox.js b/js/pages/backoffice/toolbox.js
index 41e8b4936..480793d62 100644
--- a/js/pages/backoffice/toolbox.js
+++ b/js/pages/backoffice/toolbox.js
@@ -458,6 +458,27 @@ CombodoModal.OpenInformativeModal = function(sMessage, sSeverity, oOptions) {
// Open modal
CombodoModal.OpenModal(oOptions);
}
+/**
+ * @override
+ * @inheritDoc
+ */
+CombodoToast.OpenToast = function(sMessage, sSeverity, aOptions) {
+ aOptions = $.extend({
+ text: sMessage,
+ className: "ibo-toast ibo-is-" + sSeverity,
+ duration: 6000,
+ close: true,
+ gravity: GetUserPreference('toasts_vertical_position', 'bottom'),
+ position: "right",
+ stopOnFocus: true,
+ }, aOptions);
+
+ if(aOptions.duration !== -1){
+ aOptions.className += ' ibo-is-auto-closeable';
+ }
+
+ Toastify(aOptions).showToast();
+};
// Processing on each pages of the backoffice
$(document).ready(function(){
diff --git a/js/utils.js b/js/utils.js
index 5de41a519..9e8feeed2 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -1574,4 +1574,63 @@ let CombodoModal = {
OpenErrorModal: function(sMessage, oOptions) {
CombodoModal.OpenInformativeModal(sMessage, CombodoModal.INFORMATIVE_MODAL_SEVERITY_ERROR, oOptions);
},
+};
+
+/**
+ * Abstract wrapper to manage toasts in iTop.
+ * Implementations for the various GUIs may vary but APIs are the same.
+ *
+ * @since 3.2.0
+ */
+let CombodoToast = {
+ /**
+ * Open a standard toast and put the content into it.
+ *
+ * @param sMessage {String} Message to be displayed in the toast
+ * @param sSeverity {String} Severity of the information. Default values are success, information, warning, error.
+ * @param aOptions {Object} {@see CombodoModal.OpenModal
+ */
+ OpenToast: function(sMessage, sSeverity, aOptions = {}) {
+ // Meant for overloading
+ CombodoJSConsole.Debug('CombodoToast.OpenToast not implemented');
+ },
+ /**
+ * Open a standard toast for success messages.
+ *
+ * @param sMessage {String} Success message to be displayed in the toast
+ * @param aOptions {Object} {@see CombodoModal.OpenModal
+ */
+ OpenSuccessToast: function(sMessage, aOptions = {}) {
+ CombodoToast.OpenToast(sMessage, 'success', aOptions);
+ },
+
+ /**
+ * Open a standard toast for information messages.
+ *
+ * @param sMessage {String} Information message to be displayed in the toast
+ * @param aOptions {Object} {@see CombodoModal.OpenModal
+ */
+ OpenInformationToast: function(sMessage, aOptions = {}) {
+ CombodoToast.OpenToast(sMessage, 'information', aOptions);
+ },
+
+ /**
+ * Open a standard toast for warning messages.
+ *
+ * @param sMessage {String} Warning message to be displayed in the toast
+ * @param aOptions {Object} {@see CombodoModal.OpenModal
+ */
+ OpenWarningToast: function(sMessage, aOptions = {}) {
+ CombodoToast.OpenToast(sMessage, 'warning', aOptions);
+ },
+
+ /**
+ * Open a standard toast for error messages.
+ *
+ * @param sMessage {String} Error message to be displayed in the toast
+ * @param aOptions {Object} {@see CombodoModal.OpenModal
+ */
+ OpenErrorToast: function(sMessage, aOptions = {}) {
+ CombodoToast.OpenToast(sMessage, 'error', aOptions);
+ }
};
\ No newline at end of file
diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
index 513ea2659..d319d2387 100644
--- a/node_modules/.package-lock.json
+++ b/node_modules/.package-lock.json
@@ -1,6 +1,6 @@
{
- "name": "dev-trunk",
- "lockfileVersion": 2,
+ "name": "iTop",
+ "lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@fontsource/raleway": {
@@ -88,6 +88,11 @@
"dependencies": {
"@popperjs/core": "^2.4.4"
}
+ },
+ "node_modules/toastify-js": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz",
+ "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ=="
}
}
}
diff --git a/node_modules/toastify-js/.gitattributes b/node_modules/toastify-js/.gitattributes
new file mode 100644
index 000000000..bdb0cabc8
--- /dev/null
+++ b/node_modules/toastify-js/.gitattributes
@@ -0,0 +1,17 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
diff --git a/node_modules/toastify-js/.prettierrc b/node_modules/toastify-js/.prettierrc
new file mode 100644
index 000000000..b909d0a75
--- /dev/null
+++ b/node_modules/toastify-js/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "useTabs": false,
+ "printWidth": 80,
+ "tabWidth": 2,
+ "singleQuote": false,
+ "trailingComma": "es5",
+ "parser": "babylon",
+ "noSemi": false
+}
diff --git a/node_modules/toastify-js/.travis.yml b/node_modules/toastify-js/.travis.yml
new file mode 100644
index 000000000..5b7005dc4
--- /dev/null
+++ b/node_modules/toastify-js/.travis.yml
@@ -0,0 +1,12 @@
+language: node_js
+node_js:
+ - "8"
+script:
+- echo "skipping tests"
+deploy:
+ skip_cleanup: true
+ provider: npm
+ email: $NPM_USERNAME
+ api_key: $NPM_TOKEN
+ on:
+ branch: master
\ No newline at end of file
diff --git a/node_modules/toastify-js/CHANGELOG.md b/node_modules/toastify-js/CHANGELOG.md
new file mode 100644
index 000000000..fcdc1f943
--- /dev/null
+++ b/node_modules/toastify-js/CHANGELOG.md
@@ -0,0 +1,133 @@
+# Changelog
+
+All the changes made to toastify-js library.
+
+## [1.12.0] - 2022-07-21
+
+* Accessibility fix: Support aria-live for the toast
+* Accessibility fix: Add aria-label for close icon
+
+## [1.11.2] - 2021-10-06
+
+* Bugfix: Style Options: "backgroundColor" not working! (#81)
+* Bugfix: "ShadowRoot is undefined" in older browsers (#83)
+
+## [1.11.1] - 2021-07-15
+
+* Bugfix: IE11 support broke since style option #77
+
+## [1.11.0] - 2021-04-25
+
+* New property `oldestFirst` allows to set the order of adding new toasts to page (#70 and #71)
+
+## [1.10.0] - 2021-03-25
+
+* `selector` now supports a DOM Node, along with ID string ([#65](https://github.com/apvarun/toastify-js/pull/65))
+* New property - `escapeMarkup` - Toggle the default behavior of escaping HTML markup
+* New property - `style` - Use the HTML DOM Style properties to add any style directly to toast
+* Adds `toastify-es.js`, to be used from node_modules until there are no compatibility issues
+
+### Deprecations:
+
+* `backgroundColor` is deprecated. Use `style.background` instead
+
+## [1.9.3] - 2020-10-10
+
+* Offset IE11 compatibility #64
+
+## [1.9.2] - 2020-09-24
+
+* Bugfix: Max width problem for firefox browser #61
+
+## [1.9.1] - 2020-08-13
+
+* Bugfix: Avatar positioning based on toast position
+
+## [1.9.0] - 2020-07-22
+
+* Add support for providing toast `offset`
+* Updated docs: offset
+
+## [1.8.0] - 2020-05-29
+
+* Add option to provide a node instead of text
+* Updated docs: permanent toast duration
+
+## [1.7.0] - 2020-03-01
+
+* To be able to set `stopOnFocus` for toasts without close icon
+* Bugfix: `duration` can be infinite by setting as `0`
+* Bugfix: Prevent errors when parent node is removed from DOM while using frameworks
+* Bugfix: IE 9/10 compatibility fix
+
+## [1.6.2] - 2020-01-03
+
+* Bugfix: Closing the toast when custom close icon from icon fonts are used
+
+## [1.6.1] - 2019-06-29
+
+* Bugfix: Disabling `stopOnFocus`
+
+## [1.6.0] - 2019-06-29
+
+* **Deprecation Warning**: Migrating from `positionLeft` property to `position`
+* Property `position` to support `center` as a value along with `left` and `right` - Useful for centering toast messages in the page
+
+## [1.5.0] - 2019-05-30
+
+* Added persistant toast option with ability to programatically close it
+
+## [1.4.0] - 2019-05-12
+
+* **Breaking Change**: Manually import CSS while using as module in your modern JavaScript applications
+* Ability to pause the toast dismiss timer on hover (Using `stopOnFocus` property)
+
+## [1.3.2] - 2018-12-6
+
+* Added z-index attribute
+
+## [1.2.1] - 2018-05-31
+
+* Added support for Classes. Now custom classes can be added to the toast while creating it
+
+## [1.2.0] - 2018-03-05
+
+* Fix issue when `destination` and `close` options is used at the same time
+
+## [1.1.0] - 2018-02-18
+
+* Browser support extended to IE10+ without any polyfills
+
+## [1.0.0] - 2018-02-17
+
+* Support for modules
+
+## [0.0.6] - 2017-09-09
+
+* Support for changing background [Options]
+* Optimized toast positioning logic
+* Added changelog for library update tracking
+
+## [0.0.5] - 2017-09-06
+
+* Support for toast messages on mobile screens
+* Tweaked close icon
+
+## [0.0.4] - 2017-09-05
+
+* Support for positioning of toasts on the page
+
+## [0.0.3] - 2017-09-05
+
+* Close buton for toasts [Options]
+
+## [0.0.2] - 2017-09-04
+
+* Option to add on-click link for toasts
+* Updated comments for code readability
+
+## [0.0.1] - 2017-09-02
+
+* Initial Release
+* Added Preview page
+* Optimized function structure
diff --git a/node_modules/toastify-js/LICENSE b/node_modules/toastify-js/LICENSE
new file mode 100644
index 000000000..506b07264
--- /dev/null
+++ b/node_modules/toastify-js/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 apvarun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/toastify-js/README.md b/node_modules/toastify-js/README.md
new file mode 100644
index 000000000..19363956f
--- /dev/null
+++ b/node_modules/toastify-js/README.md
@@ -0,0 +1,439 @@
+
+# Toastify
+
+
+
+[](https://www.npmjs.com/package/toastify-js)
+
+
+Toastify is a lightweight, vanilla JS toast notification library.
+
+## Demo
+
+[Click here](https://apvarun.github.io/toastify-js/)
+
+## Features
+
+* Multiple stacked notifications
+* Customizable
+* No blocking of execution thread
+
+### Customization options
+
+* Notification Text
+* Duration
+* Toast background color
+* Close icon display
+* Display position
+* Offset position
+
+## Installation
+
+#### Toastify now supports installation via NPM
+
+* Run the below command to add toastify-js to your exisitng or new project.
+
+```
+npm install --save toastify-js
+```
+
+or
+
+```
+yarn add toastify-js -S
+```
+
+* Import toastify-js into your module to start using it.
+
+```
+import Toastify from 'toastify-js'
+```
+
+You can use the default CSS from Toastify as below and later override it or choose to write your own CSS.
+
+```
+import "toastify-js/src/toastify.css"
+```
+
+#### Adding ToastifyJs to HTML page using the traditional method
+
+To start using **Toastify**, add the following CSS on to your page.
+
+```html
+
+```
+
+And the script at the bottom of the page
+
+```html
+
+```
+
+> Files are delivered via the CDN service provided by [jsdeliver](https://www.jsdelivr.com/)
+
+## Documentation
+
+```javascript
+Toastify({
+ text: "This is a toast",
+ duration: 3000,
+ destination: "https://github.com/apvarun/toastify-js",
+ newWindow: true,
+ close: true,
+ gravity: "top", // `top` or `bottom`
+ position: "left", // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ background: "linear-gradient(to right, #00b09b, #96c93d)",
+ },
+ onClick: function(){} // Callback after click
+}).showToast();
+```
+
+> Toast messages will be centered on devices with screen width less than 360px.
+
+* See the [changelog](https://github.com/apvarun/toastify-js/blob/master/CHANGELOG.md)
+
+### Add own custom classes
+
+If you want to use custom classes on the toast for customizing (like info or warning for example), you can do that as follows:
+
+```javascript
+Toastify({
+ text: "This is a toast",
+ className: "info",
+ style: {
+ background: "linear-gradient(to right, #00b09b, #96c93d)",
+ }
+}).showToast();
+```
+
+Multiple classes also can be assigned as a string, with spaces between class names.
+
+### Add some offset
+
+If you want to add offset to the toast, you can do that as follows:
+
+```javascript
+Toastify({
+ text: "This is a toast with offset",
+ offset: {
+ x: 50, // horizontal axis - can be a number or a string indicating unity. eg: '2em'
+ y: 10 // vertical axis - can be a number or a string indicating unity. eg: '2em'
+ },
+}).showToast();
+```
+
+Toast will be pushed 50px from right in x axis and 10px from top in y axis.
+
+**Note:**
+
+If `position` is equals to `left`, it will be pushed from left.
+If `gravity` is equals to `bottom`, it will be pushed from bottom.
+
+## API
+
+| Option Key | type | Usage | Defaults |
+|-----------------|----------------------|----------------------------------------------------------------------------|-------------|
+| text | string | Message to be displayed in the toast | "Hi there!" |
+| node | ELEMENT_NODE | Provide a node to be mounted inside the toast. `node` takes higher precedence over `text` | |
+| duration | number | Duration for which the toast should be displayed. -1 for permanent toast | 3000 |
+| selector | string \| ELEMENT_NODE | ShadowRoot | CSS Selector or Element Node on which the toast should be added | body |
+| destination | URL string | URL to which the browser should be navigated on click of the toast | |
+| newWindow | boolean | Decides whether the `destination` should be opened in a new window or not | false |
+| close | boolean | To show the close icon or not | false |
+| gravity | "top" or "bottom" | To show the toast from top or bottom | "top" |
+| position | "left" or "right" | To show the toast on left or right | "right" |
+| backgroundColor | CSS background value | To be deprecated, use `style.background` option instead. Sets the background color of the toast | |
+| avatar | URL string | Image/icon to be shown before text | |
+| className | string | Ability to provide custom class name for further customization | |
+| stopOnFocus | boolean | To stop timer when hovered over the toast (Only if duration is set) | true |
+| callback | Function | Invoked when the toast is dismissed | |
+| onClick | Function | Invoked when the toast is clicked | |
+| offset | Object | Ability to add some offset to axis | |
+| escapeMarkup | boolean | Toggle the default behavior of escaping HTML markup | true |
+| style | object | Use the HTML DOM Style properties to add any style directly to toast | |
+| ariaLive | string | Announce the toast to screen readers, see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions for options | "polite" |
+| oldestFirst | boolean | Set the order in which toasts are stacked in page | true |
+
+> Deprecated properties: `backgroundColor` - use `style.background` option instead
+
+## Browsers support
+
+| ![][ie] IE / Edge | ![][firefox] Firefox | ![][chrome] Chrome | ![][safari] Safari | ![][opera] Opera |
+| ---------------------- | ------------------------- | ----------------------- | ----------------------- | --------------------- |
+| IE10, IE11, Edge | last 10 versions | last 10 versions | last 10 versions | last 10 versions |
+
+## Contributors
+
+
+
+
+