Ticketliste als neue Queue Ansicht im Dashboard

Hilfe zu Znuny Problemen aller Art
Locked
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Hallo,

ist es möglich, nach eigenen Kritieren zusätzlich eine Ticketliste im Dashboard zu erstellen?
Also wie die Queue Ansicht "Neue Tickets", "Offene Tickets" etc.
Danke!
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

Ja. Wir haben uns z.B. eine "Liste" der offenen WorkOrders im Dashboard erstellt.

Vorgehen wäre:
- Kopiere dir die .pm und .tt Dateien einer Liste die deiner gewünschten möglichst nahe kommt
- Registriere sie mit anderen Namen durch eine .xml Datei in ~otrs/Kernel/Config/Files/
- Passe die kopierten Perl und Template Dateien deinen Wünschen entsprechend an.
Last edited by RStraub on 12 Jun 2015, 12:15, edited 1 time in total.
Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

und wie geht das?
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

Erste Antwort war zu kurz :) Hab sie etwas editiert.
Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Super Danke!. Kannst Du mir noch sagen in welchem Pfad die .tt Dateien liegen?
Danke und schönes Wochenende!
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

die liegen unter:
~otrs/Kernel/Output/HTML/Standard/

z.B. AgentDashboardTicketQueueOverview.tt
Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Super vielen Dank!!!!
Linux Debian Jessie
DB: postgres
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Könntest Du mir vielleicht noch ein Beispiel für die XML Registrierung geben. Das wäre nett. Danke!
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

Das hier ist das Beispiel für die "WorkOrder" Übersicht.
Eigentlich bau ich die .xml Datein zweigeteilt: Einmal die Registrierung und einmal einen Eintrag für die Konfiguration. Das ist hier beides zusammengeworfen (Sortierung, Status-Filter etc.).
Wichtig ist der Module-Eintrag im Hash und der Name vor dem ###.

Code: Select all

    <ConfigItem Name="DashboardBackend###1600-WorkOrderOverview" Required="0" Valid="1">
        <Description Translatable="1">Some Description</Description>
        <Group>TTO Framework</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardWorkOrderOverview</Item>
                <Item Key="Title">Workorder Overview</Item>
                <Item Key="Description">All workorders</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="QueuePermissionGroup">users</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="Sort">SortBy=Age;OrderBy=Up</Item>
                <Item Key="CacheTTLLocal">0.5</Item>
                <Item Key="States">
                    <Hash>
                        <Item Key="125">accepted</Item>
                        <Item Key="129">canceled</Item>
                        <Item Key="128">closed</Item>
                        <Item Key="124">created</Item>
                        <Item Key="127">in progress</Item>
                        <Item Key="126">ready</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>
Für ein Standalone-File müsstest du das ganze noch einrahmen mit:

Code: Select all

<otrs_config version="1.0" init="Framework">
</otrs_config>
Nach Aktualisierung der SysConfig sucht (und erwartet) OTRS dann diese Datei bei jedem Dashboard Aufruf:
~otrs(/Custom/)/Kernel/Output/HTML/DashboardWorkOrderOverview.pm
Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Danke soweit funktioniert es. Leider ist die Ansicht aber die Falsche. Haben möchte ich:

eine Queue Ansicht alle Tickets mit bestimmten Status. Erhalten habe ich aber eine Ansicht, welche ich mal in der Statistik erstellt habe.
Habe ich evtl. die falsche .tt Datei genommen? Ich hoffe du hast noch Geduld für eine Antwort. Danke! ;)

DashboardTicketQueueProjekt.xml

Code: Select all

<otrs_config version="1.0" init="Framework">
<ConfigItem Name="DashboardBackend###1600-DashboardTicketQueueProjekt" Required="0" Valid="1">
        <Description Translatable="1">Projektansicht</Description>
        <Group>TTO Framework</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardTicketQueueProjekt</Item>
                <Item Key="Title">Projekt Overview</Item>
                <Item Key="Description">Alle Projekte</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="QueuePermissionGroup">users</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="Sort">SortBy=Age;OrderBy=Up</Item>
                <Item Key="CacheTTLLocal">0.5</Item>
                <Item Key="States">
                    <Hash>
                        <Item Key="125">accepted</Item>
                        <Item Key="129">canceled</Item>
                        <Item Key="128">closed</Item>
                        <Item Key="124">created</Item>
                        <Item Key="127">in progress</Item>
                        <Item Key="126">ready</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>
</otrs_config>	
AgentDashboardTicketQueueProjekt.tt

Code: Select all

# --
# AgentDashboardTicketQueueOverview.tt - provides HTML for Ticket Queue Overview
# Copyright (C) 2001-2015 xxx, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

<table class="DataTable">
    <thead>
        <tr>
[% RenderBlockStart("ContentLargeTicketQueueOverviewHeaderStatus") %]
            <th>[% Translate(Data.Text) | html %]</th>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewHeaderStatus") %]
            <th class="QueueOverviewTotals">[% Translate("Totals") | html %]</th>
        </tr>
    </thead>
    <tbody>
[% RenderBlockStart("ContentLargeTicketQueueOverviewQueueName") %]
        <tr class="Row">
            <td>[% Data.QueueName | html %]</td>
[% RenderBlockStart("ContentLargeTicketQueueOverviewQueueResults") %]
            <td><a class="AsBlock" href="[% Env("Baselink") %]Action=AgentTicketSearch;Subaction=Search;[% Env("ChallengeTokenParam") | html %];StateIDs=[% Data.StateID | uri %];QueueIDs=[% Data.QueueID | uri %];[% Data.Sort | html %]">[% Translate(Data.Number) | html %]</a></td>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewQueueResults") %]
[% RenderBlockStart("ContentLargeTicketQueueOverviewQueueTotal") %]
            <td><a class="QueueOverviewTotals AsBlock" href="[% Env("Baselink") %]Action=AgentTicketSearch;Subaction=Search;[% Env("ChallengeTokenParam") | html %];QueueIDs=[% Data.QueueID | uri %];[% Data.StateIDs | html %];[% Data.Sort | html %]">[% Translate(Data.Number) | html %]</a></td>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewQueueTotal") %]
        </tr>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewQueueName") %]
[% RenderBlockStart("ContentLargeTicketQueueOverviewStatusTotalRow") %]
        <tr class="Row">
            <td class="QueueOverviewTotals">[% Translate("Totals") | html %]</td>
[% RenderBlockStart("ContentLargeTicketQueueOverviewStatusTotal") %]
            <td class="QueueOverviewTotals"><a class="AsBlock" href="[% Env("Baselink") %]Action=AgentTicketSearch;Subaction=Search;[% Env("ChallengeTokenParam") | html %];StateIDs=[% Data.StateID | uri %];[% Data.QueueIDs | html %];[% Data.Sort | html %]">[% Translate(Data.Number) | html %]</a></td>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewStatusTotal") %]
            <td class="QueueOverviewTotals"></td>
        </tr>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewStatusTotalRow") %]
[% RenderBlockStart("ContentLargeTicketQueueOverviewNone") %]
        <tr>
            <td colspan="[% Data.ColumnCount | html %]">
                [% Translate("No data found.") | html %]
            </td>
        </tr>
[% RenderBlockEnd("ContentLargeTicketQueueOverviewNone") %]
    </tbody>
</table>

[% RenderBlockStart("ContentLargeTicketQueueOverviewRefresh") %]
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
Core.Config.Set('RefreshSeconds_[% Data.NameHTML | html %]', parseInt("[% Data.RefreshTime | html %]", 10) || 0);
if (Core.Config.Get('RefreshSeconds_[% Data.NameHTML | html %]')) {
    Core.Config.Set('Timer_[% Data.NameHTML | html %]', window.setTimeout(function() {

        // get active filter
        var Filter = $('#Dashboard[% Data.Name | html %]-box').find('.Tab.Actions li.Selected a').attr('data-filter');
        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=[% Data.CustomerID | html %]', function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        clearTimeout(Core.Config.Get('Timer_[% Data.NameHTML | html %]'));
    }, Core.Config.Get('RefreshSeconds_[% Data.NameHTML | html %]') * 1000));
}
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketQueueOverviewRefresh") %]
DashboardTicketQueueProjekt.pm

Code: Select all

# --
# Kernel/Output/HTML/DashboardTicketQueueOverview.pm
# Copyright (C) 2001-2015 xxx, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Output::HTML::DashboardTicketQueueOverview;

use strict;
use warnings;

our $ObjectManagerDisabled = 1;

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );

    # get needed parameters
    for my $Object (qw( Config Name UserID )) {
        die "Got no $Object!" if ( !$Self->{$Object} );
    }

    $Self->{PrefKey}  = 'UserDashboardPref' . $Self->{Name} . '-Shown';
    $Self->{CacheKey} = $Self->{Name} . '-' . $Self->{UserID};

    return $Self;
}

sub Preferences {
    my ( $Self, %Param ) = @_;

    return;
}

sub Config {
    my ( $Self, %Param ) = @_;

    return (
        %{ $Self->{Config} },

        # remember, do not allow to use page cache
        # (it's not working because of internal filter)
        CacheKey => undef,
        CacheTTL => undef,
    );
}

sub Run {
    my ( $Self, %Param ) = @_;

    my $LimitGroup = $Self->{Config}->{QueuePermissionGroup} || 0;
    my $CacheKey = 'User' . '-' . $Self->{UserID} . '-' . $LimitGroup;

    my $Content = $Self->{CacheObject}->Get(
        Type => 'DashboardQueueOverview',
        Key  => $CacheKey,
    );
    return $Content if defined $Content;

    # get configured states, get their state ID and test if they exist while we do it
    my %States;
    my $StateIDURL;
    my %ConfiguredStates = %{ $Self->{Config}->{States} };
    for my $StateOrder ( sort { $a <=> $b } keys %ConfiguredStates ) {
        my $State = $ConfiguredStates{$StateOrder};

        # check if state is found, to record StateID
        my $StateID = $Kernel::OM->Get('Kernel::System::State')->StateLookup(
            State => $State,
        ) || '';
        if ($StateID) {
            $States{$State} = $StateID;

            # append StateID to URL for search string
            $StateIDURL .= "StateIDs=$StateID;";
        }
        else {

            # state does not exist, skipping
            delete $ConfiguredStates{$StateOrder};
        }
    }

    # get queue object
    my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');

    # get all queues
    my %Queues = $QueueObject->GetAllQueues(
        UserID => $Self->{UserID},
        Type   => 'ro',
    );

    # limit them by QueuePermissionGroup if needed
    my $LimitGroupID;
    if ($LimitGroup) {
        $LimitGroupID = $Self->{GroupObject}->GroupLookup(
            Group => $LimitGroup,
        );
    }

    my $Sort = $Self->{Config}->{Sort} || '';

    my %QueueToID;
    my $QueueIDURL;

    # lookup queues, add their QueueID to new hash (needed for Search)
    QUEUES:
    for my $QueueID ( sort keys %Queues ) {

        # see if we have to remove the queue based on LimitGroup
        if ($LimitGroup) {
            my $GroupID = $QueueObject->GetQueueGroupID(
                QueueID => $QueueID,
            );
            if ( $GroupID != $LimitGroupID ) {
                delete $Queues{$QueueID};
                next QUEUES;
            }
        }

        # add queue to reverse hash
        $QueueToID{ $Queues{$QueueID} } = $QueueID;

        # add queue to SearchURL
        $QueueIDURL .= "QueueIDs=$QueueID;";
    }

    my %Results;
    for my $QueueID ( sort keys %Queues ) {
        my @Results;
        for my $StateOrderID ( sort { $a <=> $b } keys %ConfiguredStates ) {
            my $QueueTotal = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
                UserID => $Self->{UserID},
                Result => 'COUNT',
                Queues => [ $Queues{$QueueID} ],
                States => [ $ConfiguredStates{$StateOrderID} ],
            );
            push @Results, $QueueTotal;
        }

        $Results{ $Queues{$QueueID} } = [@Results];
    }

    # build header
    my @Headers = ( 'Queue', );
    for my $StateOrder ( sort { $a <=> $b } keys %ConfiguredStates ) {
        push @Headers, $ConfiguredStates{$StateOrder};
    }

    # get layout object
    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');

    for my $HeaderItem (@Headers) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewHeaderStatus',
            Data => {
                Text => $HeaderItem,
            },
        );
    }

    my $HasContent;

    # iterate over all queues, print results;
    my @StatusTotal;
    QUEUE:
    for my $Queue ( sort values %Queues ) {

        # Hide empty queues
        if ( !grep { defined $_ && $_ > 0 } @{ $Results{$Queue} } ) {
            next QUEUE;
        }

        $HasContent++;

        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewQueueName',
            Data => {
                QueueName => $Queue,
                }
        );

        # iterate over states
        my $Counter = 0;
        my $RowTotal;
        for my $StateOrderID ( sort { $a <=> $b } keys %ConfiguredStates ) {
            $LayoutObject->Block(
                Name => 'ContentLargeTicketQueueOverviewQueueResults',
                Data => {
                    Number  => $Results{$Queue}->[$Counter],
                    QueueID => $QueueToID{$Queue},
                    StateID => $States{ $ConfiguredStates{$StateOrderID} },
                    State   => $ConfiguredStates{$StateOrderID},
                    Sort    => $Sort,
                },
            );
            $RowTotal += $Results{$Queue}->[$Counter] || 0;
            $StatusTotal[$StateOrderID] += $Results{$Queue}->[$Counter] || 0;
            $Counter++;
        }

        # print row (queue) total
        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewQueueTotal',
            Data => {
                Number   => $RowTotal,
                QueueID  => $QueueToID{$Queue},
                StateIDs => $StateIDURL,
                Sort     => $Sort,
            },
        );

    }

    if ($HasContent) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewStatusTotalRow',
        );

        for my $StateOrderID ( sort { $a <=> $b } keys %ConfiguredStates ) {
            $LayoutObject->Block(
                Name => 'ContentLargeTicketQueueOverviewStatusTotal',
                Data => {
                    Number   => $StatusTotal[$StateOrderID],
                    QueueIDs => $QueueIDURL,
                    StateID  => $States{ $ConfiguredStates{$StateOrderID} },
                    Sort     => $Sort,
                },
            );
        }
    }
    else {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewNone',
            Data => {
                ColumnCount => ( scalar keys %ConfiguredStates ) + 2,
                }
        );
    }

    # check for refresh time
    my $Refresh = '';
    if ( $Self->{UserRefreshTime} ) {
        $Refresh = 60 * $Self->{UserRefreshTime};
        my $NameHTML = $Self->{Name};
        $NameHTML =~ s{-}{_}xmsg;
        $LayoutObject->Block(
            Name => 'ContentLargeTicketQueueOverviewRefresh',
            Data => {
                %{ $Self->{Config} },
                Name        => $Self->{Name},
                NameHTML    => $NameHTML,
                RefreshTime => $Refresh,
            },
        );
    }

    $Content = $LayoutObject->Output(
        TemplateFile => 'AgentDashboardTicketQueueProjekt',
        Data         => {
            %{ $Self->{Config} },
            Name => $Self->{Name},
        },
        KeepScriptTags => $Param{AJAX},
    );

    # cache result
    if ( $Self->{Config}->{CacheTTLLocal} ) {
        $Self->{CacheObject}->Set(
            Type  => 'DashboardQueueOverview',
            Key   => $CacheKey,
            Value => $Content || '',
            TTL   => 2 * 60,
        );
    }

    return $Content;
}

1;
You do not have the required permissions to view the files attached to this post.
Linux Debian Jessie
DB: postgres
aph
Znuny superhero
Posts: 646
Joined: 20 Jun 2014, 12:11
Znuny Version: 3.3.9, 4.x, 5.x

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by aph »

Wenn du eine ähnliche Liste wie "Offene Tickets" auf dem Dashboard darstellen willt, solltest du vllt DashboardTicketGeneric.pm und AgentDashboardTicketGeneric.tt als Basis nehmen.
OTRS 3.3.x (private/testing) on Windows Server 2008 with MSSQL database.
OTRS 3.3.x (private/testing) on CentOS with MySQL database and apache
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Ok jetzt habe ich auf diese beiden Dateien umgestellt. Nun kann ich aber nicht mehr auf das Dashboard zugreifen. Internal Server Error!
Warum? Ich denke es hängt an der xml Datei. Danke!

Code: Select all

<otrs_config version="1.0" init="Framework">
<ConfigItem Name="DashboardBackend###1700-DashboardTicketGenericProjekt" Required="0" Valid="1">
        <Description Translatable="1">Projektansicht</Description>
        <Group>RitterIT Framework</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardTicketGenericProjekt</Item>
                <Item Key="Title">Projekt Overview</Item>
                <Item Key="Description">Alle Projekte</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="QueuePermissionGroup">users</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="Sort">SortBy=Age;OrderBy=Up</Item>
                <Item Key="CacheTTLLocal">0.5</Item>       
				<Item Key="States">
                    <Hash>
                        <Item Key="125">accepted</Item>
                        <Item Key="129">canceled</Item>
                        <Item Key="128">closed</Item>
                        <Item Key="124">created</Item>
                        <Item Key="127">in progress</Item>
                        <Item Key="126">ready</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>
</otrs_config>	
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

Internal Server , aha, das ist ja spezifisch :)

Zeig uns mal den Apache-Log während einem Dashboard Zugriff bitte.

(und im Zweifel erstmal:

- Apache reload
- RebuildConfig
- DeleteCache)
Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Rebuild und neustart etc. habe ich alles schon gemacht.

Sorry die Apache error.log gibt folgendes aus:

Code: Select all

[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"32"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"46"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"30"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"29"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"218"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"216"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"32"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"30"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"30"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"46"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"32"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"46"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"30"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"29"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"19"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"19"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"216"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"32"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"46"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"30"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"29"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"108"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"4"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e: Use of uninitialized value $ValueHash{"218"} in string comparison (cmp) at /opt/otrs//Kernel/Output/HTML/DashboardStats.pm line 231.
[Mon Jun 15 14:35:18 2015] -e:  (in cleanup) Can't call method "Get" on an undefined value at /opt/otrs//Kernel/System/AuthSession/DB.pm line 583.
[Mon Jun 15 14:35:18 2015] [error] \t(in cleanup) Can't call method "Get" on an undefined value at /opt/otrs//Kernel/System/AuthSession/DB.pm line 583.\n
Linux Debian Jessie
DB: postgres
RStraub
Znuny guru
Posts: 2210
Joined: 13 Mar 2014, 09:16
Znuny Version: 6.0.14
Real Name: Rolf Straub

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by RStraub »

Ich vermute das liegt daran das einige Parameter für das Generic-Widget anders gestaltet sein müssen, als für die Queue Ansicht. Für das Generic Widget, kopiere u. modifiziere auch lieber den .xml Code dafür:

Code: Select all

    <ConfigItem Name="DashboardBackend###0130-TicketOpen" Required="0" Valid="1">
        <Description Translatable="1">Parameters for the dashboard backend of the ticket pending reminder overview of the agent interface. "Limit" is the number of entries shown by default. "Group" is used to restrict the access to the plugin (e. g. Group: admin;group1;group2;). "Default" determines if the plugin is enabled by default or if the user needs to enable it manually. "CacheTTLLocal" is the cache time in minutes for the plugin. Note: Only Ticket attributes and Dynamic Fields (DynamicField_NameX) are allowed for DefaultColumns. Possible settings: 0 = Disabled, 1 = Available, 2 = Enabled by default.</Description>
        <Group>Ticket</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardTicketGeneric</Item>
                <Item Key="Title" Translatable="1">Open Tickets / Need to be answered</Item>
                <Item Key="Description" Translatable="1">All open tickets, these tickets have already been worked on, but need a response</Item>
                <Item Key="Attributes">StateType=open;</Item>
                <Item Key="Filter">All</Item>
                <Item Key="Time">Age</Item>
                <Item Key="Limit">10</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="CacheTTLLocal">0.5</Item>
                <Item Key="DefaultColumns">
                    <Hash>
                        <Item Key="Age">2</Item>
                        <Item Key="Changed">1</Item>
                        <Item Key="CustomerID">1</Item>
                        <Item Key="CustomerName">1</Item>
                        <Item Key="CustomerUserID">1</Item>
                        <Item Key="EscalationResponseTime">1</Item>
                        <Item Key="EscalationSolutionTime">1</Item>
                        <Item Key="EscalationTime">1</Item>
                        <Item Key="EscalationUpdateTime">1</Item>
                        <Item Key="TicketNumber">2</Item>
                        <Item Key="Lock">1</Item>
                        <Item Key="Owner">1</Item>
                        <Item Key="PendingTime">1</Item>
                        <Item Key="Queue">1</Item>
                        <Item Key="Responsible">1</Item>
                        <Item Key="Priority">1</Item>
                        <Item Key="Service">1</Item>
                        <Item Key="State">1</Item>
                        <Item Key="SLA">1</Item>
                        <Item Key="Title">2</Item>
                        <Item Key="Type">1</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>

Currently using: OTRS 6.0.14 -- MariaDB -- Ubuntu 16 LTS
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

hmm... nachdem ich die XML Datei nun auf Deinen Vorschlag hin umgestellt habe, erscheint die Einstellung auch in der Sysconfig nicht mehr.

Code: Select all

<ConfigItem Name="DashboardBackend###11899-DashboardTicketGenericProjekt" Required="0" Valid="1">
        <Description Translatable="1">Parameters for the dashboard backend of the ticket pending reminder overview of the agent interface. "Limit" is the number of entries shown by default. "Group" is used to restrict the access to the plugin (e. g. Group: admin;group1;group2;). "Default" determines if the plugin is enabled by default or if the user needs to enable it manually. "CacheTTLLocal" is the cache time in minutes for the plugin. Note: Only Ticket attributes and Dynamic Fields (DynamicField_NameX) are allowed for DefaultColumns. Possible settings: 0 = Disabled, 1 = Available, 2 = Enabled by default.</Description>
        <Group>Ritter Framework</Group>
        <SubGroup>Frontend::Agent::DashboardRitter</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardTicketGenericProjekt</Item>
                <Item Key="Title" Translatable="1">Offene Projekt Tickets</Item>
                <Item Key="Description" Translatable="1">All open tickets, these tickets have already been worked on, but need a response</Item>
                <Item Key="Attributes">StateType=open;</Item>
                <Item Key="Filter">All</Item>
                <Item Key="Time">Age</Item>
                <Item Key="Limit">10</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="CacheTTLLocal">0.5</Item>
                <Item Key="DefaultColumns">
                    <Hash>
                        <Item Key="Age">2</Item>
                        <Item Key="Changed">1</Item>
                        <Item Key="CustomerID">1</Item>
                        <Item Key="CustomerName">1</Item>
                        <Item Key="CustomerUserID">1</Item>
                        <Item Key="EscalationResponseTime">1</Item>
                        <Item Key="EscalationSolutionTime">1</Item>
                        <Item Key="EscalationTime">1</Item>
                        <Item Key="EscalationUpdateTime">1</Item>
                        <Item Key="TicketNumber">2</Item>
                        <Item Key="Lock">1</Item>
                        <Item Key="Owner">1</Item>
                        <Item Key="PendingTime">1</Item>
                        <Item Key="Queue">1</Item>
                        <Item Key="Responsible">1</Item>
                        <Item Key="Priority">1</Item>
                        <Item Key="Service">1</Item>
                        <Item Key="State">1</Item>
                        <Item Key="SLA">1</Item>
                        <Item Key="Title">2</Item>
                        <Item Key="Type">1</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>	
Linux Debian Jessie
DB: postgres
aph
Znuny superhero
Posts: 646
Joined: 20 Jun 2014, 12:11
Znuny Version: 3.3.9, 4.x, 5.x

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by aph »

Da fehlt am Anfang

Code: Select all

<?xml version="1.0" encoding="utf-8"?>
 <otrs_config version="1.0" init="Application">
und

Code: Select all

</ConfigItem>
</otrs_config>
am Ende
OTRS 3.3.x (private/testing) on Windows Server 2008 with MSSQL database.
OTRS 3.3.x (private/testing) on CentOS with MySQL database and apache
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

sorry das hatte ich übersehen. Leider funktioniert es aber immer noch nicht. Jetzt kommt wieder der Internal Server Error!

Im error.log von Apache bringt er nun:

Code: Select all

[Tue Jun 16 07:14:12 2015] [error] \t(in cleanup) Can't call method "Get" on an undefined value at /opt/otrs//Kernel/System/AuthSession/DB.pm line 583.\n
[Tue Jun 16 07:14:12 2015] [error] [client 172.20.220.151] File does not exist: /var/www/favicon.ico, referer: http://otrs/otrs/index.pl?Action=AgentDashboard
Linux Debian Jessie
DB: postgres
aph
Znuny superhero
Posts: 646
Joined: 20 Jun 2014, 12:11
Znuny Version: 3.3.9, 4.x, 5.x

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by aph »

Internal Server Error trotz rebuilconfig, apache Neustart und delete cache?
Kannst du die entsprechenden config xml, .pm und .tt posten?
OTRS 3.3.x (private/testing) on Windows Server 2008 with MSSQL database.
OTRS 3.3.x (private/testing) on CentOS with MySQL database and apache
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Ja genau habe ich alles gemacht. Rebuild, DeleteCache und apache neu start. Ohne Erfolg. Hier die entsprechenden Dateien. Danke!!!

DashboardTicketGenericProjekt.pm

Code: Select all

# --
# Kernel/Output/HTML/DashboardTicketGeneric.pm
# Copyright (C) 2001-2015 xxx, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Output::HTML::DashboardTicketGeneric;

use strict;
use warnings;

use Kernel::System::VariableCheck qw(:all);

our $ObjectManagerDisabled = 1;

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );

    # get needed parameters
    for my $Item (qw(Config Name UserID)) {
        die "Got no $Item!" if ( !$Self->{$Item} );
    }

    # get param object
    my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');

    my $RemoveFilters = $ParamObject->GetParam( Param => 'RemoveFilters' )
        || $Param{RemoveFilters}
        || 0;

    # get sorting params
    for my $Item (qw(SortBy OrderBy)) {
        $Self->{$Item} = $ParamObject->GetParam( Param => $Item ) || $Param{$Item};
    }

    # set filter settings
    for my $Item (qw(ColumnFilter GetColumnFilter GetColumnFilterSelect)) {
        $Self->{$Item} = $Param{$Item};
    }

    # save column filters
    $Self->{PrefKeyColumnFilters}         = 'UserDashboardTicketGenericColumnFilters' . $Self->{Name};
    $Self->{PrefKeyColumnFiltersRealKeys} = 'UserDashboardTicketGenericColumnFiltersRealKeys' . $Self->{Name};

    # get needed objects
    my $JSONObject   = $Kernel::OM->Get('Kernel::System::JSON');
    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
    my $UserObject   = $Kernel::OM->Get('Kernel::System::User');

    if ($RemoveFilters) {
        $UserObject->SetPreferences(
            UserID => $Self->{UserID},
            Key    => $Self->{PrefKeyColumnFilters},
            Value  => '',
        );
        $UserObject->SetPreferences(
            UserID => $Self->{UserID},
            Key    => $Self->{PrefKeyColumnFiltersRealKeys},
            Value  => '',
        );
    }

    # just in case new filter values arrive
    elsif (
        IsHashRefWithData( $Self->{GetColumnFilter} )
        && IsHashRefWithData( $Self->{GetColumnFilterSelect} )
        && IsHashRefWithData( $Self->{ColumnFilter} )
        )
    {

        if ( !$ConfigObject->Get('DemoSystem') ) {

            # check if the user has filter preferences for this widget
            my %Preferences = $UserObject->GetPreferences(
                UserID => $Self->{UserID},
            );
            my $ColumnPrefValues;
            if ( $Preferences{ $Self->{PrefKeyColumnFilters} } ) {
                $ColumnPrefValues = $JSONObject->Decode(
                    Data => $Preferences{ $Self->{PrefKeyColumnFilters} },
                );
            }

            PREFVALUES:
            for my $Column ( sort keys %{ $Self->{GetColumnFilterSelect} } ) {
                if ( $Self->{GetColumnFilterSelect}->{$Column} eq 'DeleteFilter' ) {
                    delete $ColumnPrefValues->{$Column};
                    next PREFVALUES;
                }
                $ColumnPrefValues->{$Column} = $Self->{GetColumnFilterSelect}->{$Column};
            }

            $UserObject->SetPreferences(
                UserID => $Self->{UserID},
                Key    => $Self->{PrefKeyColumnFilters},
                Value  => $JSONObject->Encode( Data => $ColumnPrefValues ),
            );

            # save real key's name
            my $ColumnPrefRealKeysValues;
            if ( $Preferences{ $Self->{PrefKeyColumnFiltersRealKeys} } ) {
                $ColumnPrefRealKeysValues = $JSONObject->Decode(
                    Data => $Preferences{ $Self->{PrefKeyColumnFiltersRealKeys} },
                );
            }
            REALKEYVALUES:
            for my $Column ( sort keys %{ $Self->{ColumnFilter} } ) {
                next REALKEYVALUES if !$Column;

                my $DeleteFilter = 0;
                if ( IsArrayRefWithData( $Self->{ColumnFilter}->{$Column} ) ) {
                    if ( grep { $_ eq 'DeleteFilter' } @{ $Self->{ColumnFilter}->{$Column} } ) {
                        $DeleteFilter = 1;
                    }
                }
                elsif ( IsHashRefWithData( $Self->{ColumnFilter}->{$Column} ) ) {

                    if (
                        grep { $Self->{ColumnFilter}->{$Column}->{$_} eq 'DeleteFilter' }
                        keys %{ $Self->{ColumnFilter}->{$Column} }
                        )
                    {
                        $DeleteFilter = 1;
                    }
                }

                if ($DeleteFilter) {
                    delete $ColumnPrefRealKeysValues->{$Column};
                    delete $Self->{ColumnFilter}->{$Column};
                    next REALKEYVALUES;
                }
                $ColumnPrefRealKeysValues->{$Column} = $Self->{ColumnFilter}->{$Column};
            }
            $UserObject->SetPreferences(
                UserID => $Self->{UserID},
                Key    => $Self->{PrefKeyColumnFiltersRealKeys},
                Value  => $JSONObject->Encode( Data => $ColumnPrefRealKeysValues ),
            );

        }
    }

    # check if the user has filter preferences for this widget
    my %Preferences = $UserObject->GetPreferences(
        UserID => $Self->{UserID},
    );

    # get column names from Preferences
    my $PreferencesColumnFilters;
    if ( $Preferences{ $Self->{PrefKeyColumnFilters} } ) {
        $PreferencesColumnFilters = $JSONObject->Decode(
            Data => $Preferences{ $Self->{PrefKeyColumnFilters} },
        );
    }

    if ($PreferencesColumnFilters) {
        $Self->{GetColumnFilterSelect} = $PreferencesColumnFilters;
        my @ColumnFilters = keys %{$PreferencesColumnFilters};    ## no critic
        for my $Field (@ColumnFilters) {
            $Self->{GetColumnFilter}->{ $Field . $Self->{Name} } = $PreferencesColumnFilters->{$Field};
        }
    }

    # get column real names from Preferences
    my $PreferencesColumnFiltersRealKeys;
    if ( $Preferences{ $Self->{PrefKeyColumnFiltersRealKeys} } ) {
        $PreferencesColumnFiltersRealKeys = $JSONObject->Decode(
            Data => $Preferences{ $Self->{PrefKeyColumnFiltersRealKeys} },
        );
    }

    if ($PreferencesColumnFiltersRealKeys) {
        my @ColumnFiltersReal = keys %{$PreferencesColumnFiltersRealKeys};    ## no critic
        for my $Field (@ColumnFiltersReal) {
            $Self->{ColumnFilter}->{$Field} = $PreferencesColumnFiltersRealKeys->{$Field};
        }
    }

    # get current filter
    my $Name = $ParamObject->GetParam( Param => 'Name' ) || '';
    my $PreferencesKey = 'UserDashboardTicketGenericFilter' . $Self->{Name};
    if ( $Self->{Name} eq $Name ) {
        $Self->{Filter} = $ParamObject->GetParam( Param => 'Filter' ) || '';
    }

    # remember filter
    if ( $Self->{Filter} ) {

        # update session
        $Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
            SessionID => $Self->{SessionID},
            Key       => $PreferencesKey,
            Value     => $Self->{Filter},
        );

        # update preferences
        if ( !$ConfigObject->Get('DemoSystem') ) {
            $UserObject->SetPreferences(
                UserID => $Self->{UserID},
                Key    => $PreferencesKey,
                Value  => $Self->{Filter},
            );
        }
    }
    else {
        $Self->{Filter} = $Self->{$PreferencesKey} || $Self->{Config}->{Filter} || 'All';
    }

    $Self->{PrefKeyShown}   = 'UserDashboardPref' . $Self->{Name} . '-Shown';
    $Self->{PrefKeyColumns} = 'UserDashboardPref' . $Self->{Name} . '-Columns';
    $Self->{PageShown}      = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->{ $Self->{PrefKeyShown} }
        || $Self->{Config}->{Limit};
    $Self->{StartHit} = int( $ParamObject->GetParam( Param => 'StartHit' ) || 1 );

    # define filterable columns
    $Self->{ValidFilterableColumns} = {
        'Owner'          => 1,
        'Responsible'    => 1,
        'CustomerID'     => 1,
        'CustomerUserID' => 1,
        'State'          => 1,
        'Queue'          => 1,
        'Priority'       => 1,
        'Type'           => 1,
        'Lock'           => 1,
        'Service'        => 1,
        'SLA'            => 1,
    };

    # hash with all valid sortable columns (taken from TicketSearch)
    # SortBy  => 'Age',   # Owner|Responsible|CustomerID|State|TicketNumber|Queue
    # |Priority|Type|Lock|Title|Service|SLA|Changed|PendingTime|EscalationTime
    # | EscalationUpdateTime|EscalationResponseTime|EscalationSolutionTime
    $Self->{ValidSortableColumns} = {
        'Age'                    => 1,
        'Owner'                  => 1,
        'Responsible'            => 1,
        'CustomerID'             => 1,
        'State'                  => 1,
        'TicketNumber'           => 1,
        'Queue'                  => 1,
        'Priority'               => 1,
        'Type'                   => 1,
        'Lock'                   => 1,
        'Title'                  => 1,
        'Service'                => 1,
        'Changed'                => 1,
        'SLA'                    => 1,
        'PendingTime'            => 1,
        'EscalationTime'         => 1,
        'EscalationUpdateTime'   => 1,
        'EscalationResponseTime' => 1,
        'EscalationSolutionTime' => 1,
    };

    # remove CustomerID if Customer Information Center
    if ( $Self->{Action} eq 'AgentCustomerInformationCenter' ) {
        delete $Self->{ColumnFilter}->{CustomerID};
        delete $Self->{GetColumnFilter}->{CustomerID};
        delete $Self->{GetColumnFilterSelect}->{CustomerID};
        delete $Self->{ValidFilterableColumns}->{CustomerID};
        delete $Self->{ValidSortableColumns}->{CustomerID};
    }

    $Self->{UseTicketService} = $ConfigObject->Get('Ticket::Service') || 0;

    if ( $Self->{Config}->{IsProcessWidget} ) {

        # get process management configuration
        $Self->{ProcessManagementProcessID}
            = $Kernel::OM->Get('Kernel::Config')->Get('Process::DynamicFieldProcessManagementProcessID');
        $Self->{ProcessManagementActivityID}
            = $Kernel::OM->Get('Kernel::Config')->Get('Process::DynamicFieldProcessManagementActivityID');

        # get the list of processes in the system
        my $ProcessListHash = $Kernel::OM->Get('Kernel::System::ProcessManagement::Process')->ProcessList(
            ProcessState => [ 'Active', 'FadeAway', 'Inactive' ],
            Interface    => 'all',
            Silent       => 1,
        );

        # use only the process EntityIDs
        @{ $Self->{ProcessList} } = sort keys %{$ProcessListHash};
    }

    return $Self;
}

sub Preferences {
    my ( $Self, %Param ) = @_;

    # configure columns
    my @ColumnsEnabled;
    my @ColumnsAvailable;
    my @ColumnsAvailableNotEnabled;

    # check for default settings
    if (
        $Self->{Config}->{DefaultColumns}
        && IsHashRefWithData( $Self->{Config}->{DefaultColumns} )
        )
    {
        @ColumnsAvailable = grep { $Self->{Config}->{DefaultColumns}->{$_} }
            keys %{ $Self->{Config}->{DefaultColumns} };
        @ColumnsEnabled = grep { $Self->{Config}->{DefaultColumns}->{$_} eq '2' }
            sort { $Self->_DefaultColumnSort() } keys %{ $Self->{Config}->{DefaultColumns} };
    }

    # 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{ $Self->{PrefKeyColumns} } ) {

        my $ColumnsEnabled = $JSONObject->Decode(
            Data => $Kernel::OM->Get('Kernel::Output::HTML::Layout')->{ $Self->{PrefKeyColumns} },
        );

        @ColumnsEnabled = grep { $ColumnsEnabled->{Columns}->{$_} == 1 }
            keys %{ $ColumnsEnabled->{Columns} };

        if ( $ColumnsEnabled->{Order} && @{ $ColumnsEnabled->{Order} } ) {
            @ColumnsEnabled = @{ $ColumnsEnabled->{Order} };
        }
    }

    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;
        }
    }

    # remove CustomerID if Customer Information Center
    if ( $Self->{Action} eq 'AgentCustomerInformationCenter' ) {
        delete $Columns{Columns}->{CustomerID};
        @ColumnsEnabled             = grep { $_ ne 'CustomerID' } @ColumnsEnabled;
        @ColumnsAvailableNotEnabled = grep { $_ ne 'CustomerID' } @ColumnsAvailableNotEnabled;
    }

    my @Params = (
        {
            Desc  => 'Shown Tickets',
            Name  => $Self->{PrefKeyShown},
            Block => 'Option',
            Data  => {
                5  => ' 5',
                10 => '10',
                15 => '15',
                20 => '20',
                25 => '25',
            },
            SelectedID  => $Self->{PageShown},
            Translation => 0,
        },
        {
            Desc             => 'Shown Columns',
            Name             => $Self->{PrefKeyColumns},
            Block            => 'AllocationList',
            Columns          => $JSONObject->Encode( Data => \%Columns ),
            ColumnsEnabled   => $JSONObject->Encode( Data => \@ColumnsEnabled ),
            ColumnsAvailable => $JSONObject->Encode( Data => \@ColumnsAvailableNotEnabled ),
            Translation      => 1,
        },
    );

    return @Params;
}

sub Config {
    my ( $Self, %Param ) = @_;

    # check if frontend module of link is used
    if ( $Self->{Config}->{Link} && $Self->{Config}->{Link} =~ /Action=(.+?)([&;].+?|)$/ ) {
        my $Action = $1;
        if ( !$Kernel::OM->Get('Kernel::Config')->Get('Frontend::Module')->{$Action} ) {
            $Self->{Config}->{Link} = '';
        }
    }

    return (
        %{ $Self->{Config} },

        # Don't cache this globally as it contains JS that is not inside of the HTML.
        CacheTTL => undef,
        CacheKey => undef,
    );
}

sub FilterContent {
    my ( $Self, %Param ) = @_;

    return if !$Param{FilterColumn};

    my $TicketIDs;
    my $HeaderColumn = $Param{FilterColumn};
    my @OriginalViewableTickets;

    if (
        $Kernel::OM->Get('Kernel::Config')->Get('OnlyValuesOnTicket')
        || $HeaderColumn eq 'CustomerID'
        || $HeaderColumn eq 'CustomerUserID'
        )
    {
        my %SearchParams        = $Self->_SearchParamsGet(%Param);
        my %TicketSearch        = %{ $SearchParams{TicketSearch} };
        my %TicketSearchSummary = %{ $SearchParams{TicketSearchSummary} };

        # add process management search terms
        if ( $Self->{Config}->{IsProcessWidget} ) {
            $TicketSearch{ 'DynamicField_' . $Self->{ProcessManagementProcessID} } = {
                Like => $Self->{ProcessList},
            };
        }

        if (
            !$Self->{Config}->{IsProcessWidget}
            || IsArrayRefWithData( $Self->{ProcessList} )
            )
        {
            @OriginalViewableTickets = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
                %TicketSearch,
                %{ $TicketSearchSummary{ $Self->{Filter} } },
                Result => 'ARRAY',
            );
        }
    }

    if ( $HeaderColumn =~ m/^DynamicField_/ && !defined $Self->{DynamicField} ) {

        # get the dynamic fields for this screen
        $Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
            Valid      => 0,
            ObjectType => ['Ticket'],
        );
    }

    # get column values for to build the filters later
    my $ColumnValues = $Self->_GetColumnValues(
        OriginalTicketIDs => \@OriginalViewableTickets,
        HeaderColumn      => $HeaderColumn,
    );

    # make sure that even a value of 0 is passed as a Selected value, e.g. Unchecked value of a
    # check-box dynamic field.
    my $SelectedValue = defined $Self->{GetColumnFilter}->{ $HeaderColumn . $Self->{Name} }
        ? $Self->{GetColumnFilter}->{ $HeaderColumn . $Self->{Name} }
        : '';

    my $LabelColumn = $HeaderColumn;
    if ( $LabelColumn =~ m{ \A DynamicField_ }xms ) {

        my $DynamicFieldConfig;
        $LabelColumn =~ s{\A DynamicField_ }{}xms;

        DYNAMICFIELD:
        for my $DFConfig ( @{ $Self->{DynamicField} } ) {
            next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
            next DYNAMICFIELD if $DFConfig->{Name} ne $LabelColumn;

            $DynamicFieldConfig = $DFConfig;
            last DYNAMICFIELD;
        }
        if ( IsHashRefWithData($DynamicFieldConfig) ) {
            $LabelColumn = $DynamicFieldConfig->{Label};
        }
    }

    # variable to save the filter's HTML code
    my $ColumnFilterJSON = $Self->_ColumnFilterJSON(
        ColumnName    => $HeaderColumn,
        Label         => $LabelColumn,
        ColumnValues  => $ColumnValues->{$HeaderColumn},
        SelectedValue => $SelectedValue,
        DashboardName => $Self->{Name},
    );

    return $ColumnFilterJSON;

}

sub Run {
    my ( $Self, %Param ) = @_;

    my %SearchParams        = $Self->_SearchParamsGet(%Param);
    my @Columns             = @{ $SearchParams{Columns} };
    my %TicketSearch        = %{ $SearchParams{TicketSearch} };
    my %TicketSearchSummary = %{ $SearchParams{TicketSearchSummary} };

    my $CacheKey = join '-', $Self->{Name},
        $Self->{Action},
        $Self->{PageShown},
        $Self->{StartHit},
        $Self->{UserID};
    my $CacheColumns = join(
        ',',
        map {
            $_ . '=>' . $Self->{GetColumnFilterSelect}->{$_}
            }
            sort keys %{ $Self->{GetColumnFilterSelect} }
    );
    $CacheKey .= '-' . $CacheColumns if $CacheColumns;

    $CacheKey .= '-' . $Self->{SortBy}  if defined $Self->{SortBy};
    $CacheKey .= '-' . $Self->{OrderBy} if defined $Self->{OrderBy};

    # CustomerInformationCenter shows data per CustomerID
    if ( $Param{CustomerID} ) {
        $CacheKey .= '-' . $Param{CustomerID};
    }

    # get cache object
    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');

    # check cache
    my $TicketIDs = $CacheObject->Get(
        Type => 'Dashboard',
        Key  => $CacheKey . '-' . $Self->{Filter} . '-List',
    );

    # find and show ticket list
    my $CacheUsed = 1;

    # get ticket object
    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');

    if ( !$TicketIDs ) {

        # quote all CustomerIDs
        if ( $TicketSearch{CustomerID} ) {
            $TicketSearch{CustomerID} = $Kernel::OM->Get('Kernel::System::DB')->QueryStringEscape(
                QueryString => $TicketSearch{CustomerID},
            );
        }

        # add sort by parameter to the search
        if (
            !defined $TicketSearch{SortBy}
            || !$Self->{ValidSortableColumns}->{ $TicketSearch{SortBy} }
            )
        {
            if ( $Self->{SortBy} && $Self->{ValidSortableColumns}->{ $Self->{SortBy} } ) {
                $TicketSearch{SortBy} = $Self->{SortBy};
            }
            else {
                $TicketSearch{SortBy} = 'Age';
            }
        }

        # add order by parameter to the search
        if ( $Self->{OrderBy} ) {
            $TicketSearch{OrderBy} = $Self->{OrderBy};
        }

        # add process management search terms
        if ( $Self->{Config}->{IsProcessWidget} ) {
            $TicketSearch{ 'DynamicField_' . $Self->{ProcessManagementProcessID} } = {
                Like => $Self->{ProcessList},
            };
        }

        $CacheUsed = 0;
        my @TicketIDsArray;
        if (
            !$Self->{Config}->{IsProcessWidget}
            || IsArrayRefWithData( $Self->{ProcessList} )
            )
        {
            @TicketIDsArray = $TicketObject->TicketSearch(
                Result => 'ARRAY',
                %TicketSearch,
                %{ $TicketSearchSummary{ $Self->{Filter} } },
                %{ $Self->{ColumnFilter} },
                Limit => $Self->{PageShown} + $Self->{StartHit} - 1,
            );
        }
        $TicketIDs = \@TicketIDsArray;
    }

    # check cache
    my $Summary = $CacheObject->Get(
        Type => 'Dashboard',
        Key  => $CacheKey . '-Summary',
    );

    # if no cache or new list result, do count lookup
    if ( !$Summary || !$CacheUsed ) {
        TYPE:
        for my $Type ( sort keys %TicketSearchSummary ) {
            next TYPE if !$TicketSearchSummary{$Type};

            # copy original column filter
            my %ColumnFilter = %{ $Self->{ColumnFilter} || {} };

            # loop through all column filter elements
            for my $Element ( sort keys %ColumnFilter ) {

                # verify if current column filter element is already present in the ticket search
                # summary, to delete it from the column filter hash
                if ( $TicketSearchSummary{$Type}->{$Element} ) {
                    delete $ColumnFilter{$Element};
                }
            }

            # add process management search terms
            if ( $Self->{Config}->{IsProcessWidget} ) {
                $TicketSearch{ 'DynamicField_' . $Self->{ProcessManagementProcessID} } = {
                    Like => $Self->{ProcessList},
                };
            }

            $Summary->{$Type} = 0;

            if (
                !$Self->{Config}->{IsProcessWidget}
                || IsArrayRefWithData( $Self->{ProcessList} )
                )
            {
                $Summary->{$Type} = $TicketObject->TicketSearch(
                    Result => 'COUNT',
                    %TicketSearch,
                    %{ $TicketSearchSummary{$Type} },
                    %{ $Self->{ColumnFilter} },
                    %ColumnFilter,
                );
            }
        }
    }

    # set cache
    if ( !$CacheUsed && $Self->{Config}->{CacheTTLLocal} ) {
        $CacheObject->Set(
            Type  => 'Dashboard',
            Key   => $CacheKey . '-Summary',
            Value => $Summary,
            TTL   => $Self->{Config}->{CacheTTLLocal} * 60,
        );
        $CacheObject->Set(
            Type  => 'Dashboard',
            Key   => $CacheKey . '-' . $Self->{Filter} . '-List',
            Value => $TicketIDs,
            TTL   => $Self->{Config}->{CacheTTLLocal} * 60,
        );
    }

    # set css class
    $Summary->{ $Self->{Filter} . '::Selected' } = 'Selected';

    # get layout object
    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');

    # get filter ticket counts
    $LayoutObject->Block(
        Name => 'ContentLargeTicketGenericFilter',
        Data => {
            %Param,
            %{ $Self->{Config} },
            Name => $Self->{Name},
            %{$Summary},
        },
    );

    # get config object
    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');

    # show also watcher if feature is enabled
    if ( $ConfigObject->Get('Ticket::Watcher') ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericFilterWatcher',
            Data => {
                %Param,
                %{ $Self->{Config} },
                Name => $Self->{Name},
                %{$Summary},
            },
        );
    }

    # show also responsible if feature is enabled
    if ( $ConfigObject->Get('Ticket::Responsible') ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericFilterResponsible',
            Data => {
                %Param,
                %{ $Self->{Config} },
                Name => $Self->{Name},
                %{$Summary},
            },
        );
    }

    # show only myqueues if we have the filter
    if ( $TicketSearchSummary{MyQueues} ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericFilterMyQueues',
            Data => {
                %Param,
                %{ $Self->{Config} },
                Name => $Self->{Name},
                %{$Summary},
            },
        );
    }

    # show only myservices if we have the filter
    if ( $TicketSearchSummary{MyServices} ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericFilterMyServices',
            Data => {
                %Param,
                %{ $Self->{Config} },
                Name => $Self->{Name},
                %{$Summary},
            },
        );
    }

    # add page nav bar
    my $Total = $Summary->{ $Self->{Filter} } || 0;

    my %GetColumnFilter = $Self->{GetColumnFilter} ? %{ $Self->{GetColumnFilter} } : ();

    my $ColumnFilterLink = '';
    COLUMNNAME:
    for my $ColumnName ( sort keys %GetColumnFilter ) {
        next COLUMNNAME if !$ColumnName;
        next COLUMNNAME if !$GetColumnFilter{$ColumnName};
        $ColumnFilterLink
            .= ';' . $LayoutObject->Ascii2Html( Text => 'ColumnFilter' . $ColumnName )
            . '=' . $LayoutObject->Ascii2Html( Text => $GetColumnFilter{$ColumnName} )
    }

    my $LinkPage =
        'Subaction=Element;Name=' . $Self->{Name}
        . ';Filter=' . $Self->{Filter}
        . ';SortBy=' .  ( $Self->{SortBy}  || '' )
        . ';OrderBy=' . ( $Self->{OrderBy} || '' )
        . $ColumnFilterLink
        . ';';

    if ( $Param{CustomerID} ) {
        $LinkPage .= "CustomerID=$Param{CustomerID};";
    }
    my %PageNav = $LayoutObject->PageNavBar(
        StartHit       => $Self->{StartHit},
        PageShown      => $Self->{PageShown},
        AllHits        => $Total || 1,
        Action         => 'Action=' . $LayoutObject->{Action},
        Link           => $LinkPage,
        AJAXReplace    => 'Dashboard' . $Self->{Name},
        IDPrefix       => 'Dashboard' . $Self->{Name},
        KeepScriptTags => $Param{AJAX},
    );
    $LayoutObject->Block(
        Name => 'ContentLargeTicketGenericFilterNavBar',
        Data => {
            %{ $Self->{Config} },
            Name => $Self->{Name},
            %PageNav,
        },
    );

    # show table header
    $LayoutObject->Block(
        Name => 'ContentLargeTicketGenericHeader',
        Data => {},
    );

    # define which meta items will be shown
    my @MetaItems = $LayoutObject->TicketMetaItemsCount();

    # show non-labeled table headers
    my $CSS = '';
    my $OrderBy;
    for my $Item (@MetaItems) {
        $CSS = '';
        my $Title = $Item;
        if ( $Self->{SortBy} && ( $Self->{SortBy} eq $Item ) ) {
            if ( $Self->{OrderBy} && ( $Self->{OrderBy} eq 'Up' ) ) {
                $OrderBy = 'Down';
                $CSS .= ' SortDescendingLarge';
            }
            else {
                $OrderBy = 'Up';
                $CSS .= ' SortAscendingLarge';
            }

            # set title description
            my $TitleDesc = $OrderBy eq 'Down' ? 'sorted descending' : 'sorted ascending';
            $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
            $Title .= ', ' . $TitleDesc;
        }

        # add surrounding container
        $LayoutObject->Block(
            Name => 'GeneralOverviewHeader',
        );
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericHeaderMeta',
            Data => {
                CSS => $CSS,
            },
        );

        if ( $Item eq 'New Article' ) {

            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericHeaderMetaEmpty',
                Data => {
                    HeaderColumnName => $Item,
                },
            );
        }
        else {
            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericHeaderMetaLink',
                Data => {
                    %Param,
                    Name             => $Self->{Name},
                    OrderBy          => $OrderBy || 'Up',
                    HeaderColumnName => $Item,
                    Title            => $Title,
                },
            );
        }
    }

    # show all needed headers
    HEADERCOLUMN:
    for my $HeaderColumn (@Columns) {

        # skip CustomerID if Customer Information Center
        if (
            $Self->{Action} eq 'AgentCustomerInformationCenter'
            && $HeaderColumn eq 'CustomerID'
            )
        {
            next HEADERCOLUMN;
        }

        if ( $HeaderColumn !~ m{\A DynamicField_}xms ) {

            $CSS = '';
            my $Title = $HeaderColumn;

            if ( $Self->{SortBy} && ( $Self->{SortBy} eq $HeaderColumn ) ) {
                if ( $Self->{OrderBy} && ( $Self->{OrderBy} eq 'Up' ) ) {
                    $OrderBy = 'Down';
                    $CSS .= ' SortDescendingLarge';
                }
                else {
                    $OrderBy = 'Up';
                    $CSS .= ' SortAscendingLarge';
                }

                # add title description
                my $TitleDesc = $OrderBy eq 'Down' ? 'sorted descending' : 'sorted ascending';
                $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
                $Title .= ', ' . $TitleDesc;
            }

            # translate the column name to write it in the current language
            my $TranslatedWord;
            if ( $HeaderColumn eq 'EscalationTime' ) {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Service Time');
            }
            elsif ( $HeaderColumn eq 'EscalationResponseTime' ) {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('First Response Time');
            }
            elsif ( $HeaderColumn eq 'EscalationSolutionTime' ) {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Solution Time');
            }
            elsif ( $HeaderColumn eq 'EscalationUpdateTime' ) {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Update Time');
            }
            elsif ( $HeaderColumn eq 'PendingTime' ) {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Pending till');
            }
            else {
                $TranslatedWord = $LayoutObject->{LanguageObject}->Translate($HeaderColumn);
            }

            # add surrounding container
            $LayoutObject->Block(
                Name => 'GeneralOverviewHeader',
            );
            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericHeaderTicketHeader',
                Data => {},
            );

            if ( $HeaderColumn eq 'TicketNumber' ) {
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderTicketNumberColumn',
                    Data => {
                        %Param,
                        CSS => $CSS || '',
                        Name    => $Self->{Name},
                        OrderBy => $OrderBy || 'Up',
                        Filter  => $Self->{Filter},
                        Title   => $Title,
                    },
                );
                next HEADERCOLUMN;
            }

            my $FilterTitle     = $HeaderColumn;
            my $FilterTitleDesc = 'filter not active';
            if ( $Self->{GetColumnFilterSelect} && $Self->{GetColumnFilterSelect}->{$HeaderColumn} )
            {
                $CSS .= ' FilterActive';
                $FilterTitleDesc = 'filter active';
            }
            $FilterTitleDesc = $LayoutObject->{LanguageObject}->Translate($FilterTitleDesc);
            $FilterTitle .= ', ' . $FilterTitleDesc;

            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericHeaderColumn',
                Data => {
                    HeaderColumnName     => $HeaderColumn   || '',
                    HeaderNameTranslated => $TranslatedWord || $HeaderColumn,
                    CSS                  => $CSS            || '',
                },
            );

            # verify if column is filterable and sortable
            if (
                $Self->{ValidSortableColumns}->{$HeaderColumn}
                && $Self->{ValidFilterableColumns}->{$HeaderColumn}
                )
            {

                my $Css;
                if (
                    $HeaderColumn eq 'CustomerID'
                    || $HeaderColumn eq 'Responsible'
                    || $HeaderColumn eq 'Owner'
                    )
                {
                    $Css = 'Hidden';
                }

                # variable to save the filter's html code
                my $ColumnFilterHTML = $Self->_InitialColumnFilter(
                    ColumnName => $HeaderColumn,
                    Css        => $Css,
                );

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnFilterLink',
                    Data => {
                        %Param,
                        HeaderColumnName     => $HeaderColumn,
                        CSS                  => $CSS,
                        HeaderNameTranslated => $TranslatedWord || $HeaderColumn,
                        ColumnFilterStrg     => $ColumnFilterHTML,
                        OrderBy              => $OrderBy || 'Up',
                        SortBy               => $Self->{SortBy} || 'Age',
                        Name                 => $Self->{Name},
                        Title                => $Title,
                        FilterTitle          => $FilterTitle,
                    },
                );

                if ( $HeaderColumn eq 'CustomerID' ) {

                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericHeaderColumnFilterLinkCustomerIDSearch',
                        Data => {
                            minQueryLength      => 2,
                            queryDelay          => 100,
                            maxResultsDisplayed => 20,
                        },
                    );
                }
                elsif ( $HeaderColumn eq 'Responsible' || $HeaderColumn eq 'Owner' ) {

                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericHeaderColumnFilterLinkUserSearch',
                        Data => {
                            minQueryLength      => 2,
                            queryDelay          => 100,
                            maxResultsDisplayed => 20,
                        },
                    );
                }
            }

            # verify if column is just filterable
            elsif ( $Self->{ValidFilterableColumns}->{$HeaderColumn} ) {

                my $Css;
                if ( $HeaderColumn eq 'CustomerUserID' ) {
                    $Css = 'Hidden';
                }

                # variable to save the filter's html code
                my $ColumnFilterHTML = $Self->_InitialColumnFilter(
                    ColumnName => $HeaderColumn,
                    Css        => $Css,
                );

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnFilter',
                    Data => {
                        %Param,
                        HeaderColumnName     => $HeaderColumn,
                        CSS                  => $CSS,
                        HeaderNameTranslated => $TranslatedWord || $HeaderColumn,
                        ColumnFilterStrg     => $ColumnFilterHTML,
                        Name                 => $Self->{Name},
                        Title                => $Title,
                        FilterTitle          => $FilterTitle,
                    },
                );

                if ( $HeaderColumn eq 'CustomerUserID' ) {

                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericHeaderColumnFilterLinkCustomerUserSearch',
                        Data => {
                            minQueryLength      => 2,
                            queryDelay          => 100,
                            maxResultsDisplayed => 20,
                        },
                    );
                }
            }

            # verify if column is just sortable
            elsif ( $Self->{ValidSortableColumns}->{$HeaderColumn} ) {
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnLink',
                    Data => {
                        %Param,
                        HeaderColumnName     => $HeaderColumn,
                        CSS                  => $CSS,
                        HeaderNameTranslated => $TranslatedWord || $HeaderColumn,
                        OrderBy              => $OrderBy || 'Up',
                        SortBy               => $Self->{SortBy} || $HeaderColumn,
                        Name                 => $Self->{Name},
                        Title                => $Title,
                    },
                );
            }
            else {
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnEmpty',
                    Data => {
                        %Param,
                        HeaderNameTranslated => $TranslatedWord || $HeaderColumn,
                        HeaderColumnName     => $HeaderColumn,
                        CSS                  => $CSS,
                        Title                => $Title,
                    },
                );
            }
        }

        # Dynamic fields
        else {
            my $DynamicFieldConfig;
            my $DFColumn = $HeaderColumn;
            $DFColumn =~ s/DynamicField_//g;
            DYNAMICFIELD:
            for my $DFConfig ( @{ $Self->{DynamicField} } ) {
                next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
                next DYNAMICFIELD if $DFConfig->{Name} ne $DFColumn;

                $DynamicFieldConfig = $DFConfig;
                last DYNAMICFIELD;
            }
            next HEADERCOLUMN if !IsHashRefWithData($DynamicFieldConfig);

            my $Label = $DynamicFieldConfig->{Label};

            my $TranslatedLabel = $LayoutObject->{LanguageObject}->Translate($Label);

            my $DynamicFieldName = 'DynamicField_' . $DynamicFieldConfig->{Name};

            my $CSS             = '';
            my $FilterTitle     = $Label;
            my $FilterTitleDesc = 'filter not active';
            if (
                $Self->{GetColumnFilterSelect}
                && defined $Self->{GetColumnFilterSelect}->{$DynamicFieldName}
                )
            {
                $CSS .= 'FilterActive ';
                $FilterTitleDesc = 'filter active';
            }
            $FilterTitleDesc = $LayoutObject->{LanguageObject}->Translate($FilterTitleDesc);
            $FilterTitle .= ', ' . $FilterTitleDesc;

            # get field sortable condition
            my $IsSortable = $Kernel::OM->Get('Kernel::System::DynamicField::Backend')->HasBehavior(
                DynamicFieldConfig => $DynamicFieldConfig,
                Behavior           => 'IsSortable',
            );

            # set title
            my $Title = $Label;

            # add surrounding container
            $LayoutObject->Block(
                Name => 'GeneralOverviewHeader',
            );
            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericHeaderTicketHeader',
                Data => {},
            );

            if ($IsSortable) {
                my $OrderBy;
                if (
                    $Self->{SortBy}
                    && ( $Self->{SortBy} eq ( 'DynamicField_' . $DynamicFieldConfig->{Name} ) )
                    )
                {
                    if ( $Self->{OrderBy} && ( $Self->{OrderBy} eq 'Up' ) ) {
                        $OrderBy = 'Down';
                        $CSS .= ' SortDescendingLarge';
                    }
                    else {
                        $OrderBy = 'Up';
                        $CSS .= ' SortAscendingLarge';
                    }

                    # add title description
                    my $TitleDesc = $OrderBy eq 'Down' ? 'sorted descending' : 'sorted ascending';
                    $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
                    $Title .= ', ' . $TitleDesc;
                }

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumn',
                    Data => {
                        HeaderColumnName => $DynamicFieldName || '',
                        CSS => $CSS || '',
                    },
                );

                # check if the dynamic field is sortable and filterable (sortable check was made before)
                if ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {

                    # variable to save the filter's HTML code
                    my $ColumnFilterHTML = $Self->_InitialColumnFilter(
                        ColumnName => $DynamicFieldName,
                        Label      => $Label,
                    );

                    # output sortable and filterable dynamic field
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericHeaderColumnFilterLink',
                        Data => {
                            %Param,
                            HeaderColumnName     => $DynamicFieldName,
                            CSS                  => $CSS,
                            HeaderNameTranslated => $TranslatedLabel || $DynamicFieldName,
                            ColumnFilterStrg     => $ColumnFilterHTML,
                            OrderBy              => $OrderBy || 'Up',
                            SortBy               => $Self->{SortBy} || 'Age',
                            Name                 => $Self->{Name},
                            Title                => $Title,
                            FilterTitle          => $FilterTitle,
                        },
                    );
                }

                # otherwise the dynamic field is only sortable (sortable check was made before)
                else {

                    # output sortable dynamic field
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericHeaderColumnLink',
                        Data => {
                            %Param,
                            HeaderColumnName     => $DynamicFieldName,
                            CSS                  => $CSS,
                            HeaderNameTranslated => $TranslatedLabel || $DynamicFieldName,
                            OrderBy              => $OrderBy || 'Up',
                            SortBy               => $Self->{SortBy} || $DynamicFieldName,
                            Name                 => $Self->{Name},
                            Title                => $Title,
                            FilterTitle          => $FilterTitle,
                        },
                    );
                }
            }

            # if the dynamic field was not sortable (check was made and fail before)
            # it might be filterable
            elsif ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumn',
                    Data => {
                        HeaderColumnName => $DynamicFieldName || '',
                        CSS              => $CSS              || '',
                        Title            => $Title,
                    },
                );

                # variable to save the filter's HTML code
                my $ColumnFilterHTML = $Self->_InitialColumnFilter(
                    ColumnName => $DynamicFieldName,
                    Label      => $Label,
                );

                # output filtrable (not sortable) dynamic field
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnFilter',
                    Data => {
                        %Param,
                        HeaderColumnName     => $DynamicFieldName,
                        CSS                  => $CSS,
                        HeaderNameTranslated => $TranslatedLabel || $DynamicFieldName,
                        ColumnFilterStrg     => $ColumnFilterHTML,
                        Name                 => $Self->{Name},
                        Title                => $Title,
                        FilterTitle          => $FilterTitle,
                    },
                );
            }

            # otherwise the field is not filterable and not sortable
            else {

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumn',
                    Data => {
                        HeaderColumnName => $DynamicFieldName || '',
                        CSS => $CSS || '',
                    },
                );

                # output plain dynamic field header (not filterable, not sortable)
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericHeaderColumnEmpty',
                    Data => {
                        %Param,
                        HeaderNameTranslated => $TranslatedLabel || $DynamicFieldName,
                        HeaderColumnName     => $DynamicFieldName,
                        CSS                  => $CSS,
                        Title                => $Title,
                    },
                );
            }
        }
    }

    # show tickets
    my $Count = 0;
    TICKETID:
    for my $TicketID ( @{$TicketIDs} ) {
        $Count++;
        next TICKETID if $Count < $Self->{StartHit};
        my %Ticket = $TicketObject->TicketGet(
            TicketID      => $TicketID,
            UserID        => $Self->{UserID},
            DynamicFields => 0,
            Silent        => 1
        );

        next TICKETID if !%Ticket;

        # set a default title if ticket has no title
        if ( !$Ticket{Title} ) {
            $Ticket{Title} = $LayoutObject->{LanguageObject}->Translate(
                'This ticket has no title or subject'
            );
        }

        my $WholeTitle = $Ticket{Title} || '';
        $Ticket{Title} = $TicketObject->TicketSubjectClean(
            TicketNumber => $Ticket{TicketNumber},
            Subject      => $Ticket{Title},
        );

        # create human age
        if ( $Self->{Config}->{Time} ne 'Age' ) {
            $Ticket{Time} = $LayoutObject->CustomerAgeInHours(
                Age   => $Ticket{ $Self->{Config}->{Time} },
                Space => ' ',
            );
        }
        else {
            $Ticket{Time} = $LayoutObject->CustomerAge(
                Age   => $Ticket{ $Self->{Config}->{Time} },
                Space => ' ',
            );
        }

        # show ticket
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericRow',
            Data => \%Ticket,
        );

        # show ticket flags
        my @TicketMetaItems = $LayoutObject->TicketMetaItems(
            Ticket => \%Ticket,
        );
        for my $Item (@TicketMetaItems) {

            $LayoutObject->Block(
                Name => 'GeneralOverviewRow',
            );
            $LayoutObject->Block(
                Name => 'ContentLargeTicketGenericRowMeta',
                Data => {},
            );
            if ($Item) {
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericRowMetaImage',
                    Data => $Item,
                );
            }
        }

        # save column content
        my $DataValue;

        # get needed objects
        my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
        my $UserObject    = $Kernel::OM->Get('Kernel::System::User');

        # show all needed columns
        COLUMN:
        for my $Column (@Columns) {

            # skip CustomerID if Customer Information Center
            if (
                $Self->{Action} eq 'AgentCustomerInformationCenter'
                && $Column eq 'CustomerID'
                )
            {
                next COLUMN;
            }

            if ( $Column !~ m{\A DynamicField_}xms ) {

                $LayoutObject->Block(
                    Name => 'GeneralOverviewRow',
                );
                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericTicketColumn',
                    Data => {},
                );

                my $BlockType = '';
                my $CSSClass  = '';

                if ( $Column eq 'TicketNumber' ) {
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericTicketNumber',
                        Data => {
                            %Ticket,
                            Title => $Ticket{Title},
                        },
                    );
                    next COLUMN;
                }
                elsif ( $Column eq 'EscalationTime' ) {
                    my %EscalationData;
                    $EscalationData{EscalationTime}            = $Ticket{EscalationTime};
                    $EscalationData{EscalationDestinationDate} = $Ticket{EscalationDestinationDate};

                    $EscalationData{EscalationTimeHuman} = $LayoutObject->CustomerAgeInHours(
                        Age   => $EscalationData{EscalationTime},
                        Space => ' ',
                    );
                    $EscalationData{EscalationTimeWorkingTime} = $LayoutObject->CustomerAgeInHours(
                        Age   => $EscalationData{EscalationTimeWorkingTime},
                        Space => ' ',
                    );
                    if ( defined $Ticket{EscalationTime} && $Ticket{EscalationTime} < 60 * 60 * 1 )
                    {
                        $EscalationData{EscalationClass} = 'Warning';
                    }
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericEscalationTime',
                        Data => {%EscalationData},
                    );
                    next COLUMN;

                    $DataValue = $LayoutObject->CustomerAge(
                        Age   => $Ticket{'EscalationTime'},
                        Space => ' '
                    );
                }
                elsif ( $Column eq 'Age' ) {
                    $DataValue = $LayoutObject->CustomerAge(
                        Age   => $Ticket{Age},
                        Space => ' ',
                    );
                }
                elsif ( $Column eq 'EscalationSolutionTime' ) {
                    $BlockType = 'Escalation';
                    $DataValue = $LayoutObject->CustomerAgeInHours(
                        Age => $Ticket{SolutionTime} || 0,
                        Space => ' ',
                    );
                    if ( defined $Ticket{SolutionTime} && $Ticket{SolutionTime} < 60 * 60 * 1 ) {
                        $CSSClass = 'Warning';
                    }
                }
                elsif ( $Column eq 'EscalationResponseTime' ) {
                    $BlockType = 'Escalation';
                    $DataValue = $LayoutObject->CustomerAgeInHours(
                        Age => $Ticket{FirstResponseTime} || 0,
                        Space => ' ',
                    );
                    if (
                        defined $Ticket{FirstResponseTime}
                        && $Ticket{FirstResponseTime} < 60 * 60 * 1
                        )
                    {
                        $CSSClass = 'Warning';
                    }
                }
                elsif ( $Column eq 'EscalationUpdateTime' ) {
                    $BlockType = 'Escalation';
                    $DataValue = $LayoutObject->CustomerAgeInHours(
                        Age => $Ticket{UpdateTime} || 0,
                        Space => ' ',
                    );
                    if ( defined $Ticket{UpdateTime} && $Ticket{UpdateTime} < 60 * 60 * 1 ) {
                        $CSSClass = 'Warning';
                    }
                }
                elsif ( $Column eq 'PendingTime' ) {
                    $BlockType = 'Escalation';
                    $DataValue = $LayoutObject->CustomerAge(
                        Age   => $Ticket{'UntilTime'},
                        Space => ' '
                    );
                    if ( defined $Ticket{UntilTime} && $Ticket{UntilTime} < -1 ) {
                        $CSSClass = 'Warning';
                    }
                }
                elsif ( $Column eq 'Owner' ) {

                    # get owner info
                    my %OwnerInfo = $UserObject->GetUserData(
                        UserID => $Ticket{OwnerID},
                    );
                    $DataValue = $OwnerInfo{'UserFirstname'} . ' ' . $OwnerInfo{'UserLastname'};
                }
                elsif ( $Column eq 'Responsible' ) {

                    # get responsible info
                    my %ResponsibleInfo = $UserObject->GetUserData(
                        UserID => $Ticket{ResponsibleID},
                    );
                    $DataValue = $ResponsibleInfo{'UserFirstname'} . ' '
                        . $ResponsibleInfo{'UserLastname'};
                }
                elsif (
                    $Column eq 'State'
                    || $Column eq 'Lock'
                    || $Column eq 'Priority'
                    )
                {
                    $BlockType = 'Translatable';
                    $DataValue = $Ticket{$Column};
                }
                elsif ( $Column eq 'Created' || $Column eq 'Changed' ) {
                    $BlockType = 'Time';
                    $DataValue = $Ticket{$Column};
                }
                elsif ( $Column eq 'CustomerName' ) {

                    # get customer name
                    my $CustomerName;
                    if ( $Ticket{CustomerUserID} ) {
                        $CustomerName = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerName(
                            UserLogin => $Ticket{CustomerUserID},
                        );
                    }
                    $DataValue = $CustomerName;
                }
                else {
                    $DataValue = $Ticket{$Column};
                }

                if ( $Column eq 'Title' ) {
                    $LayoutObject->Block(
                        Name => "ContentLargeTicketTitle",
                        Data => {
                            Title => "$DataValue " || '',
                            WholeTitle => $WholeTitle,
                            Class      => $CSSClass || '',
                        },
                    );

                }
                else {
                    $LayoutObject->Block(
                        Name => "ContentLargeTicketGenericColumn$BlockType",
                        Data => {
                            GenericValue => $DataValue || '',
                            Class        => $CSSClass  || '',
                        },
                    );
                }

            }

            # Dynamic fields
            else {
                my $DynamicFieldConfig;
                my $DFColumn = $Column;
                $DFColumn =~ s/DynamicField_//g;
                DYNAMICFIELD:
                for my $DFConfig ( @{ $Self->{DynamicField} } ) {
                    next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
                    next DYNAMICFIELD if $DFConfig->{Name} ne $DFColumn;

                    $DynamicFieldConfig = $DFConfig;
                    last DYNAMICFIELD;
                }
                next COLUMN if !IsHashRefWithData($DynamicFieldConfig);

                # get field value
                my $Value = $BackendObject->ValueGet(
                    DynamicFieldConfig => $DynamicFieldConfig,
                    ObjectID           => $TicketID,
                );

                my $ValueStrg = $BackendObject->DisplayValueRender(
                    DynamicFieldConfig => $DynamicFieldConfig,
                    Value              => $Value,
                    ValueMaxChars      => 20,
                    LayoutObject       => $LayoutObject,
                );

                $LayoutObject->Block(
                    Name => 'ContentLargeTicketGenericDynamicField',
                    Data => {
                        Value => $ValueStrg->{Value},
                        Title => $ValueStrg->{Title},
                    },
                );

                if ( $ValueStrg->{Link} ) {
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericDynamicFieldLink',
                        Data => {
                            Value                       => $ValueStrg->{Value},
                            Title                       => $ValueStrg->{Title},
                            Link                        => $ValueStrg->{Link},
                            $DynamicFieldConfig->{Name} => $ValueStrg->{Title},
                        },
                    );
                }
                else {
                    $LayoutObject->Block(
                        Name => 'ContentLargeTicketGenericDynamicFieldPlain',
                        Data => {
                            Value => $ValueStrg->{Value},
                            Title => $ValueStrg->{Title},
                        },
                    );
                }
            }

        }

    }

    # show "none" if no ticket is available
    if ( !$TicketIDs || !@{$TicketIDs} ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericNone',
            Data => {},
        );
    }

    # check for refresh time
    my $Refresh = '';
    if ( $Self->{UserRefreshTime} ) {
        $Refresh = 60 * $Self->{UserRefreshTime};
        my $NameHTML = $Self->{Name};
        $NameHTML =~ s{-}{_}xmsg;
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericRefresh',
            Data => {
                %{ $Self->{Config} },
                Name        => $Self->{Name},
                NameHTML    => $NameHTML,
                RefreshTime => $Refresh,
                CustomerID  => $Param{CustomerID},
                %{$Summary},
            },
        );
    }

    # check for active filters and add a 'remove filters' button to the widget header
    if ( $Self->{GetColumnFilterSelect} && IsHashRefWithData( $Self->{GetColumnFilterSelect} ) ) {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericRemoveFilters',
            Data => {
                Name       => $Self->{Name},
                CustomerID => $Param{CustomerID},
            },
        );
    }
    else {
        $LayoutObject->Block(
            Name => 'ContentLargeTicketGenericRemoveFiltersRemove',
            Data => {
                Name => $Self->{Name},
            },
        );
    }

    my $Content = $LayoutObject->Output(
        TemplateFile => 'AgentDashboardTicketGenericProjekt',
        Data         => {
            %{ $Self->{Config} },
            Name => $Self->{Name},
            %{$Summary},
            FilterValue => $Self->{Filter},
            CustomerID  => $Self->{CustomerID},
        },
        KeepScriptTags => $Param{AJAX},
    );

    return $Content;
}

sub _InitialColumnFilter {
    my ( $Self, %Param ) = @_;

    return if !$Param{ColumnName};
    return if !$Self->{ValidFilterableColumns}->{ $Param{ColumnName} };

    # get layout object
    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');

    my $Label = $Param{Label} || $Param{ColumnName};
    $Label = $LayoutObject->{LanguageObject}->Translate($Label);

    # set fixed values
    my $Data = [
        {
            Key   => '',
            Value => uc $Label,
        },
    ];

    # define if column filter values should be translatable
    my $TranslationOption = 0;

    if (
        $Param{ColumnName} eq 'State'
        || $Param{ColumnName} eq 'Lock'
        || $Param{ColumnName} eq 'Priority'
        )
    {
        $TranslationOption = 1;
    }

    my $Class = 'ColumnFilter';
    if ( $Param{Css} ) {
        $Class .= ' ' . $Param{Css};
    }

    # build select HTML
    my $ColumnFilterHTML = $LayoutObject->BuildSelection(
        Name        => 'ColumnFilter' . $Param{ColumnName} . $Self->{Name},
        Data        => $Data,
        Class       => $Class,
        Translation => $TranslationOption,
        SelectedID  => '',
    );
    return $ColumnFilterHTML;
}

sub _GetColumnValues {
    my ( $Self, %Param ) = @_;

    return if !IsStringWithData( $Param{HeaderColumn} );

    my $HeaderColumn = $Param{HeaderColumn};
    my %ColumnFilterValues;
    my $TicketIDs;

    if ( IsArrayRefWithData( $Param{OriginalTicketIDs} ) ) {
        $TicketIDs = $Param{OriginalTicketIDs};
    }

    if ( $HeaderColumn !~ m/^DynamicField_/ ) {
        my $FunctionName = $HeaderColumn . 'FilterValuesGet';
        if ( $HeaderColumn eq 'CustomerID' ) {
            $FunctionName = 'CustomerFilterValuesGet';
        }

        $ColumnFilterValues{$HeaderColumn} = $Kernel::OM->Get('Kernel::System::Ticket::ColumnFilter')->$FunctionName(
            TicketIDs    => $TicketIDs,
            HeaderColumn => $HeaderColumn,
            UserID       => $Self->{UserID},
        );
    }
    else {
        DYNAMICFIELD:
        for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {

            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

            my $FieldName = 'DynamicField_' . $DynamicFieldConfig->{Name};

            next DYNAMICFIELD if $FieldName ne $HeaderColumn;

            # get dynamic field backend object
            my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');

            my $IsFiltrable = $BackendObject->HasBehavior(
                DynamicFieldConfig => $DynamicFieldConfig,
                Behavior           => 'IsFiltrable',
            );

            next DYNAMICFIELD if !$IsFiltrable;

            $Self->{ValidFilterableColumns}->{$HeaderColumn} = $IsFiltrable;
            if ( IsArrayRefWithData($TicketIDs) ) {

                # get the historical values for the field
                $ColumnFilterValues{$HeaderColumn} = $BackendObject->ColumnFilterValuesGet(
                    DynamicFieldConfig => $DynamicFieldConfig,
                    LayoutObject       => $Kernel::OM->Get('Kernel::Output::HTML::Layout'),
                    TicketIDs          => $TicketIDs,
                );
            }
            else {

                # get PossibleValues
                $ColumnFilterValues{$HeaderColumn} = $BackendObject->PossibleValuesGet(
                    DynamicFieldConfig => $DynamicFieldConfig,
                );
            }
            last DYNAMICFIELD;
        }
    }

    return \%ColumnFilterValues;
}

=over

=item _ColumnFilterJSON()

    creates a JSON select filter for column header

    my $ColumnFilterJSON = $TicketOverviewSmallObject->_ColumnFilterJSON(
        ColumnName => 'Queue',
        Label      => 'Queue',
        ColumnValues => {
            1 => 'PostMaster',
            2 => 'Junk',
        },
        SelectedValue '1',
    );

=cut

sub _ColumnFilterJSON {
    my ( $Self, %Param ) = @_;

    return if !$Param{ColumnName};
    return if !$Self->{ValidFilterableColumns}->{ $Param{ColumnName} };

    # get layout object
    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');

    my $Label = $Param{Label};
    $Label =~ s{ \A DynamicField_ }{}gxms;
    $Label = $LayoutObject->{LanguageObject}->Translate($Label);

    # set fixed values
    my $Data = [
        {
            Key   => 'DeleteFilter',
            Value => uc $Label,
        },
        {
            Key      => '-',
            Value    => '-',
            Disabled => 1,
        },
    ];

    if ( $Param{ColumnValues} && ref $Param{ColumnValues} eq 'HASH' ) {

        my %Values = %{ $Param{ColumnValues} };

        # set possible values
        for my $ValueKey ( sort { lc $Values{$a} cmp lc $Values{$b} } keys %Values ) {
            push @{$Data}, {
                Key   => $ValueKey,
                Value => $Values{$ValueKey}
            };
        }
    }

    # define if column filter values should be translatable
    my $TranslationOption = 0;

    if (
        $Param{ColumnName} eq 'State'
        || $Param{ColumnName} eq 'Lock'
        || $Param{ColumnName} eq 'Priority'
        )
    {
        $TranslationOption = 1;
    }

    # build select HTML
    my $JSON = $LayoutObject->BuildSelectionJSON(
        [
            {
                Name         => 'ColumnFilter' . $Param{ColumnName} . $Param{DashboardName},
                Data         => $Data,
                Class        => 'ColumnFilter',
                Sort         => 'AlphanumericKey',
                TreeView     => 1,
                SelectedID   => $Param{SelectedValue},
                Translation  => $TranslationOption,
                AutoComplete => 'off',
            },
        ],
    );

    return $JSON;
}

sub _SearchParamsGet {
    my ( $Self, %Param ) = @_;

    # get all search base attributes
    my %TicketSearch;
    my %DynamicFieldsParameters;
    my @Params = split /;/, $Self->{Config}->{Attributes};

    # read user preferences and config to get columns that
    # should be shown in the dashboard widget (the preferences
    # have precedence)
    my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences(
        UserID => $Self->{UserID},
    );

    # get column names from Preferences
    my $PreferencesColumn = $Kernel::OM->Get('Kernel::System::JSON')->Decode(
        Data => $Preferences{ $Self->{PrefKeyColumns} },
    );

    # check for default settings
    my @Columns;
    if (
        $Self->{Config}->{DefaultColumns}
        && IsHashRefWithData( $Self->{Config}->{DefaultColumns} )
        )
    {
        @Columns = grep { $Self->{Config}->{DefaultColumns}->{$_} eq '2' }
            sort { $Self->_DefaultColumnSort() } keys %{ $Self->{Config}->{DefaultColumns} };
    }
    if ($PreferencesColumn) {
        if ( $PreferencesColumn->{Columns} && %{ $PreferencesColumn->{Columns} } ) {
            @Columns = grep {
                defined $PreferencesColumn->{Columns}->{$_}
                    && $PreferencesColumn->{Columns}->{$_} eq '1'
            } sort { $Self->_DefaultColumnSort() } keys %{ $Self->{Config}->{DefaultColumns} };
        }
        if ( $PreferencesColumn->{Order} && @{ $PreferencesColumn->{Order} } ) {
            @Columns = @{ $PreferencesColumn->{Order} };
        }
    }

    # always set TicketNumber
    if ( !grep { $_ eq 'TicketNumber' } @Columns ) {
        unshift @Columns, 'TicketNumber';
    }

    # also always set ProcessID and ActivityID (for process widgets)
    if ( $Self->{Config}->{IsProcessWidget} ) {

        my @AlwaysColumns = (
            'DynamicField_' . $Self->{ProcessManagementProcessID},
            'DynamicField_' . $Self->{ProcessManagementActivityID},
        );
        my $Resort;
        for my $AlwaysColumn (@AlwaysColumns) {
            if ( !grep { $_ eq $AlwaysColumn } @Columns ) {
                push @Columns, $AlwaysColumn;
                $Resort = 1;
            }
        }
        if ($Resort) {
            @Columns = sort { $Self->_DefaultColumnSort() } @Columns;
        }
    }

    {

        # loop through all the dynamic fields to get the ones that should be shown
        DYNAMICFIELDNAME:
        for my $DynamicFieldName (@Columns) {

            next DYNAMICFIELDNAME if $DynamicFieldName !~ m{ DynamicField_ }xms;

            # remove dynamic field prefix
            my $FieldName = $DynamicFieldName;
            $FieldName =~ s/DynamicField_//gi;
            $Self->{DynamicFieldFilter}->{$FieldName} = 1;
        }
    }

    # get the dynamic fields for this screen
    $Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
        Valid       => 1,
        ObjectType  => ['Ticket'],
        FieldFilter => $Self->{DynamicFieldFilter} || {},
    );

    # get dynamic field backend object
    my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');

    # get filterable Dynamic fields
    # cycle trough the activated Dynamic Fields for this screen
    DYNAMICFIELD:
    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

        my $IsFiltrable = $BackendObject->HasBehavior(
            DynamicFieldConfig => $DynamicFieldConfig,
            Behavior           => 'IsFiltrable',
        );

        # if the dynamic field is filterable add it to the ValidFilterableColumns hash
        if ($IsFiltrable) {
            $Self->{ValidFilterableColumns}->{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = 1;
        }
    }

    # get sortable Dynamic fields
    # cycle trough the activated Dynamic Fields for this screen
    DYNAMICFIELD:
    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

        my $IsSortable = $BackendObject->HasBehavior(
            DynamicFieldConfig => $DynamicFieldConfig,
            Behavior           => 'IsSortable',
        );

        # if the dynamic field is sortable add it to the ValidSortableColumns hash
        if ($IsSortable) {
            $Self->{ValidSortableColumns}->{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = 1;
        }
    }

    # get queue object
    my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');

    STRING:
    for my $String (@Params) {
        next STRING if !$String;
        my ( $Key, $Value ) = split /=/, $String;

        if ( $Key eq 'CustomerID' ) {
            $Key = "CustomerIDRaw";
        }

        # push ARRAYREF attributes directly in an ARRAYREF
        if (
            $Key
            =~ /^(StateType|StateTypeIDs|Queues|QueueIDs|Types|TypeIDs|States|StateIDs|Priorities|PriorityIDs|Services|ServiceIDs|SLAs|SLAIDs|Locks|LockIDs|OwnerIDs|ResponsibleIDs|WatchUserIDs|ArchiveFlags)$/
            )
        {
            push @{ $TicketSearch{$Key} }, $Value;
        }

        # check if parameter is a dynamic field and capture dynamic field name (with DynamicField_)
        # in $1 and the Operator in $2
        # possible Dynamic Fields options include:
        #   DynamicField_NameX_Equals=123;
        #   DynamicField_NameX_Like=value*;
        #   DynamicField_NameX_GreaterThan=2001-01-01 01:01:01;
        #   DynamicField_NameX_GreaterThanEquals=2001-01-01 01:01:01;
        #   DynamicField_NameX_SmallerThan=2002-02-02 02:02:02;
        #   DynamicField_NameX_SmallerThanEquals=2002-02-02 02:02:02;
        elsif ( $Key =~ m{\A (DynamicField_.+?) _ (.+?) \z}sxm ) {

            # prevent adding ProcessManagement search parameters (for ProcessWidget)
            if ( $Self->{Config}->{IsProcessWidget} ) {
                next STRING if $2 eq $Self->{ProcessManagementProcessID};
                next STRING if $2 eq $Self->{ProcessManagementActivityID};
            }

            push @{ $DynamicFieldsParameters{$1}->{$2} }, $Value;
        }

        elsif ( !defined $TicketSearch{$Key} ) {

            # change sort by, if needed
            if (
                $Key eq 'SortBy'
                && $Self->{SortBy}
                && $Self->{ValidSortableColumns}->{ $Self->{SortBy} }
                )
            {
                $Value = $Self->{SortBy};
            }
            elsif ( $Key eq 'SortBy' && !$Self->{ValidSortableColumns}->{$Value} ) {
                $Value = 'Age';
            }
            $TicketSearch{$Key} = $Value;
        }
        elsif ( !ref $TicketSearch{$Key} ) {
            my $ValueTmp = $TicketSearch{$Key};
            $TicketSearch{$Key} = [$ValueTmp];
            push @{ $TicketSearch{$Key} }, $Value;
        }
        else {
            push @{ $TicketSearch{$Key} }, $Value;
        }
    }
    %TicketSearch = (
        %TicketSearch,
        %DynamicFieldsParameters,
        Permission => $Self->{Config}->{Permission} || 'ro',
        UserID => $Self->{UserID},
    );

    # CustomerInformationCenter shows data per CustomerID
    if ( $Param{CustomerID} ) {
        $TicketSearch{CustomerIDRaw} = $Param{CustomerID};
    }

    # define filter attributes
    my @MyQueues = $QueueObject->GetAllCustomQueues(
        UserID => $Self->{UserID},
    );
    if ( !@MyQueues ) {
        @MyQueues = (999_999);
    }

    # get all queues the agent is allowed to see (for my services)
    my %ViewableQueues = $QueueObject->GetAllQueues(
        UserID => $Self->{UserID},
        Type   => 'ro',
    );
    my @ViewableQueueIDs = sort keys %ViewableQueues;
    if ( !@ViewableQueueIDs ) {
        @ViewableQueueIDs = (999_999);
    }

    # get the custom services from agent preferences
    # set the service ids to an array of non existing service ids (0)
    my @MyServiceIDs = (0);
    if ( $Self->{UseTicketService} ) {
        @MyServiceIDs = $Kernel::OM->Get('Kernel::System::Service')->GetAllCustomServices(
            UserID => $Self->{UserID},
        );

        if ( !defined $MyServiceIDs[0] ) {
            @MyServiceIDs = (0);
        }
    }

    my %TicketSearchSummary = (
        Locked => {
            OwnerIDs => [ $Self->{UserID}, ],
            LockIDs  => [ '2', '3' ],           # 'lock' and 'tmp_lock'
        },
        Watcher => {
            WatchUserIDs => [ $Self->{UserID}, ],
            LockIDs      => $TicketSearch{LockIDs} // undef,
        },
        Responsible => {
            ResponsibleIDs => [ $Self->{UserID}, ],
            LockIDs        => $TicketSearch{LockIDs} // undef,
        },
        MyQueues => {
            QueueIDs => \@MyQueues,
            LockIDs  => $TicketSearch{LockIDs} // undef,
        },
        MyServices => {
            QueueIDs   => \@ViewableQueueIDs,
            ServiceIDs => \@MyServiceIDs,
            LockIDs    => $TicketSearch{LockIDs} // undef,
        },
        All => {
            OwnerIDs => undef,
            LockIDs  => $TicketSearch{LockIDs} // undef,
        },
    );

    if ( defined $TicketSearch{QueueIDs} || defined $TicketSearch{Queues} ) {
        delete $TicketSearchSummary{MyQueues};
    }

    if ( !$Self->{UseTicketService} ) {
        delete $TicketSearchSummary{MyServices};
    }

    return (
        Columns             => \@Columns,
        TicketSearch        => \%TicketSearch,
        TicketSearchSummary => \%TicketSearchSummary,
    );
}

sub _DefaultColumnSort {
    my ( $Self, %Param ) = @_;

    my %DefaultColumns = (
        TicketNumber           => 100,
        Age                    => 110,
        Changed                => 111,
        PendingTime            => 112,
        EscalationTime         => 113,
        EscalationSolutionTime => 114,
        EscalationResponseTime => 115,
        EscalationUpdateTime   => 116,
        Title                  => 120,
        State                  => 130,
        Lock                   => 140,
        Queue                  => 150,
        Owner                  => 160,
        Responsible            => 161,
        CustomerID             => 170,
        CustomerName           => 171,
        CustomerUserID         => 172,
        Type                   => 180,
        Service                => 191,
        SLA                    => 192,
        Priority               => 193,
    );

    # set default order of ProcessManagement columns (for process widgets)
    if ( $Self->{Config}->{IsProcessWidget} ) {
        $DefaultColumns{"DynamicField_$Self->{ProcessManagementProcessID}"}  = 101;
        $DefaultColumns{"DynamicField_$Self->{ProcessManagementActivityID}"} = 102;
    }

    # dynamic fields can not be on the DefaultColumns sorting hash
    # when comparing 2 dynamic fields sorting must be alphabetical
    if ( !$DefaultColumns{$a} && !$DefaultColumns{$b} ) {
        return $a cmp $b;
    }

    # when a dynamic field is compared to a ticket attribute it must be higher
    elsif ( !$DefaultColumns{$a} ) {
        return 1;
    }

    # when a ticket attribute is compared to a dynamic field it must be lower
    elsif ( !$DefaultColumns{$b} ) {
        return -1;
    }

    # otherwise do a numerical comparison with the ticket attributes
    return $DefaultColumns{$a} <=> $DefaultColumns{$b};
}

1;

=back
AgentDashboardTicketGenericProjekt.tt

Code: Select all

# --
# AgentDashboardTicketGeneric.tt - provides HTML for global dashboard
# Copyright (C) 2001-2015 xxx, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

[% RenderBlockStart("ContentLargeTicketGenericFilter") %]
<ul class="Tab Actions">
    <li class="[% Data.item("Locked::Selected") | html %]"><a href="#" id="Dashboard[% Data.Name | html %]Locked" data-filter="Locked">[% Translate("My locked tickets") | html %] ([% Data.Locked | html %])</a></li>
[% RenderBlockStart("ContentLargeTicketGenericFilterWatcher") %]
    <li class="[% Data.item("Watcher::Selected") | html %]"><a href="#" id="Dashboard[% Data.Name | html %]Watcher" data-filter="Watcher">[% Translate("My watched tickets") | html %] ([% Data.Watcher | html %])</a></li>
[% RenderBlockEnd("ContentLargeTicketGenericFilterWatcher") %]
[% RenderBlockStart("ContentLargeTicketGenericFilterResponsible") %]
    <li class="[% Data.item("Responsible::Selected") | html %]"><a href="#" id="Dashboard[% Data.Name | html %]Responsible" data-filter="Responsible">[% Translate("My responsibilities") | html %] ([% Data.Responsible | html %])</a></li>
[% RenderBlockEnd("ContentLargeTicketGenericFilterResponsible") %]
[% RenderBlockStart("ContentLargeTicketGenericFilterMyQueues") %]
    <li class="[% Data.item("MyQueues::Selected") | html %]"><a href="#" id="Dashboard[% Data.Name | html %]MyQueues" data-filter="MyQueues">[% Translate("Tickets in My Queues") | html %] ([% Data.MyQueues | html %])</a></li>
[% RenderBlockEnd("ContentLargeTicketGenericFilterMyQueues") %]
[% RenderBlockStart("ContentLargeTicketGenericFilterMyServices") %]
    <li class="[% Data.item("MyServices::Selected") | html %]"><a href="#" id="Dashboard[% Data.Name | html %]MyServices" data-filter="MyServices">[% Translate("Tickets in My Services") | html %] ([% Data.MyServices | html %])</a></li>
[% RenderBlockEnd("ContentLargeTicketGenericFilterMyServices") %]
    <li class="[% Data.item("All::Selected") | html %] Last"><a href="#" id="Dashboard[% Data.Name | html %]All" data-filter="All">[% Translate("All tickets") | html %] ([% Data.All | html %])</a></li>
</ul>
[% RenderBlockStart("ContentLargeTicketGenericFilterNavBar") %]
<span class="Pagination">
    [% Data.SiteNavBar %]
</span>
[% RenderBlockEnd("ContentLargeTicketGenericFilterNavBar") %]
[% RenderBlockEnd("ContentLargeTicketGenericFilter") %]

#<!-- This form will not be submitted, we need it for the AJAX calls. -->
<form action="[% Env("CGIHandle") %]" method="post" enctype="multipart/form-data">
    <input type="hidden" name="CustomerID" value="[% Data.CustomerID | html %]"/>
    <input type="hidden" name="Filter[% Data.Name | html %]" id="Filter[% Data.Name | html %]" value="[% Data.FilterValue | html %]" />
    <table class="DataTable">
        <thead>
[% RenderBlockStart("ContentLargeTicketGenericHeader") %]
            <tr>

[% RenderBlockStart("GeneralOverviewHeader") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderMeta") %]
                <th class="DashboardHeader [% Data.CSS | html %]">
[% RenderBlockStart("ContentLargeTicketGenericHeaderMetaLink") %]
                    <a id="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" name="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" href="#" title="[% Data.Title | html %]" ></a>

[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('#[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]').unbind('click').bind('click', function (Event) {
        var Filter, LinkPage, ColumnFilterName, CustomerID;

        Filter  = $('#Filter[% Data.Name | html %]').val() || 'All';
        LinkPage = '';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // get all options of current column filter
            $(this).children().each( function() {
                if ( $(this).attr('value') && $(this).attr('selected') ) {
                    LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                }
            });
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';' + LinkPage + ';CustomerID=' + CustomerID + ';SortBy=[% Data.HeaderColumnName | html %];OrderBy=[% Data.OrderBy | html %]', function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        Event.preventDefault();
        return false;
    });
//]]></script>
[% END %]

[% RenderBlockEnd("ContentLargeTicketGenericHeaderMetaLink") %]
[% RenderBlockStart("ContentLargeTicketGenericHeaderMetaEmpty") %]
                    <span title="[% Translate(Data.HeaderColumnName) | html %]"></span>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderMetaEmpty") %]

                </th>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderMeta") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderTicketHeader") %]
[% RenderBlockStart("ContentLargeTicketGenericHeaderTicketNumberColumn") %]
                <th class="DashboardHeader TicketNumber [% Data.CSS | html %]" data-column="TicketNumber">
                    <a id="TicketNumberOverviewControl[% Data.Name | html %]" name="TicketNumberOverviewControl[% Data.Name | html %]" href="#" title="[% Data.Title | html %]" >[% Config("Ticket::Hook") %]</a>
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('#TicketNumberOverviewControl[% Data.Name | html %]').unbind('click').bind('click', function (Event) {
        var Filter, LinkPage, ColumnFilterName, CustomerID;

        Filter  = $('#Filter[% Data.Name | html %]').val() || 'All';
        LinkPage = '';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // get all options of current column filter
            $(this).children().each( function() {
                if ( $(this).attr('value') && $(this).attr('selected') ) {
                    LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                }
            });
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';' + LinkPage + ';CustomerID=' + CustomerID + ';SortBy=TicketNumber;OrderBy=[% Data.OrderBy | html %]', function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        Event.preventDefault();
        return false;
    });
//]]></script>
[% END %]
                </th>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderTicketNumberColumn") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumn") %]
                <th class="DashboardHeader [% Data.HeaderColumnName | html %] [% Data.CSS | html %]" data-column="[% Data.HeaderColumnName | html %]">

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnFilterLink") %]
                    <a href="#" class="ColumnSettingsTrigger" title="[% Data.FilterTitle | html %]">
                        <i class="fa fa-filter"></i>
                    </a>
                    <div class="ColumnSettingsContainer">
                        <div class="ColumnSettingsBox">
                            [% Data.ColumnFilterStrg %]
[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnFilterLinkCustomerIDSearch") %]
                            <input type="text" class="CustomerIDAutoComplete" autocomplete="off" />
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
Core.Config.Set('CustomerIDAutocomplete.QueryDelay', "[% Data.queryDelay | html %]");
Core.Config.Set('CustomerIDAutocomplete.MaxResultsDisplayed', "[% Data.maxResultsDisplayed | html %]");
Core.Config.Set('CustomerIDAutocomplete.MinQueryLength', "[% Data.minQueryLength | html %]");
Core.Agent.Dashboard.InitCustomerIDAutocomplete( $(".CustomerIDAutoComplete") );
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnFilterLinkCustomerIDSearch") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnFilterLinkUserSearch") %]
                            <input type="text" class="UserAutoComplete" autocomplete="off" />
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
Core.Config.Set('UserAutocomplete.QueryDelay', "[% Data.queryDelay | html %]");
Core.Config.Set('UserAutocomplete.MaxResultsDisplayed', "[% Data.maxResultsDisplayed | html %]");
Core.Config.Set('UserAutocomplete.MinQueryLength', "[% Data.minQueryLength | html %]");
Core.Agent.Dashboard.InitUserAutocomplete( $(".UserAutoComplete") );
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnFilterLinkUserSearch") %]
                            <a href="#" class="DeleteFilter Hidden"><i class="fa fa-trash-o"></i></a>
                        </div>
                    </div>

                    <a id="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" name="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" href="#" title="[% Data.Title | html %]" >[% Data.HeaderNameTranslated | html %]</a>
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('#ColumnFilter[% Data.HeaderColumnName | html %][% Data.Name | html %]').unbind('change').bind('change', function(){
        var LinkPage, ColumnFilterName, Filter, ColumnFilterID, CustomerID;

        LinkPage = '';
        Filter   = $('#Filter[% Data.Name | html %]').val() || 'All';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // set ColumnFilter value for current ColumnFilter
        ColumnFilterName = $(this).attr('name');
        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).val() + ';';

        // remember the current ColumnFilter ID
        ColumnFilterID = $(this).attr('ID');

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // exclude current column filter, apparently the selected option is not set to
            // selected at this point and uses the old value
            if ($(this).attr('ID') !== ColumnFilterID) {

                // get all options of current column filter
                $(this).children().each( function() {
                    if ( $(this).attr('value') && $(this).attr('selected') ) {
                        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                    }
                });
            }
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=' + CustomerID + ';SortBy=[% Data.SortBy | html %];OrderBy=[% Data.OrderBy | html %];' + LinkPage, function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        return false;
    });

    $('#[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]').unbind('click').bind('click', function (Event) {
        var LinkPage, ColumnFilterName, Filter, ColumnFilterID, CustomerID;

        LinkPage = '';
        Filter   = $('#Filter[% Data.Name | html %]').val() || 'All';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // set ColumnFilter value for current ColumnFilter
        ColumnFilterName = $(this).attr('name');
        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).val() + ';';

        // remember the current ColumnFilter ID
        ColumnFilterID = $(this).attr('ID');

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // exclude current column filter, apparently the selected option is not set to
            // selected at this point and uses the old value
            if ($(this).attr('ID') !== ColumnFilterID) {

                // get all options of current column filter
                $(this).children().each( function() {
                    if ( $(this).attr('value') && $(this).attr('selected') ) {
                        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                    }
                });
            }
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=' + CustomerID + ';SortBy=[% Data.HeaderColumnName | html %];OrderBy=[% Data.OrderBy | html %];' + LinkPage, function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        Event.preventDefault();
        return false;
    });
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnFilterLink") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnLink") %]
                    <a id="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" name="[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]" href="#" title="[% Data.Title | html %]" >[% Data.HeaderNameTranslated | html %]</a>
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('#[% Data.HeaderColumnName | html %]OverviewControl[% Data.Name | html %]').unbind('click').bind('click', function (Event) {
        var LinkPage, ColumnFilterName, Filter, ColumnFilterID, CustomerID;

        LinkPage = '';
        Filter   = $('#Filter[% Data.Name | html %]').val() || 'All';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // set ColumnFilter value for current ColumnFilter
        ColumnFilterName = $(this).attr('name');
        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).val() + ';';

        // remember the current ColumnFilter ID
        ColumnFilterID = $(this).attr('ID');

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // exclude current column filter, apparently the selected option is not set to
            // selected at this point and uses the old value
            if ($(this).attr('ID') !== ColumnFilterID) {

                // get all options of current column filter
                $(this).children().each( function() {
                    if ( $(this).attr('value') && $(this).attr('selected') ) {
                        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                    }
                });
            }
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=' + CustomerID +';SortBy=[% Data.HeaderColumnName | html %];OrderBy=[% Data.OrderBy | html %];' + LinkPage, function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        Event.preventDefault();
        return false;
    });
//]]></script>
[% END %]

[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnLink") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnFilter") %]
                    <a href="#" class="ColumnSettingsTrigger" title="[% Data.FilterTitle | html %]">
                        <i class="fa fa-filter"></i>
                    </a>
                    <div class="ColumnSettingsContainer">
                        <div class="ColumnSettingsBox">
                            [% Data.ColumnFilterStrg %]
[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnFilterLinkCustomerUserSearch") %]
                            <input type="text" class="CustomerUserAutoComplete" autocomplete="off" />
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
Core.Config.Set('CustomerUserAutocomplete.QueryDelay', "[% Data.queryDelay | html %]");
Core.Config.Set('CustomerUserAutocomplete.MaxResultsDisplayed', "[% Data.maxResultsDisplayed | html %]");
Core.Config.Set('CustomerUserAutocomplete.MinQueryLength', "[% Data.minQueryLength | html %]");
Core.Agent.Dashboard.InitCustomerUserAutocomplete( $(".CustomerUserAutoComplete") );
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnFilterLinkCustomerUserSearch") %]
                            <a href="#" class="DeleteFilter Hidden"><i class="fa fa-trash-o"></i></a>
                        </div>
                    </div>

[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('#ColumnFilter[% Data.HeaderColumnName | html %][% Data.Name | html %]').unbind('change').bind('change', function(){
        var LinkPage, ColumnFilterName, Filter, ColumnFilterID, CustomerID;

        LinkPage = '';
        Filter   = $('#Filter[% Data.Name | html %]').val() || 'All';
        CustomerID = $('input[name=CustomerID]').val() || '';

        // set ColumnFilter value for current ColumnFilter
        ColumnFilterName = $(this).attr('name');
        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).val() + ';';

        // remember the current ColumnFilter ID
        ColumnFilterID = $(this).attr('ID');

        // get all column filters
        $('.ColumnFilter').each(function(){
            ColumnFilterName  = $(this).attr('name');

            // exclude current column filter, apparently the selected option is not set to
            // selected at this point and uses the old value
            if ($(this).attr('ID') !== ColumnFilterID) {

                // get all options of current column filter
                $(this).children().each( function() {
                    if ( $(this).attr('value') && $(this).attr('selected') ) {
                        LinkPage = LinkPage + ColumnFilterName + '=' + $(this).attr('value') + ';';
                    }
                });
            }
        });

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=' + CustomerID + ';SortBy=[% Data.SortBy | html %];OrderBy=[% Data.OrderBy | html %];' + LinkPage, function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        return false;
    });
//]]></script>
[% END %]
                    <span class="Gray" title="[% Data.Title | html %]" >[% Data.HeaderNameTranslated | html %]</span>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnFilter") %]

[% RenderBlockStart("ContentLargeTicketGenericHeaderColumnEmpty") %]
                    <span class="Gray" title="[% Data.Title | html %]" >[% Data.HeaderNameTranslated %]</span>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumnEmpty") %]
                </th>
[% RenderBlockEnd("ContentLargeTicketGenericHeaderColumn") %]
[% RenderBlockEnd("ContentLargeTicketGenericHeaderTicketHeader") %]

[% RenderBlockEnd("GeneralOverviewHeader") %]

            </tr>

[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
$('.DashboardHeader').off('click').on('click', '.ColumnSettingsTrigger', function() {

    var $TriggerObj = $(this),
        $ColumnSettingsContainer = $TriggerObj.next('.ColumnSettingsContainer'),
        FilterName;

    if ($TriggerObj.hasClass('Active')) {

        $TriggerObj
            .next('.ColumnSettingsContainer')
            .find('.ColumnSettingsBox')
            .fadeOut('fast', function() {
                $TriggerObj.removeClass('Active');
            });
    }
    else {

        // slide up all open settings widgets
        $('.ColumnSettingsTrigger')
            .next('.ColumnSettingsContainer')
            .find('.ColumnSettingsBox')
            .fadeOut('fast', function() {
                $(this).parent().prev('.ColumnSettingsTrigger').removeClass('Active');
            });

        // show THIS settings widget
        $ColumnSettingsContainer
            .find('.ColumnSettingsBox')
            .fadeIn('fast', function() {

                $TriggerObj.addClass('Active');

                // only show and use the delete filter icon in case of autocomplete fields
                // because in regular dropdowns we have a different way to delete the filter
                if ($TriggerObj.closest('th').hasClass('FilterActive') && $ColumnSettingsContainer.find('select.ColumnFilter').hasClass('Hidden')) {
                    $ColumnSettingsContainer
                        .find('.DeleteFilter')
                        .removeClass('Hidden')
                        .off()
                        .on('click', function() {
                            $(this)
                                .closest('.ColumnSettingsContainer')
                                .find('select')
                                .val('DeleteFilter')
                                .trigger('change');

                            return false;
                        });
                }

                // refresh filter dropdown
                FilterName = $ColumnSettingsContainer
                    .find('select')
                    .attr('name');

                if ( $TriggerObj.closest('th').hasClass('CustomerID') || $TriggerObj.closest('th').hasClass('CustomerUserID') || $TriggerObj.closest('th').hasClass('Responsible') || $TriggerObj.closest('th').hasClass('Owner') ) {

                    if (!$TriggerObj.parent().find('.SelectedValue').length) {
                        Core.AJAX.FormUpdate($TriggerObj.parents('form'), 'AJAXFilterUpdate', FilterName, [ FilterName ], function() {
                            var AutoCompleteValue = $ColumnSettingsContainer
                                    .find('select')
                                    .val(),
                                AutoCompleteText  = $ColumnSettingsContainer
                                    .find('select')
                                    .find('option:selected')
                                    .text();

                            if (AutoCompleteValue !== 'DeleteFilter') {

                                $ColumnSettingsContainer
                                    .find('select')
                                    .after('<span class="SelectedValue Hidden"><span title="' + AutoCompleteText + ' (' + AutoCompleteValue + ')">' + AutoCompleteText + ' (' + AutoCompleteValue + ')</span></span>');
                            }
                        });
                    }
                }
                else {
                    Core.AJAX.FormUpdate($TriggerObj.parents('form'), 'AJAXFilterUpdate', FilterName, [ FilterName ]);
                }
        });
    }

    return false;
});

//]]></script>
[% END %]

[% RenderBlockEnd("ContentLargeTicketGenericHeader") %]
        </thead>

        <tbody>
[% RenderBlockStart("ContentLargeTicketGenericRow") %]
            <tr class="MasterAction">

[% RenderBlockStart("GeneralOverviewRow") %]

[% RenderBlockStart("ContentLargeTicketGenericRowMeta") %]
                <td class="[% Data.ClassTable | html %] Flags" title="[% Translate(Data.Title) | html %]">
[% RenderBlockStart("ContentLargeTicketGenericRowMetaImage") %]
                    <div class="[% Data.Class | html %] Small" title="[% Translate(Data.Title) | html %]">
                        <span class="[% Data.ClassSpan | html %]">
                            <i class="fa fa-star"></i>
                            <i class="fa fa-star"></i>
                            <em>[% Translate(Data.Title) | html %]</em>
                        </span>
                    </div>
[% RenderBlockEnd("ContentLargeTicketGenericRowMetaImage") %]
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericRowMeta") %]

#            <td class="W10pc">
#                <a href="[% Env("Baselink") %]Action=AgentTicketZoom;TicketID=[% Data.TicketID %]" title="[% Data.Title | html %]" class="AsBlock MasterActionLink">[% Data.TicketNumber %]</a>
#            </td>
#            <td class="W50pc">
#                <div title="[% Data.Title | html %]">[% Data.Title | truncate(70) | html %]</div>
#            </td>
#            <td>[% Data.Time | html %]</td>

[% RenderBlockStart("ContentLargeTicketGenericTicketColumn") %]
[% RenderBlockStart("ContentLargeTicketGenericTicketNumber") %]
                <td>
                    <a href="[% Env("Baselink") %]Action=AgentTicketZoom;TicketID=[% Data.TicketID %]" title="[% Data.Title | html %]" class="AsBlock MasterActionLink">[% Data.TicketNumber %]</a>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericTicketNumber") %]
[% RenderBlockStart("ContentLargeTicketGenericEscalationTime") %]
                <td>
                    <div title="[% Translate("Service Time") | html %]: [% Data.EscalationTimeWorkingTime | html %] - [% Data.EscalationDestinationDate | Localize("TimeShort") %]" class="[% Data.EscalationClass | html %]">[% Data.EscalationTimeHuman | html %]<br/>[% Data.UpdateTimeDestinationDate | Localize("TimeShort") %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericEscalationTime") %]
[% RenderBlockStart("ContentLargeTicketGenericColumn") %]
                <td>
                    <div title="[% Data.GenericValue | html %]">[% Data.GenericValue | truncate(40) | html %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericColumn") %]
[% RenderBlockStart("ContentLargeTicketTitle") %]
                <td>
                    <div title="[% Data.WholeTitle | html %]">[% Data.Title | html %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketTitle") %]
[% RenderBlockStart("ContentLargeTicketGenericColumnTranslatable") %]
                <td>
                    <div title="[% Translate(Data.GenericValue) | html %]">[% Translate(Data.GenericValue) | html %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericColumnTranslatable") %]
[% RenderBlockStart("ContentLargeTicketGenericColumnTime") %]
                <td>
                    <div title="[% Data.GenericValue | Localize("TimeShort") | html %]">[% Data.GenericValue | Localize("TimeShort") %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericColumnTime") %]
[% RenderBlockStart("ContentLargeTicketGenericColumnEscalation") %]
                <td>
                    <div title="[% Data.GenericValue | html %]" class="[% Data.Class | html %]">[% Data.GenericValue | html %]</div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericColumnEscalation") %]
[% RenderBlockEnd("ContentLargeTicketGenericTicketColumn") %]

[% RenderBlockStart("ContentLargeTicketGenericDynamicField") %]
                <td>
                    <div title="[% Data.Title | html %]">
[% RenderBlockStart("ContentLargeTicketGenericDynamicFieldLink") %]
                        <a href="[% Data.Link | Interpolate %]"  target="_blank" class="DynamicFieldLink">[% Data.Value %]</a>
[% RenderBlockEnd("ContentLargeTicketGenericDynamicFieldLink") %]
[% RenderBlockStart("ContentLargeTicketGenericDynamicFieldPlain") %]
                        [% Data.Value %]
[% RenderBlockEnd("ContentLargeTicketGenericDynamicFieldPlain") %]
                    </div>
                </td>
[% RenderBlockEnd("ContentLargeTicketGenericDynamicField") %]

[% RenderBlockEnd("GeneralOverviewRow") %]

            </tr>
[% RenderBlockEnd("ContentLargeTicketGenericRow") %]
[% RenderBlockStart("ContentLargeTicketGenericNone") %]
            <tr>
                <td class="AutoColspan">
                    [% Translate("none") | html %]
                </td>
            </tr>
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
$('.AutoColspan').each(function() {
    var ColspanCount = $(this).closest('table').find('th').length;
    $(this).attr('colspan', ColspanCount);
});
//]]></script>
[% END %]

[% RenderBlockEnd("ContentLargeTicketGenericNone") %]
        </tbody>
    </table>
</form>

[% RenderBlockStart("ContentLargeTicketGenericRefresh") %]
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
Core.Config.Set('RefreshSeconds_[% Data.NameHTML | html %]', parseInt("[% Data.RefreshTime | html %]", 10) || 0);
if (Core.Config.Get('RefreshSeconds_[% Data.NameHTML | html %]')) {
    Core.Config.Set('Timer_[% Data.NameHTML | html %]', window.setTimeout(function() {

        // get active filter
        var Filter      = $('#Dashboard[% Data.Name | html %]-box').find('.Tab.Actions li.Selected a').attr('data-filter'),
            $OrderByObj = $('#Dashboard[% Data.Name | html %]-box').find('th.SortDescendingLarge, th.SortAscendingLarge'),
            SortBy      = $OrderByObj.attr('data-column') || '',
            OrderBy     = '';

        if ($OrderByObj && $OrderByObj.hasClass('SortDescendingLarge')) {
            OrderBy = 'Up';
        }
        else if ($OrderByObj && $OrderByObj.hasClass('SortAscendingLarge')) {
            OrderBy = 'Down';
        }

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=[% Data.CustomerID | html %];SortBy=' + SortBy + ';OrderBy=' + OrderBy, function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        clearTimeout(Core.Config.Get('Timer_[% Data.NameHTML | html %]'));
    }, Core.Config.Get('RefreshSeconds_[% Data.NameHTML | html %]') * 1000));
}
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericRefresh") %]

[% RenderBlockStart("ContentLargeTicketGenericRemoveFilters") %]
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
if (!$('#Dashboard[% Data.Name | html %]-box').find('.ActionMenu').find('.RemoveFilters').length) {
    $('#Dashboard[% Data.Name | html %]-box')
        .find('.ActionMenu')
        .prepend('<div class="WidgetAction RemoveFilters"><a href="#" id="Dashboard[% Data.Name | html %]-remove-filters" title="[% Translate("Remove active filters for this widget.") | html %]"><i class="fa fa-trash-o"></i></a></div>')
        .find('.RemoveFilters')
        .on('click', function() {

            // get active filter
            var Filter = $('#Dashboard[% Data.Name | html %]-box').find('.Tab.Actions li.Selected a').attr('data-filter');
            $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
            Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=[% Data.CustomerID | html %];RemoveFilters=1', function () {
                Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
                $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
            });
            return false;
        });
}
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericRemoveFilters") %]

[% RenderBlockStart("ContentLargeTicketGenericRemoveFiltersRemove") %]
[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
$('#Dashboard[% Data.Name | html %]-box').find('.RemoveFilters').remove();
//]]></script>
[% END %]
[% RenderBlockEnd("ContentLargeTicketGenericRemoveFiltersRemove") %]

[% WRAPPER JSOnDocumentComplete %]
<script type="text/javascript">//<![CDATA[
    $('.MasterAction').bind('click', function (Event) {
        var $MasterActionLink = $(this).find('.MasterActionLink');
        // prevent MasterAction on Dynamic Fields links
        if ($(Event.target).hasClass('DynamicFieldLink')) {
            return true;
        }
        // only act if the link was not clicked directly
        if (Event.target !== $MasterActionLink.get(0)) {
            window.location = $MasterActionLink.attr('href');
            return false;
        }
    });

    $('#Dashboard[% Data.Name | html %]-box').find('.Tab.Actions li a').unbind('click').bind('click', function() {
        var Filter = $(this).attr('data-filter'),
        CustomerID;

        CustomerID = $('input[name=CustomerID]').val() || '';

        $('#Dashboard[% Data.Name | html %]-box').addClass('Loading');
        Core.AJAX.ContentUpdate($('#Dashboard[% Data.Name | html %]'), '[% Env("Baselink") %]Action=[% Env("Action") %];Subaction=Element;Name=[% Data.Name | html %];Filter=' + Filter + ';CustomerID=' + encodeURIComponent(CustomerID), function () {
            Core.UI.Table.InitCSSPseudoClasses($('#Dashboard[% Data.Name | html %]'));
            $('#Dashboard[% Data.Name | html %]-box').removeClass('Loading');
        });
        return false;
    });
//]]></script>
[% END %]

DashboardTicketGenericProjekt.xml

Code: Select all

<?xml version="1.0" encoding="utf-8"?>
<otrs_config version="1.0" init="Application">
<ConfigItem Name="DashboardBackend###11899-DashboardTicketGenericProjekt" Required="0" Valid="1">
        <Description Translatable="1">Parameters for the dashboard backend of the ticket pending reminder overview of the agent interface. "Limit" is the number of entries shown by default. "Group" is used to restrict the access to the plugin (e. g. Group: admin;group1;group2;). "Default" determines if the plugin is enabled by default or if the user needs to enable it manually. "CacheTTLLocal" is the cache time in minutes for the plugin. Note: Only Ticket attributes and Dynamic Fields (DynamicField_NameX) are allowed for DefaultColumns. Possible settings: 0 = Disabled, 1 = Available, 2 = Enabled by default.</Description>
        <Group>Ritter Framework</Group>
        <SubGroup>Frontend::Agent::DashboardRitter</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardTicketGenericProjekt</Item>
                <Item Key="Title" Translatable="1">Offene Projekt Tickets</Item>
                <Item Key="Description" Translatable="1">All open tickets, these tickets have already been worked on, but need a response</Item>
                <Item Key="Attributes">StateType=open;</Item>
                <Item Key="Filter">All</Item>
                <Item Key="Time">Age</Item>
                <Item Key="Limit">10</Item>
                <Item Key="Permission">rw</Item>
                <Item Key="Block">ContentLarge</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
                <Item Key="CacheTTLLocal">0.5</Item>
                <Item Key="DefaultColumns">
                    <Hash>
                        <Item Key="Age">2</Item>
                        <Item Key="Changed">1</Item>
                        <Item Key="CustomerID">1</Item>
                        <Item Key="CustomerName">1</Item>
                        <Item Key="CustomerUserID">1</Item>
                        <Item Key="EscalationResponseTime">1</Item>
                        <Item Key="EscalationSolutionTime">1</Item>
                        <Item Key="EscalationTime">1</Item>
                        <Item Key="EscalationUpdateTime">1</Item>
                        <Item Key="TicketNumber">2</Item>
                        <Item Key="Lock">1</Item>
                        <Item Key="Owner">1</Item>
                        <Item Key="PendingTime">1</Item>
                        <Item Key="Queue">1</Item>
                        <Item Key="Responsible">1</Item>
                        <Item Key="Priority">1</Item>
                        <Item Key="Service">1</Item>
                        <Item Key="State">1</Item>
                        <Item Key="SLA">1</Item>
                        <Item Key="Title">2</Item>
                        <Item Key="Type">1</Item>
                    </Hash>
                </Item>
            </Hash>
        </Setting>
    </ConfigItem>		
</otrs_config>
Linux Debian Jessie
DB: postgres
aph
Znuny superhero
Posts: 646
Joined: 20 Jun 2014, 12:11
Znuny Version: 3.3.9, 4.x, 5.x

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by aph »

Code: Select all

package Kernel::Output::HTML::DashboardTicketGeneric;
müsste

Code: Select all

package Kernel::Output::HTML::DashboardTicketGenericProjekt;
heißen.
Ändere dann auch die Zeilen (nicht zwingend notwendig)

Code: Select all

# Kernel/Output/HTML/DashboardTicketGeneric.pm
und

Code: Select all

# AgentDashboardTicketGeneric.tt - provides HTML for global dashboard
zu

Code: Select all

# Kernel/Output/HTML/DashboardTicketGenericProjekt.pm
und

Code: Select all

# AgentDashboardTicketGenericProjekt.tt - provides HTML for global dashboard
damit man später nicht durcheinander kommt.
OTRS 3.3.x (private/testing) on Windows Server 2008 with MSSQL database.
OTRS 3.3.x (private/testing) on CentOS with MySQL database and apache
shining01
Znuny expert
Posts: 270
Joined: 07 Apr 2011, 08:02
Znuny Version: 6.0.4
Real Name: Tom

Re: Ticketliste als neue Queue Ansicht im Dashboard

Post by shining01 »

Super jetzt funktioniert es. Vielen vielen Dank an alle!!!!
Linux Debian Jessie
DB: postgres
Locked