# --
# 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::LinkObject;
use strict;
use warnings;
use Kernel::System::LinkObject;
use Kernel::Language qw(Translatable);
use Kernel::System::VariableCheck qw(:all);
our $ObjectManagerDisabled = 1;
=head1 NAME
Kernel::Output::HTML::Layout::LinkObject - all LinkObject-related HTML functions
=head1 DESCRIPTION
All LinkObject-related HTML functions
=head1 PUBLIC INTERFACE
=head2 LinkObjectTableCreate()
create a output table
my $String = $LayoutObject->LinkObjectTableCreate(
LinkListWithData => $LinkListWithDataRef,
ViewMode => 'Simple', # (Simple|SimpleRaw|Complex|ComplexAdd|ComplexDelete|ComplexRaw)
);
=cut
sub LinkObjectTableCreate {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Argument (qw(LinkListWithData ViewMode)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
if ( $Param{ViewMode} =~ m{ \A Simple }xms ) {
return $Self->LinkObjectTableCreateSimple(
LinkListWithData => $Param{LinkListWithData},
ViewMode => $Param{ViewMode},
AdditionalLinkListWithDataJSON => $Param{AdditionalLinkListWithDataJSON},
);
}
else {
return $Self->LinkObjectTableCreateComplex(
LinkListWithData => $Param{LinkListWithData},
ViewMode => $Param{ViewMode},
AJAX => $Param{AJAX},
SourceObject => $Param{Object},
ObjectID => $Param{Key},
AdditionalLinkListWithDataJSON => $Param{AdditionalLinkListWithDataJSON},
);
}
}
=head2 LinkObjectTableCreateComplex()
create a complex output table
my $String = $LayoutObject->LinkObjectTableCreateComplex(
LinkListWithData => $LinkListRef,
ViewMode => 'Complex', # (Complex|ComplexAdd|ComplexDelete|ComplexRaw)
);
=cut
sub LinkObjectTableCreateComplex {
my ( $Self, %Param ) = @_;
# get log object
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
# create new instance of the layout object
my $LayoutObject = Kernel::Output::HTML::Layout->new( %{$Self} );
my $LayoutObject2 = Kernel::Output::HTML::Layout->new( %{$Self} );
# check needed stuff
for my $Argument (qw(LinkListWithData ViewMode)) {
if ( !$Param{$Argument} ) {
$LogObject->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# check link list
if ( ref $Param{LinkListWithData} ne 'HASH' ) {
$LogObject->Log(
Priority => 'error',
Message => 'LinkListWithData must be a hash reference!',
);
return;
}
return if !%{ $Param{LinkListWithData} };
# convert the link list
my %LinkList;
for my $Object ( sort keys %{ $Param{LinkListWithData} } ) {
for my $LinkType ( sort keys %{ $Param{LinkListWithData}->{$Object} } ) {
# extract link type List
my $LinkTypeList = $Param{LinkListWithData}->{$Object}->{$LinkType};
for my $Direction ( sort keys %{$LinkTypeList} ) {
# extract direction list
my $DirectionList = $Param{LinkListWithData}->{$Object}->{$LinkType}->{$Direction};
for my $ObjectKey ( sort keys %{$DirectionList} ) {
$LinkList{$Object}->{$ObjectKey}->{$LinkType} = $Direction;
}
}
}
}
my @OutputData;
OBJECT:
for my $Object ( sort { lc $a cmp lc $b } keys %{ $Param{LinkListWithData} } ) {
# load backend
my $BackendObject = $Self->_LoadLinkObjectLayoutBackend(
Object => $Object,
);
next OBJECT if !$BackendObject;
# get block data
my @BlockData = $BackendObject->TableCreateComplex(
ObjectLinkListWithData => $Param{LinkListWithData}->{$Object},
Action => $Self->{Action},
ObjectID => $Param{ObjectID},
);
next OBJECT if !@BlockData;
push @OutputData, @BlockData;
}
# error handling
for my $Block (@OutputData) {
ITEM:
for my $Item ( @{ $Block->{ItemList} } ) {
if ( !grep { $_->{Key} } @{$Item} ) {
$Item->[0] = {
Type => 'Text',
Content =>
'ERROR: Key attribute not found in any column of the item list.',
};
}
next ITEM if $Block->{Object};
if ( !$Block->{Object} ) {
$Item->[0] = {
Type => 'Text',
Content => 'ERROR: Object attribute not found in the block data.',
};
}
}
}
# get config option to show the link delete button
my $ShowDeleteButton = $Kernel::OM->Get('Kernel::Config')->Get('LinkObject::ShowDeleteButton');
# add "linked as" column to the table
for my $Block (@OutputData) {
# define the headline column
my $Column = {
Content => $Kernel::OM->Get('Kernel::Language')->Translate('Linked as'),
};
# add new column to the headline
push @{ $Block->{Headline} }, $Column;
# permission check
my $SourcePermission;
if ( $Param{SourceObject} && $Param{ObjectID} && $ShowDeleteButton ) {
# get source permission
$SourcePermission = $Kernel::OM->Get('Kernel::System::LinkObject')->ObjectPermission(
Object => $Param{SourceObject},
Key => $Param{ObjectID},
UserID => $Self->{UserID},
);
# we show the column headline if we got source permission
if ($SourcePermission) {
$Column = {
Content => $Kernel::OM->Get('Kernel::Language')->Translate('Delete'),
CssClass => 'Center Last',
};
# add new column to the headline
push @{ $Block->{Headline} }, $Column;
}
}
for my $Item ( @{ $Block->{ItemList} } ) {
my %LinkDeleteData;
my $TargetPermission;
# Search for key.
my ($ItemWithKey) = grep { $_->{Key} } @{$Item};
if ( $Param{SourceObject} && $Param{ObjectID} && $ItemWithKey->{Key} && $ShowDeleteButton ) {
for my $LinkType ( sort keys %{ $LinkList{ $Block->{Object} }->{ $ItemWithKey->{Key} } } ) {
# get target permission
$TargetPermission = $Kernel::OM->Get('Kernel::System::LinkObject')->ObjectPermission(
Object => $Block->{Object},
Key => $ItemWithKey->{Key},
UserID => $Self->{UserID},
);
# build the delete link only if we also got target permission
if ($TargetPermission) {
my %InstantLinkDeleteData;
# depending on the link type direction source and target must be switched
if ( $LinkList{ $Block->{Object} }->{ $ItemWithKey->{Key} }->{$LinkType} eq 'Source' ) {
$LinkDeleteData{SourceObject} = $Block->{Object};
$LinkDeleteData{SourceKey} = $ItemWithKey->{Key};
$LinkDeleteData{TargetIdentifier}
= $Param{SourceObject} . '::' . $Param{ObjectID} . '::' . $LinkType;
}
else {
$LinkDeleteData{SourceObject} = $Param{SourceObject};
$LinkDeleteData{SourceKey} = $Param{ObjectID};
$LinkDeleteData{TargetIdentifier}
= $Block->{Object} . '::' . $ItemWithKey->{Key} . '::' . $LinkType;
}
}
}
}
# define check-box cell
my $CheckboxCell = {
Type => 'LinkTypeList',
Content => '',
LinkTypeList => $LinkList{ $Block->{Object} }->{ $ItemWithKey->{Key} },
Translate => 1,
};
# add check-box cell to item
push @{$Item}, $CheckboxCell;
# check if delete icon should be shown
if ( $Param{SourceObject} && $Param{ObjectID} && $SourcePermission && $ShowDeleteButton ) {
if ($TargetPermission) {
# build delete link
push @{$Item}, {
Type => 'DeleteLinkIcon',
CssClass => 'Center Last',
Translate => 1,
%LinkDeleteData,
};
}
else {
# build no delete link, instead use empty values
# to keep table formatting correct
push @{$Item}, {
Type => 'Plain',
CssClass => 'Center Last',
Content => '',
};
}
}
}
}
return @OutputData if $Param{ViewMode} && $Param{ViewMode} eq 'ComplexRaw';
if ( $Param{ViewMode} eq 'ComplexAdd' ) {
for my $Block (@OutputData) {
# define the headline column
my $Column;
# add new column to the headline
unshift @{ $Block->{Headline} }, $Column;
for my $Item ( @{ $Block->{ItemList} } ) {
# search for key
my ($ItemWithKey) = grep { $_->{Key} } @{$Item};
# define check-box cell
my $CheckboxCell = {
Type => 'Checkbox',
Name => 'LinkTargetKeys',
Content => $ItemWithKey->{Key},
};
# add check-box cell to item
unshift @{$Item}, $CheckboxCell;
}
}
}
if ( $Param{ViewMode} eq 'ComplexDelete' ) {
for my $Block (@OutputData) {
# define the headline column
my $Column = {
Content => ' ',
};
# add new column to the headline
unshift @{ $Block->{Headline} }, $Column;
for my $Item ( @{ $Block->{ItemList} } ) {
# search for key
my ($ItemWithKey) = grep { $_->{Key} } @{$Item};
# define check-box delete cell
my $CheckboxCell = {
Type => 'CheckboxDelete',
Object => $Block->{Object},
Content => '',
Key => $ItemWithKey->{Key},
LinkTypeList => $LinkList{ $Block->{Object} }->{ $ItemWithKey->{Key} },
Translate => 1,
};
# add check-box cell to item
unshift @{$Item}, $CheckboxCell;
}
}
}
# # create new instance of the layout object
# my $LayoutObject = Kernel::Output::HTML::Layout->new( %{$Self} );
# my $LayoutObject2 = Kernel::Output::HTML::Layout->new( %{$Self} );
# output the table complex block
$LayoutObject->Block(
Name => 'TableComplex',
);
# set block description
my $BlockDescription = $Param{ViewMode} eq 'ComplexAdd' ? Translatable('Search Result') : Translatable('Linked');
my $BlockCounter = 0;
my $Config = $Kernel::OM->Get('Kernel::Config')->Get("LinkObject::ComplexTable") || {};
my $SettingsVisibility = $Kernel::OM->Get('Kernel::Config')->Get("LinkObject::ComplexTable::SettingsVisibility")
|| {};
my @SettingsVisible = ();
if ( IsHashRefWithData($SettingsVisibility) ) {
for my $Key ( sort keys %{$SettingsVisibility} ) {
for my $Item ( @{ $SettingsVisibility->{$Key} } ) {
# check if it's not in array
if ( !grep { $Item eq $_ } @SettingsVisible ) {
push @SettingsVisible, $Item;
}
}
}
}
# get OriginalAction
my $OriginalAction = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'OriginalAction' )
|| $Self->{Action};
my @LinkObjectTables;
BLOCK:
for my $Block (@OutputData) {
next BLOCK if !$Block->{ItemList};
next BLOCK if ref $Block->{ItemList} ne 'ARRAY';
next BLOCK if !@{ $Block->{ItemList} };
# output the block
$LayoutObject->Block(
Name => 'TableComplexBlock',
Data => {
BlockDescription => $BlockDescription,
Blockname => $Block->{Blockname} . ' (' . scalar @{ $Block->{ItemList} } . ')',
Name => $Block->{Blockname},
NameForm => $Block->{Blockname},
AJAX => $Param{AJAX},
},
);
# check if registered in SysConfig
if (
# AgentLinkObject not allowed because it would result in nested forms
$OriginalAction ne 'AgentLinkObject'
&& IsHashRefWithData($Config)
&& $Config->{ $Block->{Blockname} }
&& grep { $OriginalAction eq $_ } @SettingsVisible
)
{
my $SourceObjectData = '';
if ( $Block->{ObjectName} && $Block->{ObjectID} ) {
$SourceObjectData = "";
}
$LayoutObject->Block(
Name => 'ContentLargePreferences',
Data => {
Name => $Block->{Blockname},
},
);
my %Preferences = $Self->ComplexTablePreferencesGet(
Config => $Config->{ $Block->{Blockname} },
PrefKey => "LinkObject::ComplexTable-" . $Block->{Blockname},
);
# Add translations for the allocation lists for regular columns.
for my $Column ( @{ $Block->{AllColumns} } ) {
$LayoutObject->AddJSData(
Key => 'Column' . $Column->{ColumnName},
Value => $LayoutObject->{LanguageObject}->Translate( $Column->{ColumnTranslate} ),
);
}
# Prepare LinkObjectTables for JS config.
push @LinkObjectTables, $Block->{Blockname};
$LayoutObject->Block(
Name => 'ContentLargePreferencesForm',
Data => {
Name => $Block->{Blockname},
NameForm => $Block->{Blockname},
},
);
$LayoutObject->Block(
Name => $Preferences{Name} . 'PreferencesItem' . $Preferences{Block},
Data => {
%Preferences,
NameForm => $Block->{Blockname},
NamePref => $Preferences{Name},
Name => $Block->{Blockname},
SourceObject => $Param{SourceObject},
DestinationObject => $Block->{Blockname},
OriginalAction => $OriginalAction,
SourceObjectData => $SourceObjectData,
AdditionalLinkListWithDataJSON => $Param{AdditionalLinkListWithDataJSON},
},
);
}
# output table headline
for my $HeadlineColumn ( @{ $Block->{Headline} } ) {
# output a headline column block
$LayoutObject->Block(
Name => 'TableComplexBlockColumn',
Data => $HeadlineColumn,
);
}
# output item list
for my $Row ( @{ $Block->{ItemList} } ) {
# output a table row block
$LayoutObject->Block(
Name => 'TableComplexBlockRow',
);
for my $Column ( @{$Row} ) {
# create the content string
my $Content = $Self->_LinkObjectContentStringCreate(
Object => $Block->{Object},
ContentData => $Column,
LayoutObject => $LayoutObject2,
);
# output a table column block
$LayoutObject->Block(
Name => 'TableComplexBlockRowColumn',
Data => {
%{$Column},
Content => $Content,
},
);
}
}
if ( $Param{ViewMode} eq 'ComplexAdd' ) {
# output the action row block
$LayoutObject->Block(
Name => 'TableComplexBlockActionRow',
);
$LayoutObject->Block(
Name => 'TableComplexBlockActionRowBulk',
Data => {
Name => Translatable('Bulk'),
TableNumber => $BlockCounter,
},
);
# output the footer block
$LayoutObject->Block(
Name => 'TableComplexBlockFooterAdd',
Data => {
LinkTypeStrg => $Param{LinkTypeStrg} || '',
},
);
}
elsif ( $Param{ViewMode} eq 'ComplexDelete' ) {
# output the action row block
$LayoutObject->Block(
Name => 'TableComplexBlockActionRow',
);
$LayoutObject->Block(
Name => 'TableComplexBlockActionRowBulk',
Data => {
Name => Translatable('Bulk'),
TableNumber => $BlockCounter,
},
);
# output the footer block
$LayoutObject->Block(
Name => 'TableComplexBlockFooterDelete',
);
}
else {
# output the footer block
$LayoutObject->Block(
Name => 'TableComplexBlockFooterNormal',
);
}
# increase BlockCounter to set correct IDs for Select All Check-boxes
$BlockCounter++;
}
# Send LinkObjectTables to JS.
$LayoutObject->AddJSData(
Key => 'LinkObjectTables',
Value => \@LinkObjectTables,
);
return $LayoutObject->Output(
TemplateFile => 'LinkObject',
AJAX => $Param{AJAX},
);
}
=head2 LinkObjectTableCreateSimple()
create a simple output table
my $String = $LayoutObject->LinkObjectTableCreateSimple(
LinkListWithData => $LinkListWithDataRef,
ViewMode => 'SimpleRaw', # (optional) (Simple|SimpleRaw)
);
=cut
sub LinkObjectTableCreateSimple {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{LinkListWithData} || ref $Param{LinkListWithData} ne 'HASH' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need LinkListWithData!',
);
return;
}
# get type list
my %TypeList = $Kernel::OM->Get('Kernel::System::LinkObject')->TypeList(
UserID => $Self->{UserID},
);
return if !%TypeList;
my %OutputData;
OBJECT:
for my $Object ( sort keys %{ $Param{LinkListWithData} } ) {
# load backend
my $BackendObject = $Self->_LoadLinkObjectLayoutBackend(
Object => $Object,
);
next OBJECT if !$BackendObject;
# get link output data
my %LinkOutputData = $BackendObject->TableCreateSimple(
ObjectLinkListWithData => $Param{LinkListWithData}->{$Object},
);
next OBJECT if !%LinkOutputData;
for my $LinkType ( sort keys %LinkOutputData ) {
$OutputData{$LinkType}->{$Object} = $LinkOutputData{$LinkType}->{$Object};
}
}
return %OutputData if $Param{ViewMode} && $Param{ViewMode} eq 'SimpleRaw';
# create new instance of the layout object
my $LayoutObject = Kernel::Output::HTML::Layout->new( %{$Self} );
my $LayoutObject2 = Kernel::Output::HTML::Layout->new( %{$Self} );
my $Count = 0;
for my $LinkTypeLinkDirection ( sort { lc $a cmp lc $b } keys %OutputData ) {
$Count++;
# output the table simple block
if ( $Count == 1 ) {
$LayoutObject->Block(
Name => 'TableSimple',
);
}
# investigate link type name
my @LinkData = split q{::}, $LinkTypeLinkDirection;
my $LinkTypeName = $TypeList{ $LinkData[0] }->{ $LinkData[1] . 'Name' };
# output the type block
$LayoutObject->Block(
Name => 'TableSimpleType',
Data => {
LinkTypeName => $LinkTypeName,
},
);
# extract object list
my $ObjectList = $OutputData{$LinkTypeLinkDirection};
for my $Object ( sort { lc $a cmp lc $b } keys %{$ObjectList} ) {
for my $Item ( @{ $ObjectList->{$Object} } ) {
# create the content string
my $Content = $Self->_LinkObjectContentStringCreate(
Object => $Object,
ContentData => $Item,
LayoutObject => $LayoutObject2,
);
# output the type block
$LayoutObject->Block(
Name => 'TableSimpleTypeRow',
Data => {
%{$Item},
Content => $Content,
},
);
}
}
}
# show no linked object available
if ( !$Count ) {
$LayoutObject->Block(
Name => 'TableSimpleNone',
Data => {},
);
}
return $LayoutObject->Output(
TemplateFile => 'LinkObject',
);
}
=head2 LinkObjectSelectableObjectList()
return a selection list of link-able objects
my $String = $LayoutObject->LinkObjectSelectableObjectList(
Object => 'Ticket',
Selected => $Identifier, # (optional)
);
=cut
sub LinkObjectSelectableObjectList {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{Object} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Object!'
);
return;
}
# get possible objects list
my %PossibleObjectsList = $Kernel::OM->Get('Kernel::System::LinkObject')->PossibleObjectsList(
Object => $Param{Object},
UserID => $Self->{UserID},
);
return if !%PossibleObjectsList;
# get the select lists
my @SelectableObjectList;
my @SelectableTempList;
my $AddBlankLines;
POSSIBLEOBJECT:
for my $PossibleObject ( sort { lc $a cmp lc $b } keys %PossibleObjectsList ) {
# load backend
my $BackendObject = $Self->_LoadLinkObjectLayoutBackend(
Object => $PossibleObject,
);
return if !$BackendObject;
# get object select list
my @SelectableList = $BackendObject->SelectableObjectList(
%Param,
);
next POSSIBLEOBJECT if !@SelectableList;
push @SelectableTempList, \@SelectableList;
push @SelectableObjectList, @SelectableList;
next POSSIBLEOBJECT if $AddBlankLines;
# check each keys if blank lines must be added
ROW:
for my $Row (@SelectableList) {
next ROW if !$Row->{Key} || $Row->{Key} !~ m{ :: }xms;
$AddBlankLines = 1;
last ROW;
}
}
# add blank lines
if ($AddBlankLines) {
# reset list
@SelectableObjectList = ();
# define blank line entry
my %BlankLine = (
Key => '-',
Value => '-------------------------',
Disabled => 1,
);
# insert the blank lines
for my $Elements (@SelectableTempList) {
push @SelectableObjectList, @{$Elements};
}
continue {
push @SelectableObjectList, \%BlankLine;
}
# add blank lines in top of the list
unshift @SelectableObjectList, \%BlankLine;
}
# create new instance of the layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# create target object string
my $TargetObjectStrg = $LayoutObject->BuildSelection(
Data => \@SelectableObjectList,
Name => 'TargetIdentifier',
Class => 'Modernize',
TreeView => 1,
);
return $TargetObjectStrg;
}
=head2 LinkObjectSearchOptionList()
return a list of search options
my @SearchOptionList = $LayoutObject->LinkObjectSearchOptionList(
Object => 'Ticket',
SubObject => 'Bla', # (optional)
);
=cut
sub LinkObjectSearchOptionList {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{Object} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Object!'
);
return;
}
# load backend
my $BackendObject = $Self->_LoadLinkObjectLayoutBackend(
Object => $Param{Object},
);
return if !$BackendObject;
# get search option list
my @SearchOptionList = $BackendObject->SearchOptionList(
%Param,
);
return @SearchOptionList;
}
=head2 ComplexTablePreferencesGet()
get items needed for AllocationList initialization.
my %Preferences = $LayoutObject->ComplexTablePreferencesGet(
Config => {
'DefaultColumns' => {
'Age' => 1,
'EscalationTime' => 1,
...
},
Priority => {
'Age' => 120,
'TicketNumber' => 100,
...
}
}.
PrefKey => "LinkObject::ComplexTable-Ticket",
);
returns:
%Preferences = {
'ColumnsAvailable' => '["Age","Changed","CustomerID","CustomerName","CustomerUserID",...]',
'Block' => 'AllocationList',
'Translation' => 1,
'Name' => 'ContentLarge',
'Columns' => '{"Columns":{"SLA":0,"Type":0,"Owner":0,"Service":0,"CustomerUserID":0,...}}',
'Desc' => 'Shown Columns',
'ColumnsEnabled' => '["State","TicketNumber","Title","Created","Queue"]',
};
=cut
sub ComplexTablePreferencesGet {
my ( $Self, %Param ) = @_;
# configure columns
my @ColumnsEnabled;
my @ColumnsAvailable;
my @ColumnsAvailableNotEnabled;
# check for default settings
if (
$Param{Config}->{DefaultColumns}
&& IsHashRefWithData( $Param{Config}->{DefaultColumns} )
)
{
@ColumnsAvailable = grep { $Param{Config}->{DefaultColumns}->{$_} }
keys %{ $Param{Config}->{DefaultColumns} };
@ColumnsEnabled = grep { $Param{Config}->{DefaultColumns}->{$_} eq '2' }
keys %{ $Param{Config}->{DefaultColumns} };
if (
$Param{Config}->{Priority}
&& IsHashRefWithData( $Param{Config}->{Priority} )
)
{
# sort according to priority defined in SysConfig
@ColumnsEnabled
= sort { $Param{Config}->{Priority}->{$a} <=> $Param{Config}->{Priority}->{$b} } @ColumnsEnabled;
}
}
# check if the user has filter preferences for this widget
my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences(
UserID => $Self->{UserID},
);
# get JSON object
my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
# if preference settings are available, take them
if ( $Preferences{ $Param{PrefKey} } ) {
my $ColumnsEnabled = $JSONObject->Decode(
Data => $Preferences{ $Param{PrefKey} },
);
@ColumnsEnabled = grep { $ColumnsEnabled->{Columns}->{$_} == 1 }
keys %{ $ColumnsEnabled->{Columns} };
if ( $ColumnsEnabled->{Order} && @{ $ColumnsEnabled->{Order} } ) {
@ColumnsEnabled = @{ $ColumnsEnabled->{Order} };
}
# 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;
}
my %Columns;
for my $ColumnName ( sort { $a cmp $b } @ColumnsAvailable ) {
$Columns{Columns}->{$ColumnName} = ( grep { $ColumnName eq $_ } @ColumnsEnabled ) ? 1 : 0;
if ( !grep { $_ eq $ColumnName } @ColumnsEnabled ) {
push @ColumnsAvailableNotEnabled, $ColumnName;
}
}
$Columns{Order} = \@ColumnsEnabled;
my %Params = (
Desc => Translatable('Shown Columns'),
Name => "ContentLarge",
Block => 'AllocationList',
Columns => $JSONObject->Encode( Data => \%Columns ),
ColumnsEnabled => $JSONObject->Encode( Data => \@ColumnsEnabled ),
ColumnsAvailable => $JSONObject->Encode( Data => \@ColumnsAvailableNotEnabled ),
Translation => 1,
);
return %Params;
}
=head2 ComplexTablePreferencesSet()
set user preferences.
my $Success = $LayoutObject->ComplexTablePreferencesSet(
DestinationObject => 'Ticket',
);
=cut
sub ComplexTablePreferencesSet {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Needed (qw( DestinationObject)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
# needed objects
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
my $Result = 'Unknown';
my $Config = $ConfigObject->Get("LinkObject::ComplexTable") || {};
# get default preferences
my %Preferences = $Self->ComplexTablePreferencesGet(
Config => $Config->{ $Param{DestinationObject} },
PrefKey => "LinkObject::ComplexTable-" . $Param{DestinationObject},
);
if ( !%Preferences ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No preferences for $Param{DestinationObject}!"
);
return;
}
# get params
my $Value = $ParamObject->GetParam( Param => $Preferences{Name} );
# decode JSON value
my $Preference = $JSONObject->Decode(
Data => $Value,
);
# remove Columns (not needed)
delete $Preference->{Columns};
if ( $Param{DestinationObject} eq 'Ticket' ) {
# Make sure that ticket number is always present, otherwise there will be problems.
if ( !grep { $_ eq 'TicketNumber' } @{ $Preference->{Order} } ) {
unshift @{ $Preference->{Order} }, 'TicketNumber';
}
}
if ( IsHashRefWithData($Preference) ) {
$Value = $JSONObject->Encode(
Data => $Preference,
);
# update runtime vars
$Self->{ $Preferences{Name} } = $Value;
# update session
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => $Preferences{Name},
Value => $Value,
);
# update preferences
if ( !$ConfigObject->Get('DemoSystem') ) {
$Kernel::OM->Get('Kernel::System::User')->SetPreferences(
UserID => $Self->{UserID},
Key => "LinkObject::ComplexTable-" . $Param{DestinationObject},
Value => $Value,
);
return 1;
}
}
return 0;
}
=begin Internal:
=head2 _LinkObjectContentStringCreate()
return a output string
my $String = $LayoutObject->_LinkObjectContentStringCreate(
Object => 'Ticket',
ContentData => $HashRef,
LayoutObject => $LocalLayoutObject,
);
=cut
sub _LinkObjectContentStringCreate {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Argument (qw(Object ContentData LayoutObject)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# load link core module
my $LinkObject = $Kernel::OM->Get('Kernel::System::LinkObject');
# load backend
my $BackendObject = $Self->_LoadLinkObjectLayoutBackend(
Object => $Param{Object},
);
# create content string in backend module
if ($BackendObject) {
my $ContentString = $BackendObject->ContentStringCreate(
%Param,
LinkObject => $LinkObject,
LayoutObject => $Param{LayoutObject},
);
return $ContentString if defined $ContentString;
}
# extract content
my $Content = $Param{ContentData};
# set blockname
my $Blockname = $Content->{Type};
# set global default value
$Content->{MaxLength} ||= 100;
# prepare linktypelist
if ( $Content->{Type} eq 'LinkTypeList' ) {
$Blockname = 'Plain';
# get type list
my %TypeList = $LinkObject->TypeList(
UserID => $Self->{UserID},
);
return if !%TypeList;
my @LinkNameList;
LINKTYPE:
for my $LinkType ( sort { lc $a cmp lc $b } keys %{ $Content->{LinkTypeList} } ) {
next LINKTYPE if $LinkType eq 'NOTLINKED';
# extract direction
my $Direction = $Content->{LinkTypeList}->{$LinkType};
# extract linkname
my $LinkName = $TypeList{$LinkType}->{ $Direction . 'Name' };
# translate
if ( $Content->{Translate} ) {
$LinkName = $Param{LayoutObject}->{LanguageObject}->Translate($LinkName);
}
push @LinkNameList, $LinkName;
}
# join string
my $String = join qq{\n}, @LinkNameList;
# transform ascii to html
$Content->{Content} = $Param{LayoutObject}->Ascii2Html(
Text => $String || '-',
HTMLResultMode => 1,
LinkFeature => 0,
);
}
# prepare checkbox delete
elsif ( $Content->{Type} eq 'CheckboxDelete' ) {
$Blockname = 'Plain';
# get type list
my %TypeList = $LinkObject->TypeList(
UserID => $Self->{UserID},
);
return if !%TypeList;
LINKTYPE:
for my $LinkType ( sort { lc $a cmp lc $b } keys %{ $Content->{LinkTypeList} } ) {
next LINKTYPE if $LinkType eq 'NOTLINKED';
# extract direction
my $Direction = $Content->{LinkTypeList}->{$LinkType};
# extract linkname
my $LinkName = $TypeList{$LinkType}->{ $Direction . 'Name' };
# translate
if ( $Content->{Translate} ) {
$LinkName = $Param{LayoutObject}->{LanguageObject}->Translate($LinkName);
}
# run checkbox block
$Param{LayoutObject}->Block(
Name => 'Checkbox',
Data => {
%{$Content},
Name => 'LinkDeleteIdentifier',
Title => $LinkName,
Content => $Content->{Object} . '::' . $Content->{Key} . '::' . $LinkType,
},
);
}
$Content->{Content} = $Param{LayoutObject}->Output(
TemplateFile => 'LinkObject',
);
}
elsif ( $Content->{Type} eq 'TimeLong' ) {
$Blockname = 'TimeLong';
}
elsif ( $Content->{Type} eq 'Date' ) {
$Blockname = 'Date';
}
# prepare text
elsif ( $Content->{Type} eq 'Text' || !$Content->{Type} ) {
$Blockname = $Content->{Translate} ? 'TextTranslate' : 'Text';
$Content->{Content} ||= '-';
}
# run block
$Param{LayoutObject}->Block(
Name => $Blockname,
Data => $Content,
);
return $Param{LayoutObject}->Output(
TemplateFile => 'LinkObject',
);
}
=head2 _LoadLinkObjectLayoutBackend()
load a linkobject layout backend module
$BackendObject = $LayoutObject->_LoadLinkObjectLayoutBackend(
Object => 'Ticket',
);
=cut
sub _LoadLinkObjectLayoutBackend {
my ( $Self, %Param ) = @_;
# get log object
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
# check needed stuff
if ( !$Param{Object} ) {
$LogObject->Log(
Priority => 'error',
Message => 'Need Object!',
);
return;
}
# check if object is already cached
return $Self->{Cache}->{LoadLinkObjectLayoutBackend}->{ $Param{Object} }
if $Self->{Cache}->{LoadLinkObjectLayoutBackend}->{ $Param{Object} };
my $GenericModule = "Kernel::Output::HTML::LinkObject::$Param{Object}";
# load the backend module
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($GenericModule) ) {
$LogObject->Log(
Priority => 'error',
Message => "Can't load backend module $Param{Object}!"
);
return;
}
# create new instance
my $BackendObject = $GenericModule->new(
%{$Self},
%Param,
);
if ( !$BackendObject ) {
$LogObject->Log(
Priority => 'error',
Message => "Can't create a new instance of backend module $Param{Object}!",
);
return;
}
# cache the object
$Self->{Cache}->{LoadLinkObjectLayoutBackend}->{ $Param{Object} } = $BackendObject;
return $BackendObject;
}
=end Internal:
=cut
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L).
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.
=cut