Files
2024-10-14 00:08:40 +02:00

1128 lines
37 KiB
Perl

# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::Output::HTML::Layout::Ticket;
use strict;
use warnings;
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
our $ObjectManagerDisabled = 1;
=head1 NAME
Kernel::Output::HTML::Layout::Ticket - all Ticket-related HTML functions
=head1 DESCRIPTION
All Ticket-related HTML functions
=head1 PUBLIC INTERFACE
=head2 AgentCustomerViewTable()
=cut
sub AgentCustomerViewTable {
my ( $Self, %Param ) = @_;
# check customer params
if ( ref $Param{Data} ne 'HASH' ) {
$Self->FatalError( Message => 'Need Hash ref in Data param' );
}
elsif ( ref $Param{Data} eq 'HASH' && !%{ $Param{Data} } ) {
return $Self->{LanguageObject}->Translate('none');
}
# add ticket params if given
if ( $Param{Ticket} ) {
%{ $Param{Data} } = ( %{ $Param{Data} }, %{ $Param{Ticket} } );
}
my @MapNew;
my $Map = $Param{Data}->{Config}->{Map};
if ($Map) {
@MapNew = ( @{$Map} );
}
# check if customer company support is enabled
if ( $Param{Data}->{Config}->{CustomerCompanySupport} ) {
my $Map2 = $Param{Data}->{CompanyConfig}->{Map};
if ($Map2) {
push( @MapNew, @{$Map2} );
}
}
my $ShownType = 1;
if ( $Param{Type} && $Param{Type} eq Translatable('Lite') ) {
$ShownType = 2;
# check if min one lite view item is configured, if not, use
# the normal view also
my $Used = 0;
for my $Field (@MapNew) {
if ( $Field->[3] == 2 ) {
$Used = 1;
}
}
if ( !$Used ) {
$ShownType = 1;
}
}
# build html table
$Self->Block(
Name => 'Customer',
Data => $Param{Data},
);
# get needed objects
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
# check Frontend::CustomerUser::Image
my $CustomerImage = $ConfigObject->Get('Frontend::CustomerUser::Image');
if ($CustomerImage) {
my %Modules = %{$CustomerImage};
MODULE:
for my $Module ( sort keys %Modules ) {
if ( !$MainObject->Require( $Modules{$Module}->{Module} ) ) {
$Self->FatalDie();
}
my $Object = $Modules{$Module}->{Module}->new(
%{$Self},
LayoutObject => $Self,
);
# run module
next MODULE if !$Object;
$Object->Run(
Config => $Modules{$Module},
Data => $Param{Data},
);
}
}
my $DynamicFieldConfigs = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
ObjectType => [ 'CustomerUser', 'CustomerCompany', ],
);
my %DynamicFieldLookup = map { $_->{Name} => $_ } @{$DynamicFieldConfigs};
# Get dynamic field object.
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
# build table
FIELD:
for my $Field (@MapNew) {
if ( $Field->[3] && $Field->[3] >= $ShownType && $Param{Data}->{ $Field->[0] } ) {
my %Record = (
%{ $Param{Data} },
Key => $Field->[1],
Value => $Param{Data}->{ $Field->[0] },
);
# render dynamic field values
if ( $Field->[5] eq 'dynamic_field' ) {
if ( !IsArrayRefWithData( $Record{Value} ) ) {
$Record{Value} = [ $Record{Value} ];
}
my $DynamicFieldConfig = $DynamicFieldLookup{ $Field->[2] };
next FIELD if !$DynamicFieldConfig;
my @RenderedValues;
VALUE:
for my $Value ( @{ $Record{Value} } ) {
my $RenderedValue = $DynamicFieldBackendObject->DisplayValueRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $Value,
HTMLOutput => 0,
LayoutObject => $Self,
);
next VALUE if !IsHashRefWithData($RenderedValue) || !defined $RenderedValue->{Value};
# If there is configured show link in DF, save as map value.
$Field->[6] = $RenderedValue->{Link} ? $RenderedValue->{Link} : $Field->[6];
push @RenderedValues, $RenderedValue->{Value};
}
$Record{Value} = join ', ', @RenderedValues;
$Record{Key} = $DynamicFieldConfig->{Label};
}
if (
$Field->[6]
&& (
$Param{Data}->{TicketID}
|| $Param{Ticket}
|| $Field->[6] !~ m{Env\("CGIHandle"\)}
)
)
{
$Record{LinkStart} = "<a href=\"$Field->[6]\"";
if ( !$Param{Ticket} ) {
$Record{LinkStart} .= " target=\"_blank\"";
}
elsif ( $Field->[8] ) {
$Record{LinkStart} .= " target=\"$Field->[8]\"";
}
if ( $Field->[9] ) {
$Record{LinkStart} .= " class=\"$Field->[9]\"";
}
$Record{LinkStart} .= ">";
$Record{LinkStop} = "</a>";
}
if ( $Field->[0] ) {
$Record{ValueShort} = $Self->Ascii2Html(
Text => $Record{Value},
Max => $Param{Max}
);
}
$Self->Block(
Name => 'CustomerRow',
Data => \%Record,
);
if (
$Param{Data}->{Config}->{CustomerCompanySupport}
&& $Field->[0] eq 'CustomerCompanyName'
)
{
my $CompanyValidID = $Param{Data}->{CustomerCompanyValidID};
if ($CompanyValidID) {
my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
my $CompanyIsValid = grep { $CompanyValidID == $_ } @ValidIDs;
if ( !$CompanyIsValid ) {
$Self->Block(
Name => 'CustomerRowCustomerCompanyInvalid',
);
}
}
}
if (
$ConfigObject->Get('ChatEngine::Active')
&& $Field->[0] eq 'UserLogin'
)
{
# Check if agent has permission to start chats with the customer users.
my $EnableChat = 1;
my $ChatStartingAgentsGroup
= $ConfigObject->Get('ChatEngine::PermissionGroup::ChatStartingAgents') || 'users';
my $ChatStartingAgentsGroupPermission = $Kernel::OM->Get('Kernel::System::Group')->PermissionCheck(
UserID => $Self->{UserID},
GroupName => $ChatStartingAgentsGroup,
Type => 'rw',
);
if ( !$ChatStartingAgentsGroupPermission ) {
$EnableChat = 0;
}
if (
$EnableChat
&& !$ConfigObject->Get('ChatEngine::ChatDirection::AgentToCustomer')
)
{
$EnableChat = 0;
}
if ($EnableChat) {
my $VideoChatEnabled = 0;
my $VideoChatAgentsGroup
= $ConfigObject->Get('ChatEngine::PermissionGroup::VideoChatAgents') || 'users';
my $VideoChatAgentsGroupPermission = $Kernel::OM->Get('Kernel::System::Group')->PermissionCheck(
UserID => $Self->{UserID},
GroupName => $VideoChatAgentsGroup,
Type => 'rw',
);
# Enable the video chat feature if system is entitled and agent is a member of configured group.
if ($VideoChatAgentsGroupPermission) {
if ( $Kernel::OM->Get('Kernel::System::Main')
->Require( 'Kernel::System::VideoChat', Silent => 1 ) )
{
$VideoChatEnabled = $Kernel::OM->Get('Kernel::System::VideoChat')->IsEnabled();
}
}
my $CustomerEnableChat = 0;
my $ChatAccess = 0;
my $VideoChatAvailable = 0;
my $VideoChatSupport = 0;
# Default status is offline.
my $UserState = Translatable('Offline');
my $UserStateDescription = $Self->{LanguageObject}->Translate('User is currently offline.');
my $CustomerChatAvailability = $Kernel::OM->Get('Kernel::System::Chat')->CustomerAvailabilityGet(
UserID => $Param{Data}->{UserID},
);
my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
my %CustomerUser = $CustomerUserObject->CustomerUserDataGet(
User => $Param{Data}->{UserID},
);
$CustomerUser{UserFullname} = $CustomerUserObject->CustomerName(
UserLogin => $Param{Data}->{UserID},
);
$VideoChatSupport = 1 if $CustomerUser{VideoChatHasWebRTC};
if ( $CustomerChatAvailability == 3 ) {
$UserState = Translatable('Active');
$CustomerEnableChat = 1;
$UserStateDescription = $Self->{LanguageObject}->Translate('User is currently active.');
$VideoChatAvailable = 1;
}
elsif ( $CustomerChatAvailability == 2 ) {
$UserState = Translatable('Away');
$CustomerEnableChat = 1;
$UserStateDescription = $Self->{LanguageObject}->Translate('User was inactive for a while.');
}
$Self->Block(
Name => 'CustomerRowUserStatus',
Data => {
%CustomerUser,
UserState => $UserState,
UserStateDescription => $UserStateDescription,
},
);
if ($CustomerEnableChat) {
$Self->Block(
Name => 'CustomerRowChatIcons',
Data => {
%{ $Param{Data} },
%CustomerUser,
VideoChatEnabled => $VideoChatEnabled,
VideoChatAvailable => $VideoChatAvailable,
VideoChatSupport => $VideoChatSupport,
},
);
}
}
}
}
}
# check Frontend::CustomerUser::Item
my $CustomerItem = $ConfigObject->Get('Frontend::CustomerUser::Item');
my $CustomerItemCount = 0;
if ($CustomerItem) {
$Self->Block(
Name => 'CustomerItem',
);
my %Modules = %{$CustomerItem};
MODULE:
for my $Module ( sort keys %Modules ) {
if ( !$MainObject->Require( $Modules{$Module}->{Module} ) ) {
$Self->FatalDie();
}
my $Object = $Modules{$Module}->{Module}->new(
%{$Self},
LayoutObject => $Self,
);
# run module
next MODULE if !$Object;
my $Run = $Object->Run(
Config => $Modules{$Module},
Data => $Param{Data},
);
next MODULE if !$Run;
$CustomerItemCount++;
}
}
# create & return output
return $Self->Output(
TemplateFile => 'AgentCustomerTableView',
Data => \%Param
);
}
sub AgentQueueListOption {
my ( $Self, %Param ) = @_;
my $Size = $Param{Size} ? "size='$Param{Size}'" : '';
my $MaxLevel = defined( $Param{MaxLevel} ) ? $Param{MaxLevel} : 10;
my $SelectedID = defined( $Param{SelectedID} ) ? $Param{SelectedID} : '';
my $Selected = defined( $Param{Selected} ) ? $Param{Selected} : '';
my $CurrentQueueID = defined( $Param{CurrentQueueID} ) ? $Param{CurrentQueueID} : '';
my $Class = defined( $Param{Class} ) ? $Param{Class} : '';
my $SelectedIDRefArray = $Param{SelectedIDRefArray} || '';
my $Multiple = $Param{Multiple} ? 'multiple = "multiple"' : '';
my $TreeView = $Param{TreeView} ? $Param{TreeView} : 0;
my $OptionTitle = defined( $Param{OptionTitle} ) ? $Param{OptionTitle} : 0;
my $OnChangeSubmit = defined( $Param{OnChangeSubmit} ) ? $Param{OnChangeSubmit} : '';
if ($OnChangeSubmit) {
$OnChangeSubmit = " onchange=\"submit();\"";
}
else {
$OnChangeSubmit = '';
}
# set OnChange if AJAX is used
if ( $Param{Ajax} ) {
# get log object
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
if ( !$Param{Ajax}->{Depend} ) {
$LogObject->Log(
Priority => 'error',
Message => 'Need Depend Param Ajax option!',
);
$Self->FatalError();
}
if ( !$Param{Ajax}->{Update} ) {
$LogObject->Log(
Priority => 'error',
Message => 'Need Update Param Ajax option()!',
);
$Self->FatalError();
}
$Param{OnChange} = "Core.AJAX.FormUpdate(\$('#"
. $Param{Name} . "'), '"
. $Param{Ajax}->{Subaction} . "',"
. " '$Param{Name}',"
. " ['"
. join( "', '", @{ $Param{Ajax}->{Update} } ) . "']);";
}
if ( $Param{OnChange} ) {
$OnChangeSubmit = " onchange=\"$Param{OnChange}\"";
}
# just show a simple list
if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::ListType') eq 'list' ) {
# transform data from Hash in Array because of ordering in frontend by Queue name
# it was a problem with name like '(some_queue)'
# see bug#10621 http://bugs.otrs.org/show_bug.cgi?id=10621
my %QueueDataHash = %{ $Param{Data} || {} };
my @QueueDataArray = map {
{
Key => $_,
Value => $QueueDataHash{$_},
}
} sort { $QueueDataHash{$a} cmp $QueueDataHash{$b} } keys %QueueDataHash;
# find index of first element in array @QueueDataArray for displaying in frontend
# at the top should be element with ' $QueueDataArray[$_]->{Key} = 0' like "- Move -"
# if such an element is found, it is moved to the top
my $MoveStr = $Self->{LanguageObject}->Translate('Move');
my $ValueOfQueueNoKey = '- ' . $MoveStr . ' -';
my ($FirstElementIndex) = grep {
$QueueDataArray[$_]->{Value} eq '-'
|| $QueueDataArray[$_]->{Value} eq $ValueOfQueueNoKey
} 0 .. scalar(@QueueDataArray) - 1;
if ($FirstElementIndex) {
splice( @QueueDataArray, 0, 0, splice( @QueueDataArray, $FirstElementIndex, 1 ) );
}
$Param{Data} = \@QueueDataArray;
$Param{MoveQueuesStrg} = $Self->BuildSelection(
%Param,
HTMLQuote => 0,
SelectedID => $Param{SelectedID} || $Param{SelectedIDRefArray} || '',
SelectedValue => $Param{Selected},
Translation => 0,
);
return $Param{MoveQueuesStrg};
}
# build tree list
$Param{MoveQueuesStrg} = '<select name="'
. $Param{Name}
. '" id="'
. $Param{Name}
. '" class="'
. $Class
. '" data-tree="true"'
. " $Size $Multiple $OnChangeSubmit>\n";
my %UsedData;
my %Data;
if ( $Param{Data} && ref $Param{Data} eq 'HASH' ) {
%Data = %{ $Param{Data} };
}
else {
return 'Need Data Ref in AgentQueueListOption()!';
}
# add suffix for correct sorting
my $KeyNoQueue;
my $ValueNoQueue;
my $MoveStr = $Self->{LanguageObject}->Translate('Move');
my $ValueOfQueueNoKey = "- " . $MoveStr . " -";
DATA:
for ( sort { $Data{$a} cmp $Data{$b} } keys %Data ) {
# find value for default item in select box
# it can be "-" or "Move"
if (
$Data{$_} eq "-"
|| $Data{$_} eq $ValueOfQueueNoKey
)
{
$KeyNoQueue = $_;
$ValueNoQueue = $Data{$_};
next DATA;
}
$Data{$_} .= '::';
}
# get HTML utils object
my $HTMLUtilsObject = $Kernel::OM->Get('Kernel::System::HTMLUtils');
# set default item of select box
if ($ValueNoQueue) {
$Param{MoveQueuesStrg} .= '<option value="'
. $HTMLUtilsObject->ToHTML(
String => $KeyNoQueue,
ReplaceDoubleSpace => 0,
)
. '">'
. $ValueNoQueue
. "</option>\n";
}
# build selection string
KEY:
for ( sort { $Data{$a} cmp $Data{$b} } keys %Data ) {
# default item of select box has set already
next KEY if ( $Data{$_} eq "-" || $Data{$_} eq $ValueOfQueueNoKey );
my @Queue = split( /::/, $Param{Data}->{$_} );
$UsedData{ $Param{Data}->{$_} } = 1;
my $UpQueue = $Param{Data}->{$_};
$UpQueue =~ s/^(.*)::.+?$/$1/g;
if ( !$Queue[$MaxLevel] && $Queue[-1] ne '' ) {
$Queue[-1] = $Self->Ascii2Html(
Text => $Queue[-1],
Max => 50 - $#Queue
);
my $Space = '';
for ( my $i = 0; $i < $#Queue; $i++ ) {
$Space .= '&nbsp;&nbsp;';
}
# check if SelectedIDRefArray exists
if ($SelectedIDRefArray) {
for my $ID ( @{$SelectedIDRefArray} ) {
if ( $ID eq $_ ) {
$Param{SelectedIDRefArrayOK}->{$_} = 1;
}
}
}
if ( !$UsedData{$UpQueue} ) {
# integrate the not selectable parent and root queues of this queue
# useful for ACLs and complex permission settings
for my $Index ( 0 .. ( scalar @Queue - 2 ) ) {
# get the Full Queue Name (with all its parents separated by '::') this will
# make a unique name and will be used to set the %DisabledQueueAlreadyUsed
# using unique names will prevent erroneous hide of Sub-Queues with the
# same name, refer to bug#8148
my $FullQueueName;
for my $Counter ( 0 .. $Index ) {
$FullQueueName .= $Queue[$Counter];
if ( int $Counter < int $Index ) {
$FullQueueName .= '::';
}
}
if ( !$UsedData{$FullQueueName} ) {
my $DSpace = '&nbsp;&nbsp;' x $Index;
my $OptionTitleHTMLValue = '';
if ($OptionTitle) {
my $HTMLValue = $HTMLUtilsObject->ToHTML(
String => $Queue[$Index],
ReplaceDoubleSpace => 0,
);
$OptionTitleHTMLValue = ' title="' . $HTMLValue . '"';
}
$Param{MoveQueuesStrg}
.= '<option value="-" disabled="disabled"'
. $OptionTitleHTMLValue
. '>'
. $DSpace
. $Queue[$Index]
. "</option>\n";
$UsedData{$FullQueueName} = 1;
}
}
}
# create selectable elements
my $String = $Space . $Queue[-1];
my $OptionTitleHTMLValue = '';
if ($OptionTitle) {
my $HTMLValue = $HTMLUtilsObject->ToHTML(
String => $Queue[-1],
ReplaceDoubleSpace => 0,
);
$OptionTitleHTMLValue = ' title="' . $HTMLValue . '"';
}
my $HTMLValue = $HTMLUtilsObject->ToHTML(
String => $_,
ReplaceDoubleSpace => 0,
);
if (
$SelectedID eq $_
|| $Selected eq $Param{Data}->{$_}
|| $Param{SelectedIDRefArrayOK}->{$_}
)
{
$Param{MoveQueuesStrg}
.= '<option selected="selected" value="'
. $HTMLValue . '"'
. $OptionTitleHTMLValue . '>'
. $String
. "</option>\n";
}
elsif ( $CurrentQueueID eq $_ )
{
$Param{MoveQueuesStrg}
.= '<option value="-" disabled="disabled"'
. $OptionTitleHTMLValue . '>'
. $String
. "</option>\n";
}
else {
$Param{MoveQueuesStrg}
.= '<option value="'
. $HTMLValue . '"'
. $OptionTitleHTMLValue . '>'
. $String
. "</option>\n";
}
}
}
$Param{MoveQueuesStrg} .= "</select>\n";
if ( $Param{TreeView} ) {
my $TreeSelectionMessage = $Self->{LanguageObject}->Translate("Show Tree Selection");
$Param{MoveQueuesStrg}
.= ' <a href="#" title="'
. $TreeSelectionMessage
. '" class="ShowTreeSelection"><span>'
. $TreeSelectionMessage . '</span><i class="fa fa-sitemap"></i></a>';
}
return $Param{MoveQueuesStrg};
}
sub TicketListShow {
my ( $Self, %Param ) = @_;
# take object ref to local, remove it from %Param (prevent memory leak)
my $Env = $Param{Env};
delete $Param{Env};
# lookup latest used view mode
if ( !$Param{View} && $Self->{ 'UserTicketOverview' . $Env->{Action} } ) {
$Param{View} = $Self->{ 'UserTicketOverview' . $Env->{Action} };
}
# set default view mode to 'small'
my $View = $Param{View} || 'Small';
# set default view mode for AgentTicketQueue or AgentTicketService
if (
!$Param{View}
&& (
$Env->{Action} eq 'AgentTicketQueue'
|| $Env->{Action} eq 'AgentTicketService'
)
)
{
$View = 'Preview';
}
# store latest view mode
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'UserTicketOverview' . $Env->{Action},
Value => $View,
);
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# update preferences if needed
my $Key = 'UserTicketOverview' . $Env->{Action};
if ( !$ConfigObject->Get('DemoSystem') && ( $Self->{$Key} // '' ) ne $View ) {
$Kernel::OM->Get('Kernel::System::User')->SetPreferences(
UserID => $Self->{UserID},
Key => $Key,
Value => $View,
);
}
# check backends
my $Backends = $ConfigObject->Get('Ticket::Frontend::Overview');
if ( !$Backends ) {
return $Self->FatalError(
Message => 'Need config option Ticket::Frontend::Overview',
);
}
if ( ref $Backends ne 'HASH' ) {
return $Self->FatalError(
Message => 'Config option Ticket::Frontend::Overview need to be HASH ref!',
);
}
# check if selected view is available
if ( !$Backends->{$View} ) {
# try to find fallback, take first configured view mode
KEY:
for my $Key ( sort keys %{$Backends} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No Config option found for view mode $View, took $Key instead!",
);
$View = $Key;
last KEY;
}
}
# get layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
$LayoutObject->AddJSData(
Key => 'View',
Value => $View,
);
# load overview backend module
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Backends->{$View}->{Module} ) ) {
return $Env->{LayoutObject}->FatalError();
}
my $Object = $Backends->{$View}->{Module}->new( %{$Env} );
return if !$Object;
# retireve filter values
if ( $Param{FilterContentOnly} ) {
return $Object->FilterContent(
%Param,
);
}
# run action row backend module
$Param{ActionRow} = $Object->ActionRow(
%Param,
Config => $Backends->{$View},
);
# run overview backend module
$Param{SortOrderBar} = $Object->SortOrderBar(
%Param,
Config => $Backends->{$View},
);
# check start option, if higher then tickets available, set
# it to the last ticket page (Thanks to Stefan Schmidt!)
my $StartHit = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'StartHit' ) || 1;
# get personal page shown count
my $PageShownPreferencesKey = 'UserTicketOverview' . $View . 'PageShown';
my $PageShown = $Self->{$PageShownPreferencesKey} || 10;
my $Group = 'TicketOverview' . $View . 'PageShown';
# get data selection
my %Data;
my $Config = $ConfigObject->Get('PreferencesGroups');
if ( $Config && $Config->{$Group} && $Config->{$Group}->{Data} ) {
%Data = %{ $Config->{$Group}->{Data} };
}
# calculate max. shown per page
if ( $StartHit > $Param{Total} ) {
my $Pages = int( ( $Param{Total} / $PageShown ) + 0.99999 );
$StartHit = ( ( $Pages - 1 ) * $PageShown ) + 1;
}
# build nav bar
my $Limit = $Param{Limit} || 20_000;
my %PageNav = $Self->PageNavBar(
Limit => $Limit,
StartHit => $StartHit,
PageShown => $PageShown,
AllHits => $Param{Total} || 0,
Action => 'Action=' . $Self->{Action},
Link => $Param{LinkPage},
IDPrefix => $Self->{Action},
);
# build shown ticket per page
$Param{RequestedURL} = $Param{RequestedURL} || "Action=$Self->{Action}";
$Param{Group} = $Group;
$Param{PreferencesKey} = $PageShownPreferencesKey;
$Param{PageShownString} = $Self->BuildSelection(
Name => $PageShownPreferencesKey,
SelectedID => $PageShown,
Translation => 0,
Data => \%Data,
Sort => 'NumericValue',
Class => 'Modernize',
);
# nav bar at the beginning of a overview
$Param{View} = $View;
$Self->Block(
Name => 'OverviewNavBar',
Data => \%Param,
);
# back link
if ( $Param{LinkBack} ) {
$Self->Block(
Name => 'OverviewNavBarPageBack',
Data => \%Param,
);
$LayoutObject->AddJSData(
Key => 'Profile',
Value => $Param{Profile},
);
}
# filter selection
if ( $Param{Filters} ) {
my @NavBarFilters;
for my $Prio ( sort keys %{ $Param{Filters} } ) {
push @NavBarFilters, $Param{Filters}->{$Prio};
}
$Self->Block(
Name => 'OverviewNavBarFilter',
Data => {
%Param,
},
);
my $Count = 0;
for my $Filter (@NavBarFilters) {
$Count++;
if ( $Count == scalar @NavBarFilters ) {
$Filter->{CSS} = 'Last';
}
$Self->Block(
Name => 'OverviewNavBarFilterItem',
Data => {
%Param,
%{$Filter},
},
);
if ( $Filter->{Filter} eq $Param{Filter} ) {
$Self->Block(
Name => 'OverviewNavBarFilterItemSelected',
Data => {
%Param,
%{$Filter},
},
);
}
else {
$Self->Block(
Name => 'OverviewNavBarFilterItemSelectedNot',
Data => {
%Param,
%{$Filter},
},
);
}
}
}
# view mode
for my $Backend (
sort { $Backends->{$a}->{ModulePriority} <=> $Backends->{$b}->{ModulePriority} }
keys %{$Backends}
)
{
$Self->Block(
Name => 'OverviewNavBarViewMode',
Data => {
%Param,
%{ $Backends->{$Backend} },
Filter => $Param{Filter},
View => $Backend,
},
);
if ( $View eq $Backend ) {
$Self->Block(
Name => 'OverviewNavBarViewModeSelected',
Data => {
%Param,
%{ $Backends->{$Backend} },
Filter => $Param{Filter},
View => $Backend,
},
);
}
else {
$Self->Block(
Name => 'OverviewNavBarViewModeNotSelected',
Data => {
%Param,
%{ $Backends->{$Backend} },
Filter => $Param{Filter},
View => $Backend,
},
);
}
}
if (%PageNav) {
$Self->Block(
Name => 'OverviewNavBarPageNavBar',
Data => \%PageNav,
);
# don't show context settings in AJAX case (e. g. in customer ticket history),
# because the submit with page reload will not work there
if ( !$Param{AJAX} ) {
$Self->Block(
Name => 'ContextSettings',
Data => {
%PageNav,
%Param,
},
);
# show column filter preferences
if ( $View eq 'Small' ) {
# set preferences keys
my $PrefKeyColumns = 'UserFilterColumnsEnabled' . '-' . $Env->{Action};
# create extra needed objects
my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
# configure columns
my @ColumnsEnabled = @{ $Object->{ColumnsEnabled} };
my @ColumnsAvailable;
# remove duplicate columns
my %UniqueColumns;
my @ColumnsEnabledAux;
for my $Column (@ColumnsEnabled) {
if ( !$UniqueColumns{$Column} ) {
push @ColumnsEnabledAux, $Column;
}
$UniqueColumns{$Column} = 1;
}
# set filtered column list
@ColumnsEnabled = @ColumnsEnabledAux;
for my $ColumnName ( sort { $a cmp $b } @{ $Object->{ColumnsAvailable} } ) {
if ( !grep { $_ eq $ColumnName } @ColumnsEnabled ) {
push @ColumnsAvailable, $ColumnName;
}
}
my %Columns;
for my $ColumnName ( sort @ColumnsAvailable ) {
$Columns{Columns}->{$ColumnName} = ( grep { $ColumnName eq $_ } @ColumnsEnabled ) ? 1 : 0;
}
$Self->Block(
Name => 'FilterColumnSettings',
Data => {
Columns => $JSONObject->Encode( Data => \%Columns ),
ColumnsEnabled => $JSONObject->Encode( Data => \@ColumnsEnabled ),
ColumnsAvailable => $JSONObject->Encode( Data => \@ColumnsAvailable ),
NamePref => $PrefKeyColumns,
Desc => Translatable('Shown Columns'),
Name => $Env->{Action},
View => $View,
GroupName => 'TicketOverviewFilterSettings',
%Param,
},
);
}
} # end show column filters preferences
# check if there was stored filters, and print a link to delete them
if ( IsHashRefWithData( $Object->{StoredFilters} ) ) {
$Self->Block(
Name => 'DocumentActionRowRemoveColumnFilters',
Data => {
CSS => "ContextSettings RemoveFilters",
%Param,
},
);
}
}
if ( $Param{NavBar} ) {
if ( $Param{NavBar}->{MainName} ) {
$Self->Block(
Name => 'OverviewNavBarMain',
Data => $Param{NavBar},
);
}
}
my $OutputNavBar = $Self->Output(
TemplateFile => 'AgentTicketOverviewNavBar',
Data => { %Param, },
);
my $OutputRaw = '';
if ( !$Param{Output} ) {
$Self->Print( Output => \$OutputNavBar );
}
else {
$OutputRaw .= $OutputNavBar;
}
# run overview backend module
my $Output = $Object->Run(
%Param,
Config => $Backends->{$View},
Limit => $Limit,
StartHit => $StartHit,
PageShown => $PageShown,
AllHits => $Param{Total} || 0,
Output => $Param{Output} || '',
);
if ( !$Param{Output} ) {
$Self->Print( Output => \$Output );
}
else {
$OutputRaw .= $Output;
}
return $OutputRaw;
}
sub TicketMetaItemsCount {
my ( $Self, %Param ) = @_;
return ( 'Priority', 'New Article' );
}
sub TicketMetaItems {
my ( $Self, %Param ) = @_;
if ( ref $Param{Ticket} ne 'HASH' ) {
$Self->FatalError( Message => 'Need Hash ref in Ticket param!' );
}
# return attributes
my @Result;
# show priority
push @Result, {
# Image => $Image,
Title => $Param{Ticket}->{Priority},
Class => 'Flag',
ClassSpan => 'PriorityID-' . $Param{Ticket}->{PriorityID},
ClassTable => 'Flags',
};
# get ticket object
my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
my %Ticket = $TicketObject->TicketGet( TicketID => $Param{Ticket}->{TicketID} );
# Show if new message is in there, but show archived tickets as read.
my %TicketFlag;
if ( $Ticket{ArchiveFlag} ne 'y' ) {
%TicketFlag = $TicketObject->TicketFlagGet(
TicketID => $Param{Ticket}->{TicketID},
UserID => $Self->{UserID},
);
}
if ( $Ticket{ArchiveFlag} eq 'y' || $TicketFlag{Seen} ) {
push @Result, undef;
}
else {
# just show ticket flags if agent belongs to the ticket
my $ShowMeta;
if (
$Self->{UserID} == $Param{Ticket}->{OwnerID}
|| $Self->{UserID} == $Param{Ticket}->{ResponsibleID}
)
{
$ShowMeta = 1;
}
if ( !$ShowMeta && $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Watcher') ) {
my %Watch = $TicketObject->TicketWatchGet(
TicketID => $Param{Ticket}->{TicketID},
);
if ( $Watch{ $Self->{UserID} } ) {
$ShowMeta = 1;
}
}
# show ticket flags
my $Image = 'meta-new-inactive.png';
if ($ShowMeta) {
$Image = 'meta-new.png';
push @Result, {
Image => $Image,
Title => Translatable('Unread article(s) available'),
Class => 'UnreadArticles',
ClassSpan => 'UnreadArticles Remarkable',
ClassTable => 'UnreadArticles',
};
}
else {
push @Result, {
Image => $Image,
Title => Translatable('Unread article(s) available'),
Class => 'UnreadArticles',
ClassSpan => 'UnreadArticles Ordinary',
ClassTable => 'UnreadArticles',
};
}
}
return @Result;
}
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L<https://otrs.org/>).
This software comes with ABSOLUTELY NO WARRANTY. For details, see
the enclosed file COPYING for license information (GPL). If you
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
=cut