mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°2039 - Rework view all notifications page (#617)
* N°2039 - Rework view all notifications page * N°2039 - Replace modals with toasts * N°2039 - Add bulk mode to view all notifications page * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Update css/backoffice/pages/_notifications.scss * Update dictionaries/ui/application/newsroom/fr.dictionary.itop.newsroom.php * Apply suggestions from code review Co-authored-by: Molkobain <lajarige.guillaume@free.fr> * Add since in phpdoc * Change newsroom empty notification illustration * N°2039 - Refactor code to factorize logic --------- Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
This commit is contained in:
@@ -390,7 +390,18 @@
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation/>
|
||||
<presentation>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="date">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="message">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
|
||||
@@ -49,3 +49,63 @@
|
||||
.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
// Toggler legacy CSS that has somehow been added to iTop 3.0 and that is now used by some extensions
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,9 @@ $ibo-panel--collapsible-toggler--margin-right: $ibo-spacing-300 !default;
|
||||
$ibo-panel--collapsible-toggler--font-size: $ibo-font-size-250 !default;
|
||||
$ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
|
||||
$ibo-panel--is-selectable--body--after--z-index: $ibo-panel--header--z-index + 1 !default;
|
||||
$ibo-panel--is-selectable--body--after--font-size: $ibo-font-size-700 !default;
|
||||
|
||||
/* Rules */
|
||||
.ibo-panel {
|
||||
--ibo-main-color: #{map-get($ibo-panel-colors, 'neutral')}; /* --ibo-main-color is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
|
||||
@@ -128,6 +131,30 @@ $ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.ibo-is-selectable .ibo-panel--body::after {
|
||||
@include ibo-selectable;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: $ibo-panel--is-selectable--body--after--z-index;
|
||||
font-size: $ibo-panel--is-selectable--body--after--font-size;
|
||||
}
|
||||
&.ibo-is-selectable:hover .ibo-panel--body::after {
|
||||
@include ibo-selectable-hover;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected .ibo-panel--body::after {
|
||||
@include ibo-selected;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected:hover .ibo-panel--body::after {
|
||||
@include ibo-selected-hover;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-panel--header {
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
@import "input-one-way-password";
|
||||
@import "input-set";
|
||||
@import "input-text";
|
||||
@import "input-toggler";
|
||||
|
||||
72
css/backoffice/components/input/_input-toggler.scss
Normal file
72
css/backoffice/components/input/_input-toggler.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-toggler--wrapper--width: 36px !default;
|
||||
$ibo-toggler--wrapper--height: 20px !default;
|
||||
|
||||
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
|
||||
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
|
||||
|
||||
$ibo-toggler--slider--before--height: 15px !default;
|
||||
$ibo-toggler--slider--before--width: 15px !default;
|
||||
$ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
|
||||
$ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default;
|
||||
$ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
|
||||
|
||||
$ibo-toggler--label--margin-left: 4px !default;
|
||||
|
||||
|
||||
.ibo-toggler--wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: $ibo-toggler--wrapper--width;
|
||||
height: $ibo-toggler--wrapper--height;
|
||||
vertical-align: baseline;
|
||||
.ibo-toggler {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-toggler--slider{
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: $ibo-toggler--slider--border-radius;
|
||||
background-color: $ibo-toggler--slider--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--slider:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
height: $ibo-toggler--slider--before--height;
|
||||
width: $ibo-toggler--slider--before--width;
|
||||
border-radius: $ibo-toggler--slider--before--border-radius;
|
||||
background-color: $ibo-toggler--slider--before--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--wrapper input:checked + .ibo-toggler--slider {
|
||||
background-color: $ibo-toggler--slider--checked--background-color;
|
||||
}
|
||||
|
||||
input:focus + .ibo-toggler--slider {
|
||||
box-shadow: $ibo-toggler--slider--focus--box-shadow;
|
||||
}
|
||||
|
||||
input:checked + .ibo-toggler--slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
label ~ .ibo-toggler--wrapper {
|
||||
margin-left: $ibo-toggler--label--margin-left;
|
||||
}
|
||||
@@ -63,62 +63,3 @@ $ibo-top-bar--toolbar-dashboard-title--max-width: 350px !default;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-object-summary--header--margin-y: $ibo-panel--highlight--height!default;
|
||||
$ibo-object-summary--header--margin-top: $ibo-panel--highlight--height!default;
|
||||
$ibo-object-summary--header--margin-bottom: $ibo-spacing-0!default;
|
||||
$ibo-object-summary--header--margin-x: $ibo-spacing-0 !default;
|
||||
|
||||
$ibo-object-summary--header--padding-y: $ibo-spacing-300 !default;
|
||||
@@ -51,7 +52,7 @@ $ibo-object-summary--content--attributes--code--padding-right: $ibo-spacing-500
|
||||
}
|
||||
|
||||
.ibo-object-summary--header{
|
||||
margin: $ibo-object-summary--header--margin-y $ibo-object-summary--header--margin-x;
|
||||
margin: $ibo-object-summary--header--margin-top $ibo-object-summary--header--margin-x $ibo-object-summary--header--margin-bottom $ibo-object-summary--header--margin-x;
|
||||
padding: $ibo-object-summary--header--padding-y $ibo-object-summary--header--padding-x;
|
||||
background-color: $ibo-object-summary--header--background-color;
|
||||
border-bottom: $ibo-object-summary--header--border;
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
@import "run-query";
|
||||
@import "welcome-popup";
|
||||
@import "oauth.wizard";
|
||||
@import "notifications";
|
||||
@import "notifications-center";
|
||||
66
css/backoffice/pages/_notifications.scss
Normal file
66
css/backoffice/pages/_notifications.scss
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-notifications--view-all--container--grid-gap: $ibo-spacing-600 !default;
|
||||
$ibo-notifications--view-all--container--object-summary--panel--body--max-height: unset !default;
|
||||
|
||||
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-red-600 !default;
|
||||
$ibo-notifications--view-all--item--read--highlight--background-color: $ibo-color-grey-200 !default;
|
||||
|
||||
$ibo-notifications--view-all--container--large--grid-template-columns: repeat(3, 1fr) !default;
|
||||
$ibo-notifications--view-all--container--medium--grid-template-columns: repeat(2, 1fr) !default;
|
||||
$ibo-notifications--view-all--container--small--grid-template-columns: repeat(1, 1fr) !default;
|
||||
|
||||
$ibo-notifications--view-all--empty--margin-top: $ibo-spacing-950 !default;
|
||||
$ibo-notifications--view-all--empty--svg--max-width: 30% !default;
|
||||
|
||||
.ibo-notifications--view-all--container{
|
||||
display: grid;
|
||||
grid-gap: $ibo-notifications--view-all--container--grid-gap;
|
||||
.ibo-object-summary .ibo-panel--title{
|
||||
font-size: $ibo-font-size-250;
|
||||
}
|
||||
.ibo-object-summary > .ibo-panel--body{
|
||||
box-shadow: none;
|
||||
max-height: $ibo-notifications--view-all--container--object-summary--panel--body--max-height;
|
||||
}
|
||||
.ibo-object-summary + .ibo-object-summary{
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@include mobile {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--small--grid-template-columns;
|
||||
}
|
||||
@include desktop {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--medium--grid-template-columns;
|
||||
}
|
||||
@include fullhd {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--large--grid-template-columns; }
|
||||
}
|
||||
.ibo-notifications--view-all--toolbar {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ibo-notifications--view-all--toggler {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--item--read .ibo-panel--body::before{
|
||||
background-color: $ibo-notifications--view-all--item--read--highlight--background-color;
|
||||
}
|
||||
.ibo-notifications--view-all--item--unread .ibo-panel--body::before{
|
||||
background-color: $ibo-notifications--view-all--item--unread--highlight--background-color;
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--empty {
|
||||
@extend %ibo-fully-centered-content;
|
||||
flex-direction: column;
|
||||
margin-top: $ibo-notifications--view-all--empty--margin-top;
|
||||
|
||||
svg {
|
||||
max-width: $ibo-notifications--view-all--empty--svg--max-width;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
@@ -4,3 +4,4 @@
|
||||
*/
|
||||
|
||||
@import "highlight";
|
||||
@import "selectable";
|
||||
40
css/backoffice/utils/mixins/_selectable.scss
Normal file
40
css/backoffice/utils/mixins/_selectable.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-selectable--background-color: transparent !default;
|
||||
|
||||
$ibo-selectable--hover--color: $ibo-color-grey-100 !default;
|
||||
$ibo-selectable--hover--background-color: $ibo-color-grey-600 !default;
|
||||
$ibo-selectable--hover--background-opacity: 0.6 !default;
|
||||
|
||||
$ibo-selected--color: $ibo-color-grey-100 !default;
|
||||
$ibo-selected--background-color: $ibo-color-grey-900 !default;
|
||||
$ibo-selected--background-opacity: 0.5 !default;
|
||||
|
||||
$ibo-selected--hover--background-color: $ibo-color-grey-700 !default;
|
||||
$ibo-selected--hover--background-opacity: 0.5 !default;
|
||||
@mixin ibo-selectable {
|
||||
content: ' ';
|
||||
@extend %fa-solid-base;
|
||||
background-color: $ibo-selectable--background-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
@mixin ibo-selectable-hover {
|
||||
@extend %fa-regular-base;
|
||||
content: '\f058';
|
||||
color: $ibo-selectable--hover--color;
|
||||
background-color: transparentize($ibo-selectable--hover--background-color, $ibo-selectable--hover--background-opacity);
|
||||
}
|
||||
|
||||
@mixin ibo-selected {
|
||||
@extend %fa-solid-base;
|
||||
content: '\f058';
|
||||
color: $ibo-selected--color;
|
||||
background-color: transparentize($ibo-selected--background-color, $ibo-selected--background-opacity);
|
||||
}
|
||||
|
||||
@mixin ibo-selected-hover {
|
||||
background-color: transparentize($ibo-selected--hover--background-color, $ibo-selected--hover--background-opacity);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ $ibo-spacing-600: $ibo-size-300 !default;
|
||||
$ibo-spacing-700: $ibo-size-350 !default;
|
||||
$ibo-spacing-800: $ibo-size-400 !default;
|
||||
$ibo-spacing-900: $ibo-size-450 !default;
|
||||
$ibo-spacing-950: $ibo-size-500 !default;
|
||||
|
||||
:root{
|
||||
--ibo-spacing-0: #{$ibo-size-0};
|
||||
|
||||
@@ -15,6 +15,9 @@ $ibo-font-size-400: 2rem !default; /* 24px */
|
||||
$ibo-font-size-450: 2.5rem !default; /* 30px */
|
||||
$ibo-font-size-500: 3rem !default; /* 36px */
|
||||
$ibo-font-size-550: 4rem !default; /* 48px */
|
||||
$ibo-font-size-600: 5rem !default; /* 60px */
|
||||
$ibo-font-size-650: 6rem !default; /* 72px */
|
||||
$ibo-font-size-700: 7rem !default; /* 84px */
|
||||
|
||||
/* Value Common weight name (https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight) */
|
||||
$ibo-font-weight-100: 100 !default; /* 100 Thin (Harline) */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
* Copyright (C) 2013-2024 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -19,5 +19,44 @@
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Newsroom:iTopNotification:Label' => ITOP_APPLICATION_SHORT,
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Title' => ITOP_APPLICATION_SHORT.' notifications',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Title' => 'Your ' . ITOP_APPLICATION_SHORT.' notifications',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Read:Label' => 'Read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Unread:Label' => 'Unread',
|
||||
'UI:Newsroom:iTopNotification:SelectMode:Label' => 'Select mode',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsRead:Label' => 'Mark all as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsUnread:Label' => 'Mark all as unread',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Label' => 'Delete all',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Success:Message' => 'All %1$s notifications have been deleted',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Title' => 'Delete all notifications',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Message' => 'Are you sure you want to delete all notifications?',
|
||||
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Empty:Title' => 'No notification, you are up to date!',
|
||||
|
||||
// Actions
|
||||
// - Unitary buttons
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Label' => 'Delete this notification',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:ViewObject:Label' => 'Go to the notification url',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Label' => 'Mark as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Label' => 'Mark as unread',
|
||||
// - Bulk buttons
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsRead:Label' => 'Mark selected as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsUnread:Label' => 'Mark selected as unread',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Label' => 'Delete selected',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Title' => 'Delete selected notifications',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Message' => 'Are you sure you want to delete selected notifications?',
|
||||
|
||||
// Feedback messages
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:InvalidAction:Message' => 'Invalid action: "%1$s"',
|
||||
// - Mark as read
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:NoEvent:Message' => 'No notification to mark as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Success:Message' => 'The notification has been marked as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsReadMultiple:Success:Message' => '%1$s notifications have been marked as read',
|
||||
// - Mark as unread
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:NoEvent:Message' => 'No notification to mark as read',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Success:Message' => 'The notification has been marked as unread',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnreadMultiple:Success:Message' => '%1$s notifications have been marked as unread',
|
||||
// Delete
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:NoEvent:Message' => 'No notification to delete',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Success:Message' => 'The notification has been deleted',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteMultiple:Success:Message' => '%1$s notifications have been deleted',
|
||||
));
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Newsroom:iTopNotification:Label' => ITOP_APPLICATION_SHORT,
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Title' => 'Vos notifications ' . ITOP_APPLICATION_SHORT,
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Read:Label' => 'Lue',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Unread:Label' => 'Non lue',
|
||||
'UI:Newsroom:iTopNotification:SelectMode:Label' => 'Sélection multiple',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsRead:Label' => 'Marquer tout comme lu',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsUnread:Label' => 'Marquer tout comme non lu',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Label' => 'Supprimer tout',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Success:Message' => '%1$s notifications ont été supprimées',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Title' => 'Supprimer toutes les notifications',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Message' => 'Êtes-vous sûr de vouloir supprimer toutes les notifications ?',
|
||||
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Empty:Title' => 'Aucune notification, vous êtes à jour !',
|
||||
|
||||
// Actions
|
||||
// - Unitary buttons
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Label' => 'Supprimer cette notification',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:ViewObject:Label' => 'Aller à l\'url de la notification',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Label' => 'Marquer comme lu',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Label' => 'Marquer comme non lu',
|
||||
// - Bulk buttons
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsRead:Label' => 'Marquer sélectionnée(s) comme lu',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsUnread:Label' => 'Marquer sélectionnée(s) comme non lu',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Label' => 'Supprimer sélectionnée(s)',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Title' => 'Supprimer les notifications sélectionnées',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Message' => 'Êtes-vous sûr de vouloir supprimer les notifications sélectionnées ?',
|
||||
|
||||
// Feedback messages
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:InvalidAction:Message' => 'Action invalide : "%1$s"',
|
||||
// - Mark as read
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:NoEvent:Message' => 'Aucune notification à marquer comme lue',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Success:Message' => 'La notification a été marquée comme lue',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsReadMultiple:Success:Message' => '%1$s notifications ont été marquées comme lues',
|
||||
// - Mark as unread
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:NoEvent:Message' => 'Aucune notification à marquer comme non lue',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Success:Message' => 'La notification a été marquée comme non lue',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnreadMultiple:Success:Message' => '%1$s notifications ont été marquées comme non lues',
|
||||
// Delete
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:NoEvent:Message' => 'Aucune notification à supprimer',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Success:Message' => 'La notification a été supprimée',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteMultiple:Success:Message' => '%1$s notifications ont été supprimées',
|
||||
));
|
||||
49
images/illustrations/undraw_social_serenity.svg
Normal file
49
images/illustrations/undraw_social_serenity.svg
Normal file
@@ -0,0 +1,49 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="870.4" height="598.682" viewBox="0 0 870.4 598.682" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Group_14" data-name="Group 14" transform="translate(-182.787 -183.377)">
|
||||
<g id="Group_9" data-name="Group 9" transform="translate(-237 346.007)">
|
||||
<path id="Path_141-368" data-name="Path 141" d="M827.279,436.053H539.012a5.345,5.345,0,0,1-5.338-5.338V184.207a5.345,5.345,0,0,1,5.338-5.338H827.279a5.345,5.345,0,0,1,5.338,5.338V430.714a5.344,5.344,0,0,1-5.338,5.338ZM539.012,181a3.207,3.207,0,0,0-3.2,3.2V430.714a3.207,3.207,0,0,0,3.2,3.2H827.279a3.206,3.206,0,0,0,3.2-3.2V184.207a3.207,3.207,0,0,0-3.2-3.2Z" transform="translate(-44.905)" fill="#e6e6e6"/>
|
||||
<circle id="Ellipse_19" data-name="Ellipse 19" cx="21.745" cy="21.745" r="21.745" transform="translate(517.152 370.472)" fill="#e6e6e6"/>
|
||||
<path id="Path_142-369" data-name="Path 142" d="M634.024,377.72a3.624,3.624,0,0,0,0,7.248H804.88a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.905)" fill="#e6e6e6"/>
|
||||
<path id="Path_143-370" data-name="Path 143" d="M634.024,399.466a3.624,3.624,0,0,0,0,7.248h73.52a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.905)" fill="#e6e6e6"/>
|
||||
<path id="Path_154-371" data-name="Path 154" d="M895.768,350.074H607.5a5.344,5.344,0,0,1-5.338-5.338V218.229a5.344,5.344,0,0,1,5.338-5.338H895.768a5.344,5.344,0,0,1,5.338,5.338V344.736A5.344,5.344,0,0,1,895.768,350.074Z" transform="translate(-44.905)" fill="#6c63ff"/>
|
||||
<path id="Path_155-372" data-name="Path 155" d="M666.206,256.985a3.624,3.624,0,0,0,0,7.248H837.063a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.905)" fill="#fff"/>
|
||||
<path id="Path_156-373" data-name="Path 156" d="M666.206,277.985a3.624,3.624,0,0,0,0,7.248H837.063a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.905)" fill="#fff"/>
|
||||
<path id="Path_157-374" data-name="Path 157" d="M666.206,298.731a3.624,3.624,0,0,0,0,7.248h73.52a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.905)" fill="#fff"/>
|
||||
</g>
|
||||
<rect id="Rectangle_1" data-name="Rectangle 1" width="870.4" height="2" transform="translate(182.787 779.636)" fill="#3f3d56"/>
|
||||
<g id="Group_10" data-name="Group 10" transform="translate(100 164.584)">
|
||||
<path id="Path_138-375" data-name="Path 138" d="M883.279,615.053H595.012a5.345,5.345,0,0,1-5.338-5.338V538.207a5.345,5.345,0,0,1,5.338-5.338H883.279a5.345,5.345,0,0,1,5.338,5.338v71.507A5.345,5.345,0,0,1,883.279,615.053ZM595.012,535a3.207,3.207,0,0,0-3.2,3.2v71.507a3.207,3.207,0,0,0,3.2,3.2H883.279a3.206,3.206,0,0,0,3.2-3.2V538.207a3.206,3.206,0,0,0-3.2-3.2Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
<circle id="Ellipse_18" data-name="Ellipse 18" cx="21.745" cy="21.745" r="21.745" transform="translate(573.152 549.472)" fill="#e6e6e6"/>
|
||||
<path id="Path_139-376" data-name="Path 139" d="M690.024,556.72a3.624,3.624,0,0,0,0,7.248H860.88a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
<path id="Path_140-377" data-name="Path 140" d="M690.024,578.466a3.624,3.624,0,0,0,0,7.248h73.52a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
</g>
|
||||
<g id="Group_11" data-name="Group 11" transform="matrix(0.914, 0.407, -0.407, 0.914, 266.183, -179.59)">
|
||||
<path id="Path_135-378" data-name="Path 135" d="M811.279,721.053H523.012a5.345,5.345,0,0,1-5.338-5.338V644.207a5.344,5.344,0,0,1,5.338-5.338H811.279a5.345,5.345,0,0,1,5.338,5.338v71.507a5.345,5.345,0,0,1-5.338,5.338ZM523.012,641a3.207,3.207,0,0,0-3.2,3.2v71.507a3.207,3.207,0,0,0,3.2,3.2H811.279a3.206,3.206,0,0,0,3.2-3.2V644.207a3.207,3.207,0,0,0-3.2-3.2Z" transform="translate(112.094 -174.499)" fill="#e6e6e6"/>
|
||||
<circle id="Ellipse_17" data-name="Ellipse 17" cx="21.745" cy="21.745" r="21.745" transform="translate(658.152 480.973)" fill="#e6e6e6"/>
|
||||
<path id="Path_136-379" data-name="Path 136" d="M618.024,662.72a3.624,3.624,0,0,0,0,7.248H788.88a3.624,3.624,0,1,0,0-7.248Z" transform="translate(112.094 -174.499)" fill="#e6e6e6"/>
|
||||
<path id="Path_137-380" data-name="Path 137" d="M618.024,684.466a3.624,3.624,0,1,0,0,7.248h73.52a3.624,3.624,0,0,0,0-7.248Z" transform="translate(112.094 -174.499)" fill="#e6e6e6"/>
|
||||
</g>
|
||||
<g id="Group_12" data-name="Group 12" transform="matrix(0.996, -0.087, 0.087, 0.996, -217.382, -42.579)">
|
||||
<path id="Path_138-2-381" data-name="Path 138" d="M883.279,615.053H595.012a5.345,5.345,0,0,1-5.338-5.338V538.207a5.345,5.345,0,0,1,5.338-5.338H883.279a5.345,5.345,0,0,1,5.338,5.338v71.507A5.345,5.345,0,0,1,883.279,615.053ZM595.012,535a3.207,3.207,0,0,0-3.2,3.2v71.507a3.207,3.207,0,0,0,3.2,3.2H883.279a3.206,3.206,0,0,0,3.2-3.2V538.207a3.206,3.206,0,0,0-3.2-3.2Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
<circle id="Ellipse_18-2" data-name="Ellipse 18" cx="21.745" cy="21.745" r="21.745" transform="translate(573.152 549.472)" fill="#e6e6e6"/>
|
||||
<path id="Path_139-2-382" data-name="Path 139" d="M690.024,556.72a3.624,3.624,0,0,0,0,7.248H860.88a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
<path id="Path_140-2-383" data-name="Path 140" d="M690.024,578.466a3.624,3.624,0,0,0,0,7.248h73.52a3.624,3.624,0,0,0,0-7.248Z" transform="translate(-44.906)" fill="#e6e6e6"/>
|
||||
</g>
|
||||
<g id="Group_13" data-name="Group 13" transform="translate(-1676 -1453.057)">
|
||||
<circle id="Ellipse_21" data-name="Ellipse 21" cx="33" cy="33" r="33" transform="translate(2259.759 1653.646)" fill="#2f2e41"/>
|
||||
<circle id="Ellipse_22" data-name="Ellipse 22" cx="24.561" cy="24.561" r="24.561" transform="translate(2268.868 1673.439)" fill="#feb8b8"/>
|
||||
<path id="Path_159-384" data-name="Path 159" d="M902.978,629.758s-45-8-74,2l8.5,67.5-2,11,60-2-4-11Z" transform="translate(1427.781 1103.888)" fill="#feb8b8"/>
|
||||
<path id="Path_160-385" data-name="Path 160" d="M871.707,702.6a302.545,302.545,0,0,1-31-1.964,8.492,8.492,0,0,1-7.561-8.645l.73-31.567.085-.123c8.694-12.593,4.459-21.791,1.2-26.743a6.4,6.4,0,0,1-1.052-3.522h0c-.5-.7-.612.405-.3-.379a2.51,2.51,0,0,1,1.836-1.538l4.964-.992a2.5,2.5,0,0,1,2.858,1.651c1.668,4.977,8.169,20.991,23.066,20.987,12.445,0,17.089-17.611,17.367-21.681a2.5,2.5,0,0,1,2.493-2.322h6.2a2.617,2.617,0,0,1,2.066.934,2.48,2.48,0,0,1,.244,2.751c-7.076,13.01,3.265,33.6,3.37,33.8l.066.13-2.918,30.293a8.541,8.541,0,0,1-6.574,7.477C884.336,702.206,878.239,702.6,871.707,702.6Z" transform="translate(1427.781 1103.888)" fill="#ccc"/>
|
||||
<path id="Path_161-386" data-name="Path 161" d="M814.6,772.888c-6.72,0-12.872-.74-17.76-2.489-5.81-2.079-9.458-5.441-10.844-10a13.2,13.2,0,0,1,1.606-11.673c8.595-12.87,38.421-16.5,42.423-16.929l2.12-17.667a8.531,8.531,0,0,1,8.307-7.486l50.232-.784a8.421,8.421,0,0,1,8.5,6.977l2.854,15.7L869.1,744.512l4.98,13.945-.325.217C864.115,765.1,836.392,772.887,814.6,772.888Z" transform="translate(1427.781 1103.888)" fill="#2f2e41"/>
|
||||
<path id="Path_162-387" data-name="Path 162" d="M897.478,726.258s46-6,43,18-38,41-91,0l6-12s30,8,42,2Z" transform="translate(1427.781 1103.888)" fill="#2f2e41"/>
|
||||
<path id="Path_163-388" data-name="Path 163" d="M856.478,735.258s0-12-10-11-28,2-28,2-6,4,2,6,32,12,32,12Z" transform="translate(1427.781 1103.888)" fill="#feb8b8"/>
|
||||
<path id="Path_164-389" data-name="Path 164" d="M873.478,733.258s0-12,10-11,28,2,28,2,6,4-2,6-32,12-32,12Z" transform="translate(1427.781 1103.888)" fill="#feb8b8"/>
|
||||
<path id="Path_165-390" data-name="Path 165" d="M933.4,730.985l-14.921-51.727s-3-18-6-35-14-15-14-15l-2,1v27l2,25,19.965,54.9a10.5,10.5,0,1,0,14.956-6.177Z" transform="translate(1427.781 1103.888)" fill="#feb8b8"/>
|
||||
<path id="Path_166-391" data-name="Path 166" d="M832.478,631.258s-11-2-14,15-6,35-6,35l-14.921,51.727a10.5,10.5,0,1,0,14.956,6.177l19.965-54.9,2-25V634.494a3.618,3.618,0,0,0-2-3.236Z" transform="translate(1427.781 1103.888)" fill="#feb8b8"/>
|
||||
<path id="Path_167-392" data-name="Path 167" d="M841.335,579.024a73.043,73.043,0,0,0,31.6,10.412l-3.331-3.991a24.48,24.48,0,0,0,7.561,1.5,8.281,8.281,0,0,0,6.75-3.159,7.7,7.7,0,0,0,.516-7.115,14.588,14.588,0,0,0-4.589-5.739,27.323,27.323,0,0,0-25.431-4.545,16.33,16.33,0,0,0-7.6,4.872,9.236,9.236,0,0,0-1.863,8.561" transform="translate(1427.781 1103.888)" fill="#2f2e41"/>
|
||||
<path id="Path_168-393" data-name="Path 168" d="M868.084,553.421a75.485,75.485,0,0,0-27.463-17.759c-6.639-2.459-13.865-3.979-20.805-2.582s-13.5,6.2-15.44,13.008c-1.583,5.568.052,11.564,2.509,16.806s5.738,10.1,7.725,15.54A35.468,35.468,0,0,1,778.92,626c6.819.914,13.105,4.119,19.771,5.825s14.533,1.59,19.486-3.185c5.241-5.052,5.346-13.267,5.092-20.542l-1.13-32.445c-.192-5.515-.356-11.208,1.633-16.356s6.716-9.656,12.235-9.609c4.183.036,7.884,2.569,11.239,5.068s6.9,5.165,11.071,5.536,8.923-2.711,8.611-6.883" transform="translate(1427.781 1103.888)" fill="#2f2e41"/>
|
||||
</g>
|
||||
<path id="Path_133-394" data-name="Path 133" d="M318.432,675.924a158.394,158.394,0,0,1-7.4,43.785c-.1.329-.211.653-.319.982H283.1c.029-.295.059-.624.088-.982,1.841-21.166-8.677-148.453-21.369-170.483C262.931,551.013,320.573,608.67,318.432,675.924Z" transform="translate(697.642 58.945)" fill="#e6e6e6"/>
|
||||
<path id="Path_134-395" data-name="Path 134" d="M284.933,719.709c-.231.329-.471.658-.717.982H263.5c.157-.28.339-.609.55-.982,3.422-6.176,13.551-24.642,22.953-43.785,10.1-20.572,19.374-41.924,18.593-49.652C305.838,628.014,312.83,681.148,284.933,719.709Z" transform="translate(729.069 58.945)" fill="#e6e6e6"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
35
js/pages/backoffice/itop-newsroom.view-all.js
Normal file
35
js/pages/backoffice/itop-newsroom.view-all.js
Normal file
@@ -0,0 +1,35 @@
|
||||
$('body').on('change', '.ibo-toggler', function() {
|
||||
$('.ibo-notifications--view-all--bulk-buttons').toggleClass('ibo-is-hidden');
|
||||
$('.ibo-object-summary').toggleClass('ibo-is-selectable').removeClass('ibo-is-selected');
|
||||
});
|
||||
|
||||
$('body').on('click', '.ibo-object-summary.ibo-is-selectable', function() {
|
||||
$(this).toggleClass('ibo-is-selected');
|
||||
});
|
||||
|
||||
$('body').on('itop.notification.deleted', '.ibo-notifications--view-all--container', function() {
|
||||
if($(this).find('.ibo-object-summary').length === 0) {
|
||||
$('.ibo-notifications--view-all--empty').removeClass('ibo-is-hidden');
|
||||
$('.ibo-notifications--view-all--container').addClass('ibo-is-hidden');
|
||||
$('.ibo-notifications--view-all--read-action').attr('disabled', 'disabled');
|
||||
$('.ibo-notifications--view-all--unread-action').attr('disabled', 'disabled');
|
||||
$('.ibo-notifications--view-all--delete-action').attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
|
||||
let fReadUnreadDisabled = function() {
|
||||
if($('.ibo-object-summary.ibo-notifications--view-all--item--unread').length === 0) {
|
||||
$('.ibo-notifications--view-all--read-action').attr('disabled', 'disabled');
|
||||
$('.ibo-notifications--view-all--unread-action').removeAttr('disabled');
|
||||
} else if ($('.ibo-object-summary.ibo-notifications--view-all--item--read').length === 0) {
|
||||
$('.ibo-notifications--view-all--read-action').removeAttr('disabled');
|
||||
$('.ibo-notifications--view-all--unread-action').attr('disabled', 'disabled');
|
||||
} else {
|
||||
$('.ibo-notifications--view-all--read-action').removeAttr('disabled');
|
||||
$('.ibo-notifications--view-all--unread-action').removeAttr('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
$('body').on('itop.notification.read itop.notification.unread', '.ibo-notifications--view-all--container', fReadUnreadDisabled);
|
||||
|
||||
$('body').on('itop.notification.unread', '.ibo-notifications--view-all--container', fReadUnreadDisabled);
|
||||
@@ -265,6 +265,7 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Set\\Set' => $baseDir . '/sources/Application/UI/Base/Component/Input/Set/Set.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Set\\SetUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Input/Set/SetUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\TextArea' => $baseDir . '/sources/Application/UI/Base/Component/Input/TextArea.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Toggler' => $baseDir . '/sources/Application/UI/Base/Component/Input/Toggler.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\tInputLabel' => $baseDir . '/sources/Application/UI/Base/Component/Input/tInputLabel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\MedallionIcon\\MedallionIcon' => $baseDir . '/sources/Application/UI/Base/Component/MedallionIcon/MedallionIcon.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Modal\\DoNotShowAgainOptionBlock' => $baseDir . '/sources/Application/UI/Base/Component/Modal/DoNotShowAgainOptionBlock.php',
|
||||
|
||||
@@ -640,6 +640,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Set\\Set' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Input/Set/Set.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Set\\SetUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Input/Set/SetUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\TextArea' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Input/TextArea.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\Toggler' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Input/Toggler.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Input\\tInputLabel' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Input/tInputLabel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\MedallionIcon\\MedallionIcon' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/MedallionIcon/MedallionIcon.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Modal\\DoNotShowAgainOptionBlock' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Modal/DoNotShowAgainOptionBlock.php',
|
||||
|
||||
@@ -38,14 +38,8 @@ class ButtonGroup extends UIBlock
|
||||
/**
|
||||
* Button constructor.
|
||||
*
|
||||
* @param string $sLabel
|
||||
* @param array $aButtons
|
||||
* @param string|null $sId
|
||||
* @param string $sTooltip
|
||||
* @param string $sIconClass
|
||||
* @param string $sActionType
|
||||
* @param string $sColor
|
||||
* @param string $sJsCode
|
||||
* @param string $sOnClickJsCode
|
||||
*/
|
||||
public function __construct(array $aButtons = [], ?string $sId = null)
|
||||
{
|
||||
|
||||
@@ -95,10 +95,11 @@ class InputUIBlockFactory extends AbstractUIBlockFactory
|
||||
* @param string $sLabel
|
||||
* @param \Combodo\iTop\Application\UI\Base\Component\Input\Input $oInput
|
||||
* @param string|null $sId
|
||||
* @since 3.2.0 method is now public
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Component\Input\InputWithLabel
|
||||
*/
|
||||
private static function MakeInputWithLabel(string $sName, string $sLabel, Input $oInput, ?string $sId = null)
|
||||
public static function MakeInputWithLabel(string $sName, string $sLabel, Input $oInput, ?string $sId = null)
|
||||
{
|
||||
$oInput->SetName($sName);
|
||||
|
||||
|
||||
@@ -138,4 +138,8 @@ class InputWithLabel extends UIBlock
|
||||
return utils::IsNotNullOrEmptyString($this->sDescription);
|
||||
}
|
||||
|
||||
public function GetSubBlocks(): array
|
||||
{
|
||||
return [$this->oInput->GetId() => $this->oInput];
|
||||
}
|
||||
}
|
||||
37
sources/Application/UI/Base/Component/Input/Toggler.php
Normal file
37
sources/Application/UI/Base/Component/Input/Toggler.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\Input;
|
||||
|
||||
|
||||
/**
|
||||
* @package Combodo\iTop\Application\UI\Base\Component\Input
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Toggler extends Input {
|
||||
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-toggler';
|
||||
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/input/input-toggler';
|
||||
public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'base/components/input/input-toggler';
|
||||
|
||||
|
||||
public function __construct(?string $sId = null)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->SetType('checkbox');
|
||||
}
|
||||
|
||||
public function SetIsToggled(bool $bIsToggled): static
|
||||
{
|
||||
return $this->SetIsChecked($bIsToggled);
|
||||
}
|
||||
|
||||
public function IsToggled(): bool
|
||||
{
|
||||
return $this->IsChecked();
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class NewsroomMenuFactory
|
||||
$sPlaceholderImageUrl= 'far fa-envelope';
|
||||
$aParams = array(
|
||||
'image_icon' => $sImageUrl,
|
||||
'no_message_icon' => file_get_contents(APPROOT.'images/illustrations/undraw_empty.svg'),
|
||||
'no_message_icon' => file_get_contents(APPROOT.'images/illustrations/undraw_social_serenity.svg'),
|
||||
'placeholder_image_icon' => $sPlaceholderImageUrl,
|
||||
'cache_uuid' => 'itop-newsroom-'.UserRights::GetUserId().'-'.md5(APPROOT),
|
||||
'providers' => $aProviderParams,
|
||||
|
||||
@@ -103,6 +103,17 @@ class ObjectDetails extends Panel implements iKeyboardShortcut
|
||||
return $this->sClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see self::$sClassLabel
|
||||
* @return $this
|
||||
*/
|
||||
public function SetClassLabel($sClassLabel)
|
||||
{
|
||||
$this->sClassLabel = $sClassLabel;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see self::$sClassLabel
|
||||
* @return string
|
||||
|
||||
@@ -102,8 +102,8 @@ class ObjectSummary extends ObjectDetails
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$oDetailsButton = null;
|
||||
if(UserRights::IsActionAllowed($this->sClassName, UR_ACTION_MODIFY)) {
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
// We can pass a DBObject to the UIBlock, so we check for the DisplayModifyForm method
|
||||
if(method_exists($this->oObject, 'DisplayModifyForm') && UserRights::IsActionAllowed($this->sClassName, UR_ACTION_MODIFY)) {
|
||||
$oPopoverMenu = new PopoverMenu();
|
||||
|
||||
$oDetailsAction = new URLPopupMenuItem(
|
||||
|
||||
@@ -5,15 +5,33 @@ namespace Combodo\iTop\Controller\Newsroom;
|
||||
use ArchivedObjectException;
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\Button;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\ButtonGroup\ButtonGroupUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Toggler;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItemFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Object\ObjectSummary;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\JsonPage;
|
||||
use Combodo\iTop\Application\WebPage\JsonPPage;
|
||||
use Combodo\iTop\Service\Notification\NotificationsRepository;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
use CoreException;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use Dict;
|
||||
use DisplayBlock;
|
||||
use JSPopupMenuItem;
|
||||
use MetaModel;
|
||||
use SecurityException;
|
||||
use URLPopupMenuItem;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
@@ -38,11 +56,475 @@ class iTopNewsroomController extends Controller
|
||||
public function OperationViewAll()
|
||||
{
|
||||
$oPage = new iTopWebPage(Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Title'));
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT EventiTopNotification WHERE read = "no"');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/pages/backoffice/itop-newsroom.view-all.js');
|
||||
// Add title block
|
||||
// Make bulk actions block
|
||||
$oBulkActionsBlock = PanelUIBlockFactory::MakeForInformation(Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Title'));
|
||||
$oToolbar = ToolbarUIBlockFactory::MakeStandard();
|
||||
$oToolbar->AddCSSClass('ibo-notifications--view-all--toolbar');
|
||||
$oAllModeButtonsContainer = new UIContentBlock('ibo-notifications--view-all--all-mode-buttons', ['ibo-notifications--view-all--bulk-buttons', 'ibo-notifications--view-all--all-mode-buttons']);
|
||||
// Create CSRF token we'll use in this page
|
||||
$sCSRFToken = utils::GetNewTransactionId();
|
||||
// Make button to mark all as read
|
||||
$sMarkMultipleAsReadUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.mark_multiple_as_read', ['token' => $sCSRFToken]);
|
||||
$sMarkMultipleAsUnreadUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.mark_multiple_as_unread', ['token' => $sCSRFToken]);
|
||||
$sDeleteMultipleUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.delete_multiple', ['token' => $sCSRFToken]);
|
||||
|
||||
$oMarkAllAsReadButton = ButtonUIBlockFactory::MakeForSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsRead:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsRead:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsRead:Label'
|
||||
);
|
||||
$oMarkAllAsReadButton->SetIconClass('far fa-envelope-open')
|
||||
->AddCSSClass('ibo-notifications--view-all--read-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToMarkAsRead = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"].ibo-notifications--view-all--item--unread');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToMarkAsRead.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{$sMarkMultipleAsReadUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
let MarkAsReadButton = oNotificationToMarkAsRead.find('.ibo-button-group:not(.ibo-is-hidden)');
|
||||
let MarkAsUnreadButton = oNotificationToMarkAsRead.find('.ibo-button-group.ibo-is-hidden');
|
||||
MarkAsReadButton.addClass('ibo-is-hidden');
|
||||
MarkAsUnreadButton.removeClass('ibo-is-hidden');
|
||||
oNotificationToMarkAsRead.removeClass('ibo-notifications--view-all--item--unread').addClass('ibo-notifications--view-all--item--read');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.read');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
// Make button to mark all as unread
|
||||
$oMarkAllAsUnreadButton = ButtonUIBlockFactory::MakeForSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsUnread:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsUnread:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAllAsUnread:Label',
|
||||
);
|
||||
$oMarkAllAsUnreadButton->SetIconClass('far fa-envelope')
|
||||
->AddCSSClass('ibo-notifications--view-all--unread-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToMarkAsUnread = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"].ibo-notifications--view-all--item--read');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToMarkAsUnread.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{$sMarkMultipleAsUnreadUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
let MarkAsUnreadButton = oNotificationToMarkAsUnread.find('.ibo-button-group:not(.ibo-is-hidden)');
|
||||
let MarkAsReadButton = oNotificationToMarkAsUnread.find('.ibo-button-group.ibo-is-hidden');
|
||||
|
||||
MarkAsReadButton.removeClass('ibo-is-hidden');
|
||||
MarkAsUnreadButton.addClass('ibo-is-hidden');
|
||||
oNotificationToMarkAsUnread.removeClass('ibo-notifications--view-all--item--read').addClass('ibo-notifications--view-all--item--unread');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.unread');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
// Make button to delete all
|
||||
$oDeleteAllButton = ButtonUIBlockFactory::MakeForDestructiveAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Label'
|
||||
);
|
||||
$oDeleteAllButtonConfirmTitle = Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Title');
|
||||
$oDeleteAllButtonConfirmMessage = Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteAll:Confirmation:Message');
|
||||
$oDeleteAllButton->SetActionType(Button::ENUM_ACTION_TYPE_ALTERNATIVE);
|
||||
$oDeleteAllButton->SetIconClass('fas fa-trash-alt')
|
||||
->AddCSSClass('ibo-notifications--view-all--delete-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToDelete = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"]');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToDelete.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
CombodoModal.OpenConfirmationModal({
|
||||
title: '$oDeleteAllButtonConfirmTitle',
|
||||
content: '$oDeleteAllButtonConfirmMessage',
|
||||
callback_on_confirm: function() {
|
||||
$.ajax({
|
||||
url: '{$sDeleteMultipleUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
oNotificationToDelete.remove();
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.deleted');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: '$oDeleteAllButtonConfirmTitle',
|
||||
classes: ['ibo-is-danger']
|
||||
}
|
||||
},
|
||||
do_not_show_again_pref_key: 'notifications-center.delete-all-confirmation-modal.do-not-show-again',
|
||||
}, []);
|
||||
|
||||
JS
|
||||
);
|
||||
// Add "all" buttons to their container
|
||||
$oAllModeButtonsContainer->AddSubBlock($oMarkAllAsReadButton);
|
||||
$oAllModeButtonsContainer->AddSubBlock($oMarkAllAsUnreadButton);
|
||||
$oAllModeButtonsContainer->AddSubBlock($oDeleteAllButton);
|
||||
$oToolbar->AddSubBlock($oAllModeButtonsContainer);
|
||||
|
||||
$oSelectedModelButtonsContainer = new UIContentBlock('ibo-notifications--view-all--selected-mode-buttons', ['ibo-is-hidden', 'ibo-notifications--view-all--bulk-buttons', 'ibo-notifications--view-all--selected-mode-buttons']);
|
||||
// Make button mark all selected as read
|
||||
$oMarkSelectedAsReadButton = ButtonUIBlockFactory::MakeForSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsRead:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsRead:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsRead:Label'
|
||||
);
|
||||
$oMarkSelectedAsReadButton->SetIconClass('far fa-envelope-open')
|
||||
->AddCSSClass('ibo-notifications--view-all--read-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToMarkAsRead = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"].ibo-notifications--view-all--item--unread.ibo-is-selected');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToMarkAsRead.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{$sMarkMultipleAsReadUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
let MarkAsReadButton = oNotificationToMarkAsRead.find('.ibo-button-group:not(.ibo-is-hidden)');
|
||||
let MarkAsUnreadButton = oNotificationToMarkAsRead.find('.ibo-button-group.ibo-is-hidden');
|
||||
MarkAsReadButton.addClass('ibo-is-hidden');
|
||||
MarkAsUnreadButton.removeClass('ibo-is-hidden');
|
||||
oNotificationToMarkAsRead.removeClass('ibo-notifications--view-all--item--unread').addClass('ibo-notifications--view-all--item--read');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.read');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
// Make button mark all selected as unread
|
||||
$oMarkSelectedAsUnreadButton = ButtonUIBlockFactory::MakeForSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsUnread:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsUnread:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkSelectedAsUnread:Label'
|
||||
);
|
||||
$oMarkSelectedAsUnreadButton->SetIconClass('far fa-envelope')
|
||||
->AddCSSClass('ibo-notifications--view-all--unread-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToMarkAsUnread = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"].ibo-notifications--view-all--item--read.ibo-is-selected');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToMarkAsUnread.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{$sMarkMultipleAsUnreadUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
let MarkAsUnreadButton = oNotificationToMarkAsUnread.find('.ibo-button-group:not(.ibo-is-hidden)');
|
||||
let MarkAsReadButton = oNotificationToMarkAsUnread.find('.ibo-button-group.ibo-is-hidden');
|
||||
|
||||
MarkAsReadButton.removeClass('ibo-is-hidden');
|
||||
MarkAsUnreadButton.addClass('ibo-is-hidden');
|
||||
|
||||
oNotificationToMarkAsUnread.removeClass('ibo-notifications--view-all--item--read').addClass('ibo-notifications--view-all--item--unread');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.unread');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
// Make button delete all selected
|
||||
$oDeleteSelectedButton = ButtonUIBlockFactory::MakeForDestructiveAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Label'
|
||||
);
|
||||
$oDeleteSelectedButtonConfirmTitle = Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Title');
|
||||
$oDeleteSelectedButtonConfirmMessage = Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:DeleteSelected:Confirmation:Message');
|
||||
$oDeleteSelectedButton->SetActionType(Button::ENUM_ACTION_TYPE_ALTERNATIVE);
|
||||
$oDeleteSelectedButton->SetIconClass('fas fa-trash-alt')
|
||||
->AddCSSClass('ibo-notifications--view-all--delete-action')
|
||||
->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
let oNotificationToDelete = $('.ibo-notifications--view-all--container [data-role="ibo-object-summary"].ibo-is-selected');
|
||||
let aNotificationIds = [];
|
||||
oNotificationToDelete.each(function(){
|
||||
aNotificationIds.push($(this).attr('data-object-id'));
|
||||
});
|
||||
CombodoModal.OpenConfirmationModal({
|
||||
title: '$oDeleteSelectedButtonConfirmTitle',
|
||||
content: '$oDeleteSelectedButtonConfirmMessage',
|
||||
callback_on_confirm: function() {
|
||||
$.ajax({
|
||||
url: '{$sDeleteMultipleUrl}',
|
||||
data: {
|
||||
notification_ids: aNotificationIds
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
oNotificationToDelete.remove();
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.deleted');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: '$oDeleteSelectedButtonConfirmTitle',
|
||||
classes: ['ibo-is-danger']
|
||||
}
|
||||
},
|
||||
do_not_show_again_pref_key: 'notifications-center.delete-all-confirmation-modal.do-not-show-again',
|
||||
}, []);
|
||||
JS
|
||||
);
|
||||
|
||||
// Add "selected" buttons to their container
|
||||
$oSelectedModelButtonsContainer->AddSubBlock($oMarkSelectedAsReadButton);
|
||||
$oSelectedModelButtonsContainer->AddSubBlock($oMarkSelectedAsUnreadButton);
|
||||
$oSelectedModelButtonsContainer->AddSubBlock($oDeleteSelectedButton);
|
||||
|
||||
$oToolbar->AddSubBlock($oSelectedModelButtonsContainer);
|
||||
|
||||
// Make toggler to switch between "all" and "selected" mode
|
||||
$oTogglerContentBlock = new UIContentBlock('ibo-notifications--view-all--toggler', ['ibo-notifications--view-all--toggler']);
|
||||
$oToggler = new Toggler();
|
||||
$oInputWithLabel = InputUIBlockFactory::MakeInputWithLabel('slider', Dict::S('UI:Newsroom:iTopNotification:SelectMode:Label'), $oToggler);
|
||||
$oTogglerContentBlock->AddSubBlock($oInputWithLabel);
|
||||
$oToolbar->AddSubBlock($oTogglerContentBlock);
|
||||
|
||||
$oBulkActionsBlock->AddSubBlock($oToolbar);
|
||||
$oPage->AddUiBlock($oBulkActionsBlock);
|
||||
|
||||
// Search for all notifications for the current user
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT EventiTopNotification');
|
||||
$oSearch->AddCondition('contact_id', UserRights::GetContactId(), '=');
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, []);
|
||||
$oBlock->Display($oPage, 0);
|
||||
$oPage->add("<div class='sf_results_area ibo-add-margin-top-250' data-target='search_results'>");
|
||||
$oSet = new DBObjectSet($oSearch, array('read' => true, 'date' => true), array());
|
||||
|
||||
// Add main content block
|
||||
$oMainContentBlock = new UIContentBlock(null, ['ibo-notifications--view-all--container']);
|
||||
$oPage->AddUiBlock($oMainContentBlock);
|
||||
|
||||
while ($oEvent = $oSet->Fetch()) {
|
||||
$iEventId = $oEvent->GetKey();
|
||||
// Prepare object summary block
|
||||
$sReadColor = $oEvent->Get('read') === 'no' ? 'ibo-notifications--view-all--item--unread' : 'ibo-notifications--view-all--item--read';
|
||||
$sReadLabel = $oEvent->Get('read') === 'no' ? Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Unread:Label') : Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Read:Label');
|
||||
$oEventBlock = new ObjectSummary($oEvent);
|
||||
$oEventBlock->SetCSSColorClass($sReadColor);
|
||||
$oEventBlock->SetSubTitle($sReadLabel);
|
||||
$oEventBlock->SetClassLabel('');
|
||||
$oImage = $oEvent->Get('icon');
|
||||
if (!$oImage->IsEmpty()) {
|
||||
$sIconUrl = $oImage->GetDisplayURL(get_class($oEvent), $iEventId, 'icon');
|
||||
$oEventBlock->SetIcon($sIconUrl, Panel::ENUM_ICON_COVER_METHOD_COVER,true);
|
||||
}
|
||||
|
||||
// Prepare Event actions
|
||||
$oMarkAsReadPopoverMenu = new PopoverMenu();
|
||||
$oMarkAsUnreadPopoverMenu = new PopoverMenu();
|
||||
|
||||
// Common actions
|
||||
$sDeleteUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.delete_event', ['notification_id' => $oEvent->GetKey(), 'token' => $sCSRFToken]);
|
||||
$oDeleteButton = new JSPopupMenuItem(
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Label',
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:Delete:Label'),
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
|
||||
$.ajax({
|
||||
url: '{$sDeleteUrl}',
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
$(oSelf).parents('.ibo-object-summary').remove();
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.deleted');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS,
|
||||
'_blank'
|
||||
);
|
||||
$oViewButton = new URLPopupMenuItem(
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:ViewObject:Label',
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:ViewObject:Label'),
|
||||
Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.view_event', ['event_id' => $oEvent->GetKey()]),
|
||||
'_blank'
|
||||
);
|
||||
|
||||
// Mark as read action
|
||||
$oMarkAsReadButton = ButtonUIBlockFactory::MakeForAlternativeSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsRead:Label',
|
||||
);
|
||||
|
||||
// Mark as read action
|
||||
$oMarkAsReadPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oViewButton))->SetContainer(PopoverMenu::ENUM_CONTAINER_PARENT);
|
||||
$oMarkAsReadPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oDeleteButton))->SetContainer(PopoverMenu::ENUM_CONTAINER_PARENT);
|
||||
|
||||
// Mark as unread action
|
||||
$oMarkAsUnreadPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oViewButton))->SetContainer(PopoverMenu::ENUM_CONTAINER_PARENT);
|
||||
$oMarkAsUnreadPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oDeleteButton))->SetContainer(PopoverMenu::ENUM_CONTAINER_PARENT);
|
||||
|
||||
|
||||
// Mark as unread action
|
||||
$sMarkAsReadUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.mark_as_read', ['notification_id' => $oEvent->GetKey(), 'token' => $sCSRFToken]);
|
||||
$oMarkAsReadButton->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
$.ajax({
|
||||
url: '{$sMarkAsReadUrl}',
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
$(oSelf).parent('.ibo-button-group').addClass('ibo-is-hidden');
|
||||
$(oSelf).parent('.ibo-button-group').siblings('.ibo-button-group').removeClass('ibo-is-hidden');
|
||||
$(oSelf).parents('.ibo-object-summary').removeClass('ibo-notifications--view-all--item--unread').addClass('ibo-notifications--view-all--item--read');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.read');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
$oMarkAsReadButtonGroup = ButtonGroupUIBlockFactory::MakeButtonWithOptionsMenu($oMarkAsReadButton, $oMarkAsReadPopoverMenu);
|
||||
|
||||
$oMarkAsUnreadButton = ButtonUIBlockFactory::MakeForAlternativeSecondaryAction(
|
||||
Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Label'),
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Label',
|
||||
'UI:Newsroom:iTopNotification:ViewAllPage:Action:MarkAsUnread:Label'
|
||||
);
|
||||
$sMarkAsUnreadUrl = Router::GetInstance()->GenerateUrl(self::ROUTE_NAMESPACE.'.mark_as_unread', ['notification_id' => $oEvent->GetKey(), 'token' => $sCSRFToken]);
|
||||
$oMarkAsUnreadButton->SetOnClickJsCode(
|
||||
<<<JS
|
||||
let oSelf = this;
|
||||
$.ajax({
|
||||
url: '{$sMarkAsUnreadUrl}',
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
if (data.status === 'success') {
|
||||
$(oSelf).parent('.ibo-button-group').addClass('ibo-is-hidden');
|
||||
$(oSelf).parent('.ibo-button-group').siblings('.ibo-button-group').removeClass('ibo-is-hidden');
|
||||
$(oSelf).parents('.ibo-object-summary').removeClass('ibo-notifications--view-all--item--read').addClass('ibo-notifications--view-all--item--unread');
|
||||
CombodoToast.OpenSuccessToast(data.message);
|
||||
$('.ibo-notifications--view-all--container').trigger('itop.notification.unread');
|
||||
}
|
||||
else {
|
||||
CombodoToast.OpenErrorToast(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
$oMarkAsUnreadButtonGroup = ButtonGroupUIBlockFactory::MakeButtonWithOptionsMenu($oMarkAsUnreadButton, $oMarkAsUnreadPopoverMenu);
|
||||
|
||||
// Add actions to the object summary block and remove old button
|
||||
$oOldButtonId = $oEventBlock->GetActions()->GetId();
|
||||
$oEventBlock->RemoveSubBlock($oOldButtonId);
|
||||
$oEventBlock->SetToolBlocks([$oMarkAsReadButtonGroup, $oMarkAsUnreadButtonGroup]);
|
||||
$oActionsBlock = new UIContentBlock();
|
||||
$oActionsBlock->AddSubBlock($oMarkAsReadButtonGroup);
|
||||
$oActionsBlock->AddSubBlock($oMarkAsUnreadButtonGroup);
|
||||
$oEventBlock->SetActions($oActionsBlock);
|
||||
|
||||
// Display the right button depending on the read status
|
||||
if($oEvent->Get('read') === 'no'){
|
||||
$oMarkAsUnreadButtonGroup->SetCSSClasses(['ibo-is-hidden']);
|
||||
}
|
||||
else{
|
||||
$oMarkAsReadButtonGroup->SetCSSClasses(['ibo-is-hidden']);
|
||||
}
|
||||
|
||||
$oMainContentBlock->AddSubBlock($oEventBlock);
|
||||
}
|
||||
|
||||
// Add empty content block
|
||||
$oEmptyContentBlock = new UIContentBlock('ibo-notifications--view-all--empty', ['ibo-notifications--view-all--empty', 'ibo-svg-illustration--container']);
|
||||
$oEmptyContentBlock->AddSubBlock(new Html(file_get_contents(APPROOT.'/images/illustrations/undraw_social_serenity.svg')));
|
||||
$oEmptyContentBlock->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:Newsroom:iTopNotification:ViewAllPage:Empty:Title')));
|
||||
$oPage->AddUiBlock($oEmptyContentBlock);
|
||||
|
||||
// Hide empty content block if there are notifications
|
||||
if($oSet->Count() === 0){
|
||||
$oMainContentBlock->AddCSSClass('ibo-is-hidden');
|
||||
}
|
||||
else {
|
||||
$oEmptyContentBlock->AddCSSClass('ibo-is-hidden');
|
||||
}
|
||||
|
||||
return $oPage;
|
||||
}
|
||||
@@ -159,4 +641,163 @@ HTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationMarkAsUnread(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnSingleNotification('mark_as_unread'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationMarkAsRead(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnSingleNotification('mark_as_read'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationDeleteEvent(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnSingleNotification('delete'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationMarkMultipleAsRead(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnMultipleNotifications('mark_as_read'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationMarkMultipleAsUnread(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnMultipleNotifications('mark_as_unread'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\WebPage\JsonPage
|
||||
*/
|
||||
public function OperationDeleteMultiple(): JsonPage
|
||||
{
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetData($this->PerformActionOnMultipleNotifications('delete'));
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
*
|
||||
* @return string[]
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
protected function PerformActionOnSingleNotification(string $sAction): array
|
||||
{
|
||||
$iNotificationId = utils::ReadParam('notification_id', 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER);
|
||||
return $this->PerformAction($sAction, [$iNotificationId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
*
|
||||
* @return string[]
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
protected function PerformActionOnMultipleNotifications(string $sAction): array
|
||||
{
|
||||
$aNotificationIds = utils::ReadParam('notification_ids', []);
|
||||
return $this->PerformAction($sAction, $aNotificationIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
* @param array $aNotificationIds
|
||||
*
|
||||
* @return string[]
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
protected function PerformAction(string $sAction, array $aNotificationIds): array
|
||||
{
|
||||
$sCSRFToken = utils::ReadParam('token', '', false, 'raw_data');
|
||||
if(utils::IsTransactionValid($sCSRFToken, false) === false){
|
||||
throw new SecurityException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
$sActionAsCamelCase = utils::ToCamelCase($sAction);
|
||||
$aReturnData = [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid notification(s)'
|
||||
];
|
||||
|
||||
// Check action type
|
||||
if (false === in_array($sAction, ['mark_as_read', 'mark_as_unread', 'delete'])) {
|
||||
$aReturnData['message'] = Dict::S("UI:Newsroom:iTopNotification:ViewAllPage:Action:InvalidAction:Message");
|
||||
return $aReturnData;
|
||||
}
|
||||
|
||||
// No ID passed to the API
|
||||
if (count($aNotificationIds) === 0) {
|
||||
$aReturnData['message'] = Dict::S("UI:Newsroom:iTopNotification:ViewAllPage:Action:$sActionAsCamelCase:NoEvent:Message");
|
||||
return $aReturnData;
|
||||
}
|
||||
|
||||
try {
|
||||
$sRepositoryMethodName = "SearchNotificationsTo{$sActionAsCamelCase}ByContact";
|
||||
$oSet = NotificationsRepository::GetInstance()->$sRepositoryMethodName(UserRights::GetContactId(), $aNotificationIds);
|
||||
|
||||
// No notification found
|
||||
$iCount = $oSet->Count();
|
||||
if($iCount === 0) {
|
||||
$aReturnData['message'] = Dict::S("UI:Newsroom:iTopNotification:ViewAllPage:Action:$sActionAsCamelCase:NoEvent:Message");
|
||||
return $aReturnData;
|
||||
}
|
||||
|
||||
while ($oEvent = $oSet->Fetch()) {
|
||||
if ($sAction === 'mark_as_read') {
|
||||
$oEvent->Set('read', 'yes');
|
||||
$oEvent->SetCurrentDate('read_date');
|
||||
$oEvent->DBWrite();
|
||||
} elseif ($sAction === 'mark_as_unread') {
|
||||
$oEvent->Set('read', 'no');
|
||||
$oEvent->DBWrite();
|
||||
} elseif ($sAction === 'delete') {
|
||||
$oEvent->DBDelete();
|
||||
}
|
||||
}
|
||||
|
||||
$aReturnData['status'] = 'success';
|
||||
if ($iCount === 1) {
|
||||
$aReturnData['message'] = Dict::S("UI:Newsroom:iTopNotification:ViewAllPage:Action:{$sActionAsCamelCase}:Success:Message");
|
||||
} else {
|
||||
$aReturnData['message'] = Dict::Format("UI:Newsroom:iTopNotification:ViewAllPage:Action:{$sActionAsCamelCase}Multiple:Success:Message", $iCount);
|
||||
}
|
||||
} catch (Exception $oException) {
|
||||
$aReturnData['message'] = $oException->getMessage();
|
||||
}
|
||||
|
||||
return $aReturnData;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Combodo\iTop\Service\Notification;
|
||||
|
||||
use BinaryExpression;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use Expression;
|
||||
use FieldExpression;
|
||||
use VariableExpression;
|
||||
|
||||
/**
|
||||
* Class NotificationsRepository
|
||||
@@ -44,6 +48,74 @@ class NotificationsRepository
|
||||
// Don't do anything, we don't want to be initialized
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iContactId ID of the contact to retrieve notifications for
|
||||
* @param array $aNotificationIds Optional IDs of the notifications to retrieve, if omitted all notifications will be retrieved
|
||||
*
|
||||
* @return \DBObjectSet Set of notifications for $iContactId, optionally limited to $aNotificationIds
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchNotificationsByContact(int $iContactId, array $aNotificationIds = []): DBObjectSet
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT EventiTopNotification WHERE contact_id = :contact_id");
|
||||
$aParams = [
|
||||
"contact_id" => $iContactId,
|
||||
];
|
||||
|
||||
if (count($aNotificationIds) > 0) {
|
||||
$oSearch->AddConditionExpression(Expression::FromOQL("{$oSearch->GetClassAlias()}.id IN (:notification_ids)"));
|
||||
$aParams["notification_ids"] = $aNotificationIds;
|
||||
}
|
||||
|
||||
return new DBObjectSet($oSearch, [], $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iContactId ID of the contact to retrieve unread notifications for
|
||||
* @param array $aNotificationIds Optional IDs of the unread notifications to retrieve, if omitted all unread notifications will be retrieved
|
||||
*
|
||||
* @return \DBObjectSet Set of unread notifications for $iContactId, optionally limited to $aNotificationIds
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchNotificationsToMarkAsReadByContact(int $iContactId, array $aNotificationIds = []): DBObjectSet
|
||||
{
|
||||
$oSet = $this->SearchNotificationsByContact($iContactId, $aNotificationIds);
|
||||
$oSet->GetFilter()->AddCondition("read", "=", "no");
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iContactId ID of the contact to retrieve read notifications for
|
||||
* @param array $aNotificationIds Optional IDs of the read notifications to retrieve, if omitted all read notifications will be retrieved
|
||||
*
|
||||
* @return \DBObjectSet Set of read notifications for $iContactId, optionally limited to $aNotificationIds
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchNotificationsToMarkAsUnreadByContact(int $iContactId, array $aNotificationIds = []): DBObjectSet
|
||||
{
|
||||
$oSet = $this->SearchNotificationsByContact($iContactId, $aNotificationIds);
|
||||
$oSet->GetFilter()->AddCondition("read", "=", "yes");
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iContactId ID of the contact to retrieve read notifications for
|
||||
* @param array $aNotificationIds Optional IDs of the notifications to retrieve, if omitted all notifications will be retrieved
|
||||
*
|
||||
* @return \DBObjectSet Set of notifications for $iContactId, optionally limited to $aNotificationIds
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchNotificationsToDeleteByContact(int $iContactId, array $aNotificationIds = []): DBObjectSet
|
||||
{
|
||||
return $this->SearchNotificationsByContact($iContactId, $aNotificationIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for subscriptions by contact ID.
|
||||
*
|
||||
|
||||
7
templates/base/components/input/input-toggler.html.twig
Normal file
7
templates/base/components/input/input-toggler.html.twig
Normal file
@@ -0,0 +1,7 @@
|
||||
{% extends "base/components/input/layout.html.twig" %}
|
||||
{% block iboInput %}
|
||||
<span class="ibo-toggler--wrapper">
|
||||
{{ parent() }}
|
||||
<span class="ibo-toggler--slider"></span>
|
||||
</span>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,5 @@
|
||||
$('#{{ oUIBlock.GetId() }}').parent().on('click', function() {
|
||||
let oInput = $(this).find('.ibo-toggler');
|
||||
oInput.prop('checked', !oInput.prop('checked'));
|
||||
oInput.trigger('change');
|
||||
});
|
||||
Reference in New Issue
Block a user