mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-18 23:08:46 +02:00
N°3629 - Activity panel: Add possibility to close the panel
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
$ibo-activity-panel--width: 480px !default;
|
||||
/* TODO: This should be changed when responsive breakpoints are defined and used */
|
||||
$ibo-activity-panel--is-expanded--width: 60vw !default;
|
||||
$ibo-activity-panel--is-closed--width: 32px !default;
|
||||
$ibo-activity-panel--height: 100% !default;
|
||||
$ibo-activity-panel--padding-x: 16px !default;
|
||||
$ibo-activity-panel--padding-y: 0 !default;
|
||||
@@ -27,8 +28,9 @@ $ibo-activity-panel--padding-y: 0 !default;
|
||||
/* - Header */
|
||||
$ibo-activity-panel--header--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-activity-panel--size-toggler--color: $ibo-color-grey-600 !default;
|
||||
$ibo-activity-panel--size-toggler--on-hover--color: $ibo-color-grey-800 !default;
|
||||
$ibo-activity-panel--togglers--color: $ibo-color-grey-600 !default;
|
||||
$ibo-activity-panel--togglers--on-hover--color: $ibo-color-grey-800 !default;
|
||||
$ibo-activity-panel--togglers--elements-spacing: 0.75rem !default;
|
||||
|
||||
/* - Tabs togglers*/
|
||||
$ibo-activity-panel--tabs-togglers--padding-x: $ibo-activity-panel--padding-x * 3 !default; /* We need to increase this so the size toggler which will be set in abs. pos. can overlap it nicely */
|
||||
@@ -104,26 +106,45 @@ $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default;
|
||||
$ibo-activity-panel--entry-forms-confirmation-explanation--spacing: 16px !default;
|
||||
$ibo-activity-panel--entry-forms-confirmation-preference-input--spacing: 0.5rem !default;
|
||||
|
||||
$ibo-activity-panel--closed-cover--background-color: $ibo-activity-panel--header--background-color !default;
|
||||
$ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
|
||||
|
||||
/* Whole layout */
|
||||
.ibo-activity-panel{
|
||||
width: $ibo-activity-panel--width;
|
||||
height: $ibo-activity-panel--height;
|
||||
transition: width 0.2s ease-in-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.ibo-activity-panel {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: $ibo-activity-panel--width;
|
||||
height: $ibo-activity-panel--height;
|
||||
transition: width 0.2s ease-in-out;
|
||||
|
||||
&.ibo-is-expanded{
|
||||
width: $ibo-activity-panel--is-expanded--width;
|
||||
&.ibo-is-expanded {
|
||||
width: $ibo-activity-panel--is-expanded--width;
|
||||
|
||||
.ibo-activity-panel--expand-icon{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&:not(.ibo-is-expanded){
|
||||
.ibo-activity-panel--collapse-icon{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ibo-activity-panel--expand-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.ibo-is-expanded) {
|
||||
.ibo-activity-panel--reduce-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.ibo-is-closed {
|
||||
width: $ibo-activity-panel--is-closed--width;
|
||||
|
||||
.ibo-activity-panel--header,
|
||||
.ibo-activity-panel--body,
|
||||
.ibo-activity-panel--add-caselog-entry-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ibo-activity-panel--closed-cover {
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Header */
|
||||
@@ -136,18 +157,23 @@ $ibo-activity-panel--entry-forms-confirmation-preference-input--spacing: 0.5rem
|
||||
color: $ibo-activity-panel--tab-toolbar--text-color;
|
||||
}
|
||||
}
|
||||
/* Size toggler */
|
||||
.ibo-activity-panel--size-toggler{
|
||||
position: absolute;
|
||||
right: $ibo-activity-panel--padding-x;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@extend %ibo-fully-centered-content;
|
||||
color: $ibo-activity-panel--size-toggler--color;
|
||||
|
||||
&:hover{
|
||||
color: $ibo-activity-panel--size-toggler--on-hover--color;
|
||||
}
|
||||
/* Size/display togglers */
|
||||
.ibo-activity-panel--togglers {
|
||||
position: absolute;
|
||||
right: $ibo-activity-panel--padding-x;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@extend %ibo-fully-centered-content;
|
||||
color: $ibo-activity-panel--togglers--color;
|
||||
|
||||
&:hover {
|
||||
color: $ibo-activity-panel--togglers--on-hover--color;
|
||||
}
|
||||
|
||||
> *:not(:first-child) {
|
||||
margin-left: $ibo-activity-panel--togglers--elements-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs togglers */
|
||||
@@ -379,3 +405,29 @@ $ibo-activity-panel--entry-forms-confirmation-preference-input--spacing: 0.5rem
|
||||
.ibo-activity-panel--entry-forms-confirmation-preference-input{
|
||||
margin-right: $ibo-activity-panel--entry-forms-confirmation-preference-input--spacing;
|
||||
}
|
||||
|
||||
|
||||
/* Closed cover */
|
||||
.ibo-activity-panel--closed-cover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 2; // Above the compose button and all
|
||||
// padding-top: 64px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@extend %ibo-fully-centered-content;
|
||||
// align-items: flex-start;
|
||||
background-color: $ibo-activity-panel--closed-cover--background-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ibo-activity-panel--closed-content-container {
|
||||
transform: rotateZ(-90deg);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ibo-activity-panel--open-icon {
|
||||
margin-left: $ibo-activity-panel--open-icon--margin-left;
|
||||
}
|
||||
@@ -20,7 +20,8 @@
|
||||
// Activity panel
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Layout:ActivityPanel:SizeToggler:Expand:Tooltip' => 'Expand',
|
||||
'UI:Layout:ActivityPanel:SizeToggler:Collapse:Tooltip' => 'Reduce',
|
||||
'UI:Layout:ActivityPanel:SizeToggler:Reduce:Tooltip' => 'Reduce',
|
||||
'UI:Layout:ActivityPanel:DisplayToggler:Close:Tooltip' => 'Close',
|
||||
|
||||
// Tabs
|
||||
'UI:Layout:ActivityPanel:Tab:Activity:Title' => 'Activity',
|
||||
@@ -45,4 +46,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
|
||||
// Placeholder
|
||||
'UI:Layout:ActivityPanel:NoEntry:Placeholder:Hint' => 'It\'s calm up here, no activity yet',
|
||||
|
||||
// Closed cover
|
||||
'UI:Layout:ActivityPanel:ClosedCover:Title' => 'Activity panel',
|
||||
'UI:Layout:ActivityPanel:ClosedCover:Tooltip' => 'Click to open the activity panel',
|
||||
));
|
||||
@@ -33,10 +33,12 @@ $(function()
|
||||
lock_watcher_period: 30, // Period (in seconds) between lock status update, uses the "activity_panel.lock_watcher_period" config. param.
|
||||
lock_endpoint: null,
|
||||
show_multiple_entries_submit_confirmation: true,
|
||||
save_state_endpoint: null,
|
||||
},
|
||||
css_classes:
|
||||
{
|
||||
is_expanded: 'ibo-is-expanded',
|
||||
is_reduced: 'ibo-is-reduced',
|
||||
is_opened: 'ibo-is-opened',
|
||||
is_closed: 'ibo-is-closed',
|
||||
is_active: 'ibo-is-active',
|
||||
@@ -47,7 +49,11 @@ $(function()
|
||||
},
|
||||
js_selectors:
|
||||
{
|
||||
panel_size_toggler: '[data-role="ibo-activity-panel--size-toggler"]',
|
||||
panel_togglers: '[data-role="ibo-activity-panel--togglers"]',
|
||||
panel_size_expand: '[data-role="ibo-activity-panel--expand-icon"]',
|
||||
panel_size_reduce: '[data-role="ibo-activity-panel--reduce-icon"]',
|
||||
panel_size_close: '[data-role="ibo-activity-panel--close-icon"]',
|
||||
panel_size_open: '[data-role="ibo-activity-panel--closed-cover"]',
|
||||
tab_toggler: '[data-role="ibo-activity-panel--tab-toggler"]',
|
||||
tab_title: '[data-role="ibo-activity-panel--tab-title"]',
|
||||
tabs_toolbars: '[data-role="ibo-activity-panel--tabs-toolbars"]',
|
||||
@@ -126,100 +132,109 @@ $(function()
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
_destroy: function () {
|
||||
this.element.removeClass('ibo-activity-panel');
|
||||
},
|
||||
_bindEvents: function()
|
||||
{
|
||||
_bindEvents: function () {
|
||||
const me = this;
|
||||
const oBodyElem = $('body');
|
||||
|
||||
// Tabs title
|
||||
// - Click on the panel collapse/expand toggler
|
||||
this.element.find(this.js_selectors.panel_size_toggler).on('click', function(oEvent){
|
||||
me._onPanelSizeTogglerClick(oEvent);
|
||||
// - Click on the panel reduce/expand togglers
|
||||
this.element.find(this.js_selectors.panel_size_expand+', '+this.js_selectors.panel_size_reduce).on('click', function (oEvent) {
|
||||
me._onPanelSizeIconClick(oEvent);
|
||||
});
|
||||
// - Click on the panel close/open togglers
|
||||
this.element.find(this.js_selectors.panel_size_close+', '+this.js_selectors.panel_size_open).on('click', function (oEvent) {
|
||||
me._onPanelDisplayIconClick(oEvent);
|
||||
});
|
||||
// - Click on a tab title
|
||||
this.element.find(this.js_selectors.tab_title).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.tab_title).on('click', function (oEvent) {
|
||||
me._onTabTitleClick(oEvent, $(this));
|
||||
});
|
||||
|
||||
// Tabs toolbar
|
||||
// - Change on a filter
|
||||
this.element.find(this.js_selectors.activity_filter).on('change', function(){
|
||||
this.element.find(this.js_selectors.activity_filter).on('change', function () {
|
||||
me._onFilterChange($(this));
|
||||
});
|
||||
// - Click on a filter options toggler
|
||||
this.element.find(this.js_selectors.activity_filter_options_toggler).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.activity_filter_options_toggler).on('click', function (oEvent) {
|
||||
me._onFilterOptionsTogglerClick(oEvent, $(this));
|
||||
})
|
||||
// - Change on a filter option
|
||||
this.element.find(this.js_selectors.activity_filter_option_input).on('change', function(){
|
||||
this.element.find(this.js_selectors.activity_filter_option_input).on('change', function () {
|
||||
me._onFilterOptionChange($(this));
|
||||
});
|
||||
// - Click on open all case log messages
|
||||
this.element.find(this.js_selectors.caselog_tab_open_all).on('click', function(){
|
||||
this.element.find(this.js_selectors.caselog_tab_open_all).on('click', function () {
|
||||
me._onCaseLogOpenAllClick($(this));
|
||||
});
|
||||
// - Click on close all case log messages
|
||||
this.element.find(this.js_selectors.caselog_tab_close_all).on('click', function(){
|
||||
this.element.find(this.js_selectors.caselog_tab_close_all).on('click', function () {
|
||||
me._onCaseLogCloseAllClick($(this));
|
||||
});
|
||||
|
||||
// Entry form
|
||||
// - Click on the compose button
|
||||
this.element.find(this.js_selectors.compose_button).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.compose_button).on('click', function (oEvent) {
|
||||
me._onComposeButtonClick(oEvent);
|
||||
});
|
||||
// - Draft value ongoing
|
||||
this.element.on('draft.caselog_entry_form.itop', function(oEvent, oData){
|
||||
this.element.on('draft.caselog_entry_form.itop', function (oEvent, oData) {
|
||||
me._onDraftEntryForm(oData.attribute_code);
|
||||
});
|
||||
// - Empty value
|
||||
this.element.on('emptied.caselog_entry_form.itop', function(oEvent, oData){
|
||||
this.element.on('emptied.caselog_entry_form.itop', function (oEvent, oData) {
|
||||
me._onEmptyEntryForm(oData.attribute_code);
|
||||
});
|
||||
// - Entry form cancelled
|
||||
this.element.on('cancelled_form.caselog_entry_form.itop', function(){
|
||||
this.element.on('cancelled_form.caselog_entry_form.itop', function () {
|
||||
me._onCancelledEntryForm();
|
||||
});
|
||||
// - Entry form submission request
|
||||
this.element.on('request_submission.caselog_entry_form.itop', function(){
|
||||
this.element.on('request_submission.caselog_entry_form.itop', function () {
|
||||
me._onRequestSubmission();
|
||||
});
|
||||
|
||||
// Entries
|
||||
// - Click on a closed case log message
|
||||
this.element.find(this.js_selectors.entry_group).on('click', '.'+this.css_classes.is_closed + ' ' + this.js_selectors.entry_main_information, function(oEvent){
|
||||
this.element.find(this.js_selectors.entry_group).on('click', '.'+this.css_classes.is_closed+' '+this.js_selectors.entry_main_information, function (oEvent) {
|
||||
me._onCaseLogClosedMessageClick($(this).closest(me.js_selectors.entry));
|
||||
});
|
||||
// - Click on an edits entry's long description toggler
|
||||
this.element.find(this.js_selectors.edits_entry_long_description_toggler).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.edits_entry_long_description_toggler).on('click', function (oEvent) {
|
||||
me._onEditsLongDescriptionTogglerClick(oEvent, $(this).closest(me.js_selectors.entry));
|
||||
});
|
||||
|
||||
// Mostly for outside clicks that should close elements
|
||||
oBodyElem.on('click', function(oEvent){
|
||||
oBodyElem.on('click', function (oEvent) {
|
||||
me._onBodyClick(oEvent);
|
||||
});
|
||||
// Mostly for hotkeys
|
||||
oBodyElem.on('keyup', function(oEvent){
|
||||
oBodyElem.on('keyup', function (oEvent) {
|
||||
me._onBodyKeyUp(oEvent);
|
||||
});
|
||||
},
|
||||
|
||||
// Events callbacks
|
||||
_onPanelSizeTogglerClick: function(oEvent)
|
||||
{
|
||||
_onPanelSizeIconClick: function (oEvent) {
|
||||
// Avoid anchor glitch
|
||||
oEvent.preventDefault();
|
||||
|
||||
// Toggle menu
|
||||
this.element.toggleClass(this.css_classes.is_expanded);
|
||||
this._SaveStatePreferences();
|
||||
},
|
||||
_onTabTitleClick: function(oEvent, oTabTitleElem)
|
||||
{
|
||||
_onPanelDisplayIconClick: function (oEvent) {
|
||||
// Avoid anchor glitch
|
||||
oEvent.preventDefault();
|
||||
|
||||
// Toggle menu
|
||||
this.element.toggleClass(this.css_classes.is_closed);
|
||||
this._SaveStatePreferences();
|
||||
},
|
||||
_onTabTitleClick: function (oEvent, oTabTitleElem) {
|
||||
// Avoid anchor glitch
|
||||
oEvent.preventDefault();
|
||||
|
||||
@@ -396,10 +411,9 @@ $(function()
|
||||
* @param oEvent {Object} The jQuery event
|
||||
* @private
|
||||
*/
|
||||
_onBodyKeyUp: function(oEvent)
|
||||
{
|
||||
_onBodyKeyUp: function (oEvent) {
|
||||
// On "Esc" key
|
||||
if(oEvent.key === 'Escape') {
|
||||
if (oEvent.key === 'Escape') {
|
||||
// Hide all filters's options
|
||||
this._HideAllFiltersOptions();
|
||||
}
|
||||
@@ -407,25 +421,43 @@ $(function()
|
||||
|
||||
// Methods
|
||||
// - Helpers on host object
|
||||
_GetHostObjectClass: function()
|
||||
{
|
||||
_GetHostObjectClass: function () {
|
||||
return this.element.attr('data-object-class');
|
||||
},
|
||||
_GetHostObjectID: function()
|
||||
{
|
||||
_GetHostObjectID: function () {
|
||||
return this.element.attr('data-object-id');
|
||||
},
|
||||
_GetHostObjectMode: function () {
|
||||
return this.element.attr('data-object-mode');
|
||||
},
|
||||
/**
|
||||
* Save to the user pref. the expanded and closed states the host object class / mode
|
||||
*
|
||||
* @return {void}
|
||||
* @private
|
||||
*/
|
||||
_SaveStatePreferences: function () {
|
||||
$.post(
|
||||
this.options.save_state_endpoint,
|
||||
{
|
||||
'operation': 'save_activity_panel_state',
|
||||
'object_class': this._GetHostObjectClass(),
|
||||
'object_mode': this._GetHostObjectMode(),
|
||||
'is_expanded': this.element.hasClass(this.css_classes.is_expanded),
|
||||
'is_closed': this.element.hasClass(this.css_classes.is_closed),
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
// - Helpers on dates
|
||||
/**
|
||||
* Reformat date times to be relative (only if they are not too far in the past)
|
||||
* @private
|
||||
*/
|
||||
_ReformatDateTimes: function()
|
||||
{
|
||||
_ReformatDateTimes: function () {
|
||||
const me = this;
|
||||
|
||||
this.element.find(this.js_selectors.entry_datetime).each(function(){
|
||||
this.element.find(this.js_selectors.entry_datetime).each(function () {
|
||||
const oEntryDateTime = moment($(this).attr('data-formatted-datetime'), me.options.datetime_format);
|
||||
const oNowDateTime = moment();
|
||||
|
||||
|
||||
@@ -238,6 +238,7 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanel' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelHelper' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelHelper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelPrint' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelPrint.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryFormFactory\\CaseLogEntryFormFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
|
||||
|
||||
@@ -468,6 +468,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanel' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelHelper' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelHelper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelPrint' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelPrint.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryFormFactory\\CaseLogEntryFormFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
|
||||
|
||||
@@ -2752,14 +2752,32 @@ EOF
|
||||
$aRenderRes = $oRenderer->Render($aRequestedFields);
|
||||
|
||||
$aResult['form']['updated_fields'] = $aRenderRes;
|
||||
} catch (Exception $e)
|
||||
{
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$aResult['error'] = $e->getMessage();
|
||||
}
|
||||
$oPage->add(json_encode($aResult));
|
||||
break;
|
||||
|
||||
// Activity panel
|
||||
/** @internal */
|
||||
case 'save_activity_panel_state':
|
||||
$oPage->SetContentType('application/json');
|
||||
try {
|
||||
$oAjaxRenderController::SaveActivityPanelState();
|
||||
$aResult = [
|
||||
'success' => true,
|
||||
];
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
$aResult = [
|
||||
'success' => false,
|
||||
'error_message' => $oException->getMessage(),
|
||||
];
|
||||
}
|
||||
$oPage->add(json_encode($aResult));
|
||||
break;
|
||||
|
||||
case 'add_caselog_entries':
|
||||
$oPage->SetContentType('application/json');
|
||||
try {
|
||||
|
||||
@@ -18,6 +18,7 @@ use CMDBSource;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntryFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityPanelHelper;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
@@ -377,6 +378,27 @@ class AjaxRenderController
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function SaveActivityPanelState(): void
|
||||
{
|
||||
$sObjectClass = utils::ReadPostedParam('object_class', '', utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$sObjectMode = utils::ReadPostedParam('object_mode');
|
||||
$bIsExpanded = utils::ReadPostedParam('is_expanded');
|
||||
$bIsClosed = utils::ReadPostedParam('is_closed');
|
||||
|
||||
if (false === empty($bIsExpanded)) {
|
||||
ActivityPanelHelper::SaveExpandedStateForClass($sObjectClass, $sObjectMode, ('true' === $bIsExpanded));
|
||||
}
|
||||
|
||||
if (false === empty($bIsClosed)) {
|
||||
ActivityPanelHelper::SaveClosedStateForClass($sObjectClass, $sObjectMode, ('true' === $bIsClosed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new entries to some of the object's (identified by posted parameters) case logs
|
||||
*
|
||||
|
||||
@@ -59,8 +59,8 @@ class ActivityPanel extends UIBlock
|
||||
/** @var \DBObject $oObject The object for which the activity panel is for */
|
||||
protected $oObject;
|
||||
/**
|
||||
* @var string $sObjectMode Display mode of $oObject (create, edit, view, ...)
|
||||
* @see \cmdbAbstractObject::ENUM_OBJECT_MODE_XXX
|
||||
* @var string $sObjectMode Display mode of $oObject (create, edit, view, ...)
|
||||
*/
|
||||
protected $sObjectMode;
|
||||
/** @var null|string $sTransactionId Only when $sObjectMode is set to \cmdbAbstractObject::ENUM_OBJECT_MODE_VIEW */
|
||||
@@ -198,6 +198,34 @@ class ActivityPanel extends UIBlock
|
||||
return $this->sObjectMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if it should be expanded, false otherwise. Based on the user pref. or reduced by default.
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function IsExpanded(): bool
|
||||
{
|
||||
$bDefault = false;
|
||||
$aStates = appUserPreferences::GetPref('activity_panel.is_expanded', []);
|
||||
|
||||
return $aStates[$this->GetObjectClass().'::'.$this->GetObjectMode()] ?? $bDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if it should be closed, false otherwise. Based on the user pref. or closed by default if the object has no case log.
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function IsClosed(): bool
|
||||
{
|
||||
$bDefault = !$this->HasCaseLogTabs();
|
||||
$aStates = appUserPreferences::GetPref('activity_panel.is_closed', []);
|
||||
|
||||
return $aStates[$this->GetObjectClass().'::'.$this->GetObjectMode()] ?? $bDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @uses static::$sTransactionId
|
||||
@@ -669,6 +697,15 @@ class ActivityPanel extends UIBlock
|
||||
return utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The endpoint for the state (expanded, closed, ...) changes to be saved
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetSaveStateEndpoint(): string
|
||||
{
|
||||
return utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel;
|
||||
|
||||
|
||||
use appUserPreferences;
|
||||
use cmdbAbstractObject;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class ActivityPanelHelper
|
||||
*
|
||||
* @internal
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 3.0.0
|
||||
* @package Combodo\iTop\Application\UI\Base\Layout\ActivityPanel
|
||||
*/
|
||||
class ActivityPanelHelper
|
||||
{
|
||||
/**
|
||||
* Save in the user pref. if the activity panel should be expanded or not for $sObjectClass in $sObjectMode
|
||||
*
|
||||
* @param string $sObjectClass
|
||||
* @param string $sObjectMode
|
||||
* @param bool $bIsExpanded
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function SaveExpandedStateForClass(string $sObjectClass, string $sObjectMode, bool $bIsExpanded): void
|
||||
{
|
||||
if (false === MetaModel::IsValidClass($sObjectClass)) {
|
||||
throw new Exception('"'.$sObjectClass.'" must be a valid class.');
|
||||
}
|
||||
|
||||
if (false === in_array($sObjectMode, cmdbAbstractObject::EnumObjectModes())) {
|
||||
throw new Exception('Wrong object mode "'.$sObjectMode.'", must be among '.implode(' / ', cmdbAbstractObject::EnumObjectModes()));
|
||||
}
|
||||
|
||||
$aStates = appUserPreferences::GetPref('activity_panel.is_expanded', []);
|
||||
$aStates[$sObjectClass.'::'.$sObjectMode] = $bIsExpanded;
|
||||
appUserPreferences::SetPref('activity_panel.is_expanded', $aStates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save in the user pref. if the activity panel should be expanded or not for $sObjectClass in $sObjectMode
|
||||
*
|
||||
* @param string $sObjectClass
|
||||
* @param string $sObjectMode
|
||||
* @param bool $bIsClosed
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function SaveClosedStateForClass(string $sObjectClass, string $sObjectMode, bool $bIsClosed)
|
||||
{
|
||||
if (false === MetaModel::IsValidClass($sObjectClass)) {
|
||||
throw new Exception('"'.$sObjectClass.'" must be a valid class.');
|
||||
}
|
||||
|
||||
if (false === in_array($sObjectMode, cmdbAbstractObject::EnumObjectModes())) {
|
||||
throw new Exception('Wrong object mode "'.$sObjectMode.'", must be among '.implode(' / ', cmdbAbstractObject::EnumObjectModes()));
|
||||
}
|
||||
|
||||
$aStates = appUserPreferences::GetPref('activity_panel.is_closed', []);
|
||||
$aStates[$sObjectClass.'::'.$sObjectMode] = $bIsClosed;
|
||||
appUserPreferences::SetPref('activity_panel.is_closed', $aStates);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-activity-panel" data-role="ibo-activity-panel" data-object-class="{{ oUIBlock.GetObjectClass() }}" data-object-id="{{ oUIBlock.GetObjectId() }}" data-object-mode="{{ oUIBlock.GetObjectMode() }}">
|
||||
<div id="{{ oUIBlock.GetId() }}"
|
||||
class="ibo-activity-panel {% if oUIBlock.IsExpanded() %}ibo-is-expanded{% endif %} {% if oUIBlock.IsClosed() %}ibo-is-closed{% endif %}"
|
||||
data-role="ibo-activity-panel"
|
||||
data-object-class="{{ oUIBlock.GetObjectClass() }}"
|
||||
data-object-id="{{ oUIBlock.GetObjectId() }}"
|
||||
data-object-mode="{{ oUIBlock.GetObjectMode() }}">
|
||||
<div class="ibo-activity-panel--header" data-role="ibo-activity-panel--header">
|
||||
<div class="ibo-activity-panel--tabs-togglers" data-role="ibo-activity-panel--tabs-togglers">
|
||||
{% for sCaseLogAttCode, aCaseLogData in oUIBlock.GetCaseLogTabs() %}
|
||||
{% set sExtraCSSClass = (loop.index == 1) ? 'ibo-is-active' : '' %}
|
||||
{% set sExtraCSSClass = (loop.index == 1) ? 'ibo-is-active' : '' %}
|
||||
<div class="ibo-activity-panel--tab-toggler ibo-activity-panel--tab-toggler-for-caselog ibo-activity-panel--tab-toggler-for-caselog-{{ loop.index }} {{ sExtraCSSClass }}"
|
||||
data-role="ibo-activity-panel--tab-toggler"
|
||||
data-tab-type="caselog"
|
||||
@@ -27,17 +32,22 @@
|
||||
<span class="ibo-activity-panel--tab-title-text" title="{{ 'UI:Layout:ActivityPanel:Tab:Activity:Title'|dict_s }}">{{ 'UI:Layout:ActivityPanel:Tab:Activity:Title'|dict_s }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="ibo-activity-panel--size-toggler" data-role="ibo-activity-panel--size-toggler">
|
||||
<div class="ibo-activity-panel--togglers" data-role="ibo-activity-panel--togglers">
|
||||
<a href="#" class="ibo-activity-panel--expand-icon"
|
||||
data-role="ibo-activity-panel--expand-icon"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:SizeToggler:Expand:Tooltip'|dict_s }}">
|
||||
<span class="fas fa-fw fa-expand-alt"></span>
|
||||
</a>
|
||||
<a href="#" class="ibo-activity-panel--collapse-icon"
|
||||
data-role="ibo-activity-panel--collapse-icon"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:SizeToggler:Collapse:Tooltip'|dict_s }}">
|
||||
<a href="#" class="ibo-activity-panel--reduce-icon"
|
||||
data-role="ibo-activity-panel--reduce-icon"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:SizeToggler:Reduce:Tooltip'|dict_s }}">
|
||||
<span class="fas fa-fw fa-compress-alt"></span>
|
||||
</a>
|
||||
<a href="#" class="ibo-activity-panel--close-icon"
|
||||
data-role="ibo-activity-panel--close-icon"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:DisplayToggler:Close:Tooltip'|dict_s }}">
|
||||
<span class="fas fa-fw fa-chevron-right"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibo-activity-panel--tabs-toolbars" data-role="ibo-activity-panel--tabs-toolbars">
|
||||
@@ -73,5 +83,13 @@
|
||||
<div class="ibo-activity-panel--body--placeholder-hint">{{ 'UI:Layout:ActivityPanel:NoEntry:Placeholder:Hint'|dict_s }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibo-activity-panel--closed-cover" data-role="ibo-activity-panel--closed-cover" data-tooltip-content="{{ 'UI:Layout:ActivityPanel:ClosedCover:Tooltip'|dict_s }}" data-tooltip-placement="left">
|
||||
<span class="ibo-activity-panel--closed-content-container" data-role="ibo-activity-panel--closed-content-container">
|
||||
<span class="ibo-activity-panel--closed-title" data-role="ibo-activity-panel--closed-title">{{ 'UI:Layout:ActivityPanel:ClosedCover:Title'|dict_s }}</span>
|
||||
<span class="ibo-activity-panel--open-icon" data-role="ibo-activity-panel--open-icon">
|
||||
<span class="fas fa-fw fa-chevron-up"></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>f
|
||||
@@ -5,5 +5,6 @@ $('#{{ oUIBlock.GetId() }}').activity_panel({
|
||||
lock_enabled: {{ oUIBlock.IsLockEnabled()|var_export }},
|
||||
lock_watcher_period: {{ get_config_parameter('activity_panel.lock_watcher_period') }},
|
||||
lock_endpoint: {{ oUIBlock.GetLockEndpointForJSWidget()|var_export|raw }},
|
||||
show_multiple_entries_submit_confirmation: {{ oUIBlock.GetShowMultipleEntriesSubmitConfirmation()|var_export }}
|
||||
show_multiple_entries_submit_confirmation: {{ oUIBlock.GetShowMultipleEntriesSubmitConfirmation()|var_export }},
|
||||
save_state_endpoint: {{ oUIBlock.GetSaveStateEndpoint()|var_export|raw }}
|
||||
});
|
||||
Reference in New Issue
Block a user