From dc7240cf7765f3076bf453f1f79a7945c7039cf9 Mon Sep 17 00:00:00 2001
From: Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de>
Date: Thu, 27 Jul 2023 00:38:28 +0200
Subject: [PATCH] fix layout of tables, fixes #9, #17 and #25

---
 Stundenzettel.class.php                   |   8 +-
 controllers/index.php                     |  19 ++-
 controllers/timesheet.php                 |   2 +-
 migrations/006_add_approved_timestamp.php |   8 +
 models/StundenzettelContract.class.php    |  21 +--
 models/StundenzettelTimesheet.class.php   |  42 +++--
 views/index/index.php                     | 193 +++++++++++-----------
 views/index/new.php                       |   5 +
 views/timesheet/admin_index.php           |  55 +++---
 views/timesheet/index.php                 |  62 +++----
 10 files changed, 214 insertions(+), 201 deletions(-)

diff --git a/Stundenzettel.class.php b/Stundenzettel.class.php
index 3c22610..7b5a694 100644
--- a/Stundenzettel.class.php
+++ b/Stundenzettel.class.php
@@ -112,7 +112,7 @@ class Stundenzettel extends StudipPlugin implements SystemPlugin
 
     public function isStumiSupervisor()
     {
-        return StundenzettelContract::findBySupervisor($GLOBALS['user']->user_id);
+        return StundenzettelContract::findBySupervisor_id($GLOBALS['user']->user_id);
     }
 
     public function vacationEntitelment($user_id, $inst_id, $year) {
@@ -201,11 +201,7 @@ class Stundenzettel extends StudipPlugin implements SystemPlugin
     public function can_access_contract_timesheets($contract_id)
     {
         $contract = StundenzettelContract::find($contract_id);
-        if ($contract->supervisor == User::findCurrent()->user_id || $contract->user_id == User::findCurrent()->user_id) {
-            return true;
-        } else {
-            return false;
-        }
+        return $contract->supervisor_id == User::findCurrent()->user_id || $contract->user_id == User::findCurrent()->user_id;
     }
 
     //TODO gehört in die Models
diff --git a/controllers/index.php b/controllers/index.php
index c7d8e73..ba64298 100644
--- a/controllers/index.php
+++ b/controllers/index.php
@@ -73,7 +73,7 @@ class IndexController extends PluginController {
                         $stumi = User::find($member->user_id);
                         if (!$this->search || stripos($stumi->username . ' ' . $stumi->vorname . ' ' . $stumi->nachname, $this->search)) {
                             $this->inst_data[$inst_id][$group->id]['stumis'][] = $stumi;
-                            $this->inst_data[$inst_id][$group->id]['stumi_contracts'][$member->user_id] = StundenzettelContract::findBySQL('`user_id` = ? AND `inst_id` = ?', [$member->user_id, $inst_id]);
+                            $this->inst_data[$inst_id][$group->id]['stumi_contracts'][$member->user_id] = StundenzettelContract::findBySQL('user_id = ? AND inst_id = ?', [$member->user_id, $inst_id]);
                             $user_ids[] = $member->user_id;
                         }
                     }
@@ -84,7 +84,7 @@ class IndexController extends PluginController {
                     $former_stumi = User::find($old_contract->user_id);
                     if ((!in_array($old_contract->user_id, $user_ids)) && (!$this->search || stripos($former_stumi->username . ' ' . $former_stumi->vorname . ' ' . $former_stumi->nachname, $this->search))) {
                         $this->inst_data[$inst_id][0]['stumis'][] = $former_stumi;
-                        $this->inst_data[$inst_id][0]['stumi_contracts'][$former_stumi->user_id] = StundenzettelContract::findBySQL('`user_id` = ? AND `inst_id` = ?', [$former_stumi->user_id, $inst_id]);
+                        $this->inst_data[$inst_id][0]['stumi_contracts'][$former_stumi->user_id] = StundenzettelContract::findBySQL('user_id = ? AND inst_id = ?', [$former_stumi->user_id, $inst_id]);
                         $user_ids[] = $former_stumi->user_id;
                     }
                 }
@@ -97,13 +97,13 @@ class IndexController extends PluginController {
         if ($this->supervisorrole) {
 
             //get stumis for this user
-            $stumi_contracts = StundenzettelContract::findBySupervisor(User::findCurrent()->user_id);
+            $stumi_contracts = StundenzettelContract::findBySupervisor_id(User::findCurrent()->user_id);
             $this->user_ids = [];
             foreach ($stumi_contracts as $contract) {
                 if (!in_array($contract->user_id, $this->user_ids)) {
                     $this->user_ids[] = $contract->user_id;
                     $this->stumis[] = User::find($contract->user_id);
-                    $this->stumi_contracts[$contract->user_id] = StundenzettelContract::findBySQL('`user_id` = ? AND `supervisor` = ?', [$contract->user_id, User::findCurrent()->user_id]);
+                    $this->stumi_contracts[$contract->user_id] = StundenzettelContract::findBySQL('user_id = ? AND supervisor_id = ?', [$contract->user_id, User::findCurrent()->user_id]);
                 }
             }
 
@@ -147,11 +147,11 @@ class IndexController extends PluginController {
         $this->contract = StundenzettelContract::find($contract_id);
         $this->inst_id = $this->contract->inst_id;
         $this->stumi = $this->contract->stumi;
-        $supervisor = User::find($this->contract->supervisor);
+        $supervisor = $this->contract->supervisor;
         $this->following_contract = $following_contract;
 
         $this->search = QuickSearch::get('user_id', new StandardSearch('user_id'))
-            ->defaultValue($this->contract->supervisor, $supervisor->vorname . ' ' . $supervisor->nachname)
+            ->defaultValue($this->contract->supervisor_id, $supervisor->vorname . ' ' . $supervisor->nachname)
             ->withButton(array('search_button_name' => 'search_user', 'reset_button_name' => 'reset_search'))
             ->render();
 
@@ -188,7 +188,8 @@ class IndexController extends PluginController {
         $contract->contract_begin = strtotime(Request::get('begin'));
         $contract->contract_end = strtotime(Request::get('end'));
         $contract->contract_hours = Request::get('hours');
-        $contract->supervisor = Request::get('user_id');
+        $contract->description = trim(Request::get('description'));
+        $contract->supervisor_id = Request::get('user_id');
         $contract->store();
 
         //TODO
@@ -309,7 +310,7 @@ class IndexController extends PluginController {
         foreach ($settings->stumi_statusgroups as $group) {
             foreach ($group->members as $member) {
                 $stumi = User::find($member->user_id);
-                $stumi_contracts = StundenzettelContract::findBySQL('`user_id` = ? AND `inst_id` = ?', [$member->user_id, $inst_id]);
+                $stumi_contracts = StundenzettelContract::findBySQL('user_id = ? AND inst_id = ?', [$member->user_id, $inst_id]);
                 foreach ($stumi_contracts as $contract) {
                     $contract = StundenzettelContract::find($contract->id);
                     $export_data[] = [
@@ -324,7 +325,7 @@ class IndexController extends PluginController {
                         StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacation(date('Y'))),
                         Stundenzettel::vacationEntitelment($stumi->user_id, $inst_id, date('Y')),
                         StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacationAtEndOfYear(date('Y')-1)),
-                        User::find($contract->supervisor)->vorname . ' ' . User::find($contract->supervisor)->nachname
+                        $contract->supervisor->vorname . ' ' . $contract->supervisor->nachname
                     ];
                 }
             }
diff --git a/controllers/timesheet.php b/controllers/timesheet.php
index 2f6cfd7..4afe4b6 100644
--- a/controllers/timesheet.php
+++ b/controllers/timesheet.php
@@ -419,7 +419,7 @@ class TimesheetController extends PluginController {
     {
         $timesheet = StundenzettelTimesheet::find($timesheet_id);
 
-        if (!($this->adminrole || $timesheet->contract->supervisor == User::findCurrent()->user_id)) {
+        if (!($this->adminrole || $timesheet->contract->supervisor_id == User::findCurrent()->user_id)) {
             throw new AccessDeniedException($this->_("Sie haben keine Zugriffsberechtigung"));
         }
 
diff --git a/migrations/006_add_approved_timestamp.php b/migrations/006_add_approved_timestamp.php
index e27ba9c..52ee4f8 100644
--- a/migrations/006_add_approved_timestamp.php
+++ b/migrations/006_add_approved_timestamp.php
@@ -16,6 +16,10 @@ class AddApprovedTimestamp extends Migration
                 ADD approved_at date DEFAULT NULL,
                 ADD approver_id varchar(32) COLLATE latin1_bin DEFAULT NULL';
         $db->exec($sql);
+
+        $sql = 'ALTER TABLE stundenzettel_contracts
+                CHANGE supervisor supervisor_id varchar(32) COLLATE latin1_bin NULL';
+        $db->exec($sql);
     }
 
     public function down()
@@ -27,5 +31,9 @@ class AddApprovedTimestamp extends Migration
                 DROP approved_at,
                 DROP approver_id';
         $db->exec($sql);
+
+        $sql = 'ALTER TABLE stundenzettel_contracts
+                CHANGE supervisor_id supervisor varchar(32) COLLATE latin1_bin NULL';
+        $db->exec($sql);
     }
 }
diff --git a/models/StundenzettelContract.class.php b/models/StundenzettelContract.class.php
index 6c5b76a..d42276b 100644
--- a/models/StundenzettelContract.class.php
+++ b/models/StundenzettelContract.class.php
@@ -77,9 +77,9 @@ class StundenzettelContract extends \SimpleORMap
     {
         $config['db_table'] = 'stundenzettel_contracts';
 
-        $config['belongs_to']['supervisor_user'] = [
+        $config['belongs_to']['supervisor'] = [
             'class_name'  => 'User',
-            'foreign_key' => 'supervisor'
+            'foreign_key' => 'supervisor_id'
         ];
         $config['belongs_to']['stumi'] = [
             'class_name'  => 'User',
@@ -126,9 +126,10 @@ class StundenzettelContract extends \SimpleORMap
     }
 
     function can_read($user) {
-        if ($this->user_id == $user->user_id || $this->supervisor == $user->user_id || Stundenzettel::isInstAdmin($this->inst_id)) {
+        if ($this->user_id == $user->user_id || $this->supervisor_id == $user->user_id || Stundenzettel::isInstAdmin($this->inst_id)) {
             return true;
         }
+        return false;
     }
 
     static function getCurrentContractId($user_id)
@@ -161,13 +162,13 @@ class StundenzettelContract extends \SimpleORMap
 
         if ($GLOBALS['perm']->have_perm('admin')) {
             return $all_contracts;
-        } else {
-            foreach ($all_contracts as $contract) {
-                if ($contract->user_id == User::findCurrent()->user_id ||
-                $contract->supervisor == User::findCurrent()->user_id ||
+        }
+
+        foreach ($all_contracts as $contract) {
+            if ($contract->user_id == User::findCurrent()->user_id ||
+                $contract->supervisor_id == User::findCurrent()->user_id ||
                 Stundenzettel::isInstAdmin($contract->inst_id)) {
-                    $contracts[] = $contract;
-                }
+                $contracts[] = $contract;
             }
         }
 
@@ -175,7 +176,7 @@ class StundenzettelContract extends \SimpleORMap
     }
 
     //TODO Institutsbezogen
-     static function getUserContractsByMonth($user_id, $month, $year)
+    static function getUserContractsByMonth($user_id, $month, $year)
     {
         $begin_lastmonth = strtotime(date("y-m",strtotime("-1 month")) . '-01');
         $end_nextmonth = strtotime(date("y-m",strtotime("+1 month")) . '-28');
diff --git a/models/StundenzettelTimesheet.class.php b/models/StundenzettelTimesheet.class.php
index 38cf0f1..e1b1a74 100644
--- a/models/StundenzettelTimesheet.class.php
+++ b/models/StundenzettelTimesheet.class.php
@@ -201,8 +201,8 @@ class StundenzettelTimesheet extends \SimpleORMap
 
     function send_finished_mail()
     {
-        $user = User::find($this->contract->user_id);
-        $supervisor = User::find($this->contract->supervisor);
+        $user = $this->contract->stumi;
+        $supervisor = $this->contract->supervisor;
         setTempLanguage($supervisor->id);
         $sender = "studip@uni-osnabrueck.de";
         $subject = sprintf(dgettext('stundenzettel', '%s %s hat den Stundenzettel für den Monat %s eingereicht'), $user->vorname, $user->nachname, strftime("%B", mktime(0, 0, 0, $this->month, 10)) );
@@ -212,8 +212,8 @@ class StundenzettelTimesheet extends \SimpleORMap
         restoreLanguage();
         $mail       = new StudipMail();
         $success    = $mail->addRecipient($supervisor->email)
-             ->setSenderEmail( $sender )
-             ->setSenderName( 'Stud.IP' )
+             ->setSenderEmail($sender)
+             ->setSenderName('Stud.IP')
              ->setSubject($subject)
              ->setBodyText($mailtext)
              ->send();
@@ -225,8 +225,8 @@ class StundenzettelTimesheet extends \SimpleORMap
         $sender = "studip@uni-osnabrueck.de";
         $mail       = new StudipMail();
         $success    = $mail->addRecipient($empfaenger_mail)
-             ->setSenderEmail( $sender )
-             ->setSenderName( 'Stud.IP' )
+             ->setSenderEmail($sender)
+             ->setSenderName('Stud.IP')
              ->setSubject($betreff)
              ->setBodyHtml($mailtext)
              ->setBodyHtml(strip_tags($mailtext))
@@ -236,37 +236,33 @@ class StundenzettelTimesheet extends \SimpleORMap
 
     function is_supervisor($user)
     {
-        if ($this->contract->supervisor == $user->user_id) {
-             return true;
-         } else return false;
+        return $this->contract->supervisor_id == $user->user_id;
     }
 
-    function can_edit($user) {
-         if (($this->contract->user_id == $user->user_id) && !$this->locked) {
-             return true;
-         } else return false;
+    function can_edit($user)
+    {
+        return $this->contract->user_id == $user->user_id && !$this->locked;
     }
 
     //TODO InstAdmin identifizieren und Zugriff erlauben
     function can_read($user) {
         if ($this->contract->can_read($user)) {
             if ($this->contract->user_id == $user->user_id ||
-                    (($this->contract->supervisor == $user->user_id) && $this->finished)) {
+                $this->contract->supervisor_id == $user->user_id && $this->finished) {
                 return true;
             }
         }
+        return false;
     }
 
     function calculate_sum() {
-        //if (!$this->locked) {
-            $records = StundenzettelRecord::findByTimesheet_Id($this->id);
-            $sum = 0;
-            foreach ($records as $record) {
-                $sum += $record->sum;
-            }
-            $this->sum = $sum;
-            $this->store();
-        //}
+        $records = StundenzettelRecord::findByTimesheet_Id($this->id);
+        $sum = 0;
+        foreach ($records as $record) {
+            $sum += $record->sum;
+        }
+        $this->sum = $sum;
+        $this->store();
     }
 
     //wird für vacation Berechnung noch benutzt
diff --git a/views/index/index.php b/views/index/index.php
index 9b37a26..b6946b0 100644
--- a/views/index/index.php
+++ b/views/index/index.php
@@ -2,16 +2,12 @@
 
 <? if ($adminrole) : ?>
     <? foreach ($inst_ids as $inst_id) : ?>
-        <? if ($adminrole) : ?>
-           <h2>
-               <a  href='<?=$this->controller->link_for('index/edit_institute_settings/' . $inst_id) ?>' title='<?= $controller->_('Konfiguration bearbeiten') ?>' data-dialog='size=auto'>
-                   <?=Icon::create('edit')?>
-               </a>
-               <?= htmlready(Institute::find($inst_id)->name) ?>
-            </h2>
-        <? else : ?>
-            <h2><?= $controller->_('Studentische MitarbeiterInnen') ?></h2>
-        <? endif ?>
+        <h2>
+           <a  href='<?=$controller->link_for('index/edit_institute_settings/' . $inst_id) ?>' title='<?= $controller->_('Konfiguration bearbeiten') ?>' data-dialog='size=auto'>
+               <?=Icon::create('edit')?>
+           </a>
+           <?= htmlready(Institute::find($inst_id)->name) ?>
+        </h2>
         <? foreach ($groups[$inst_id] as $group) : ?>
            <? if ($group->id) : ?>
                 <? $group_id = $group->id; ?> <!-- echte Gruppe -->
@@ -22,16 +18,15 @@
             <table id='stumi-contract-entries' class="sortable-table default" data-sortlist="[[0,0]]">
                 <thead>
                     <tr>
-                        <th data-sort="text" style='width:10%'><?= $controller->_('Nachname, Vorname') ?></th>
-                        <th data-sort="htmldata" style='width:10%'><?= $controller->_('Vertragsbeginn') ?></th>
-                        <th data-sort="htmldata" style='width:10%'><?= $controller->_('Vertragsende') ?></th>
-                        <th data-sort="digit" style='width:7%'><?= $controller->_('Monatsstunden/Tagessatz') ?></th>
-                        <th data-sort="digit" style='width:7%'><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
-                        <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Urlaub in Anspruch genommen %s'), date('Y')) ?></th>
-                        <th data-sort="digit" style='width:7%'><?= sprintf($controller->_('Resturlaub %s'), date('Y')) ?></th>
-                        <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Urlaubsanspruch %s'), date('Y')) ?></th>
-                        <th data-sort="digit" style='width:10%'><?= sprintf($controller->_('Resturlaub %s zu Jahresbeginn'), date('Y')-1) ?></th>
-                        <th data-sort="text" style='width:10%'><?= $controller->_('Verantwortliche/r MA') ?></th>
+                        <th data-sort="text"><?= $controller->_('Nachname, Vorname') ?></th>
+                        <th data-sort="htmldata"><?= $controller->_('Vertragsbeginn') ?></th>
+                        <th data-sort="htmldata"><?= $controller->_('Vertragsende') ?></th>
+                        <th data-sort="digit"><?= $controller->_('Stunden') ?></th>
+                        <th data-sort="digit"><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
+                        <th data-sort="false"><?= sprintf($controller->_('Urlaub in %s'), date('Y')) ?></th>
+                        <th data-sort="digit"><?= sprintf($controller->_('Resturlaub %s'), date('Y')) ?></th>
+                        <th data-sort="false"><?= sprintf($controller->_('Urlaubsanspruch %s'), date('Y')) ?></th>
+                        <th data-sort="text"><?= $controller->_('Verantwortliche/r MA') ?></th>
                         <th class="actions"><?= $controller->_('Aktionen') ?></th>
                     </tr>
                 </thead>
@@ -40,7 +35,7 @@
                     <? if ($inst_data[$inst_id][$group_id]['stumi_contracts'][$stumi->user_id]) : ?>
                         <? foreach ($inst_data[$inst_id][$group_id]['stumi_contracts'][$stumi->user_id] as $contract): ?>
                         <tr>
-                            <td><a href='<?=$this->controller->link_for('timesheet/index/' . $contract->id) ?>' ><?= htmlready($stumi->nachname) ?>, <?= htmlready($stumi->vorname) ?></a>
+                            <td><a href='<?=$controller->link_for('timesheet/index/' . $contract->id) ?>' ><?= htmlready($stumi->nachname) ?>, <?= htmlready($stumi->vorname) ?></a>
                             </td>
                             <td data-sort-value="<?= $contract->contract_begin ?>"><?= date('d.m.Y', $contract->contract_begin) ?>
                                 <? if ($contract->begin_digital_recording_month && $contract->begin_digital_recording_year) : ?>
@@ -49,7 +44,7 @@
                                 <? endif ?>
                             </td>
                             <td data-sort-value="<?= $contract->contract_end ?>"><?= date('d.m.Y', $contract->contract_end) ?></td>
-                            <td><?= htmlready($contract->contract_hours) ?> / <?= htmlready($contract->default_workday_time) ?></td>
+                            <td><?= htmlready($contract->contract_hours) ?></td>
                             <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getWorktimeBalance())) ?></td>
                             <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getClaimedVacation(date('Y'))))?></td>
                             <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacation(date('Y'))))?></td>
@@ -57,21 +52,28 @@
                                 <?= Icon::create('info-circle', Icon::ROLE_CLICKABLE,
                                             ['title' => $controller->_('Davon aus diesem Vertrag erworbener Anspruch') . ': ' . htmlready($contract->getVacationEntitlement(date('Y'))) ]);?>
                             </td>
-                            <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacationAtEndOfYear(date('Y')-1)))?></td>
-                            <td><?= htmlready(sprintf('%s %s', User::find($contract->supervisor)->vorname, User::find($contract->supervisor)->nachname)) ?></td>
-                            <td>
-                                <? if ($adminrole) : ?>
-                                    <a data-confirm='<?= $controller->_('Eintrag löschen?') ?>' href='<?=$this->controller->link_for('index/delete/' . $contract->id) ?>' title='Eintrag löschen' ><?=Icon::create('trash')?></a>
-                                    <a  href='<?=$this->controller->link_for('index/edit/' . $contract->id) ?>' title='<?= $controller->_('Vertragsdaten bearbeiten') ?>' data-dialog='size=auto'><?=Icon::create('edit')?></a>
-                                    <a  href='<?=$this->controller->link_for('index/add_contract_begin_data/' . $contract->id) ?>' title='<?= $controller->_('Zeitpunkt für Beginn digitaler Erfassung definieren') ?>' data-dialog='size=auto'><?=Icon::create('date')?></a>
-                                    <a  href='<?=$this->controller->link_for('index/edit/'. $contract->id . '/1') ?>' title='<?= $controller->_('Folgevertrag anlegen') ?>' data-dialog='size=auto'><?=Icon::create('add')?></a>
-                                    <? endif ?>
+                            <td><?= htmlready($contract->supervisor->getFullName('no_title_rev')) ?></td>
+                            <td class="actions">
+                                <? $menu = ActionMenu::get() ?>
+                                <? $menu->addLink($controller->url_for('index/edit', $contract->id),
+                                       $controller->_('Vertragsdaten bearbeiten'), Icon::create('edit'), ['data-dialog' => 'size=auto']
+                                   ) ?>
+                                <? $menu->addLink($controller->url_for('index/add_contract_begin_data', $contract->id),
+                                       $controller->_('Beginn digitaler Erfassung definieren'), Icon::create('date'), ['data-dialog' => 'size=auto']
+                                   ) ?>
+                                <? $menu->addLink($controller->url_for('index/edit', $contract->id, 1),
+                                       $controller->_('Folgevertrag anlegen'), Icon::create('add'), ['data-dialog' => 'size=auto']
+                                   ) ?>
+                                <? $menu->addLink($controller->url_for('index/delete', $contract->id),
+                                       $controller->_('Eintrag löschen'), Icon::create('trash'), ['data-confirm' => $controller->_('Eintrag löschen?')]
+                                   ) ?>
+                                <?= $menu->render() ?>
                             </td>
 
                         </tr>
                         <? endforeach ?>
 
-                   <? elseif ($adminrole) : ?>
+                   <? else : ?>
                         <tr>
                             <td><?= htmlready($stumi->nachname) ?>, <?= htmlready($stumi->vorname) ?>
                             </td>
@@ -83,11 +85,14 @@
                             <td> -- </td>
                             <td> -- </td>
                             <td> -- </td>
-                            <td> -- </td>
-                            <td>
-                               <a  href='<?=$this->controller->link_for('index/new/'. $inst_id . '/' . $stumi->user_id) ?>' title='<?= $controller->_('Vertrag hinzufügen') ?>' data-dialog='size=auto'><?=Icon::create('add')?></a>
+                            <td class="actions">
+                                <? $menu = ActionMenu::get() ?>
+                                <? $menu->addLink($controller->url_for('index/new', $inst_id, $stumi->user_id),
+                                       $controller->_('Vertrag hinzufügen'), Icon::create('add'), ['data-dialog' => 'size=auto']
+                                   ) ?>
+                                <?= $menu->render() ?>
                             </td>
-                            </tr>
+                        </tr>
 
                     <? endif ?>
                 <? endforeach ?>
@@ -97,62 +102,56 @@
         <? endforeach ?>
     <? endforeach ?>
 
-<? elseif ( $supervisorrole ) : ?>
+<? elseif ($supervisorrole) : ?>
     <h2><?= $controller->_('Vertragsdaten Hilfskräfte') ?></h2>
-        <table id='stumi-contract-entries' class="sortable-table default" data-sortlist="[[0,0]]">
-            <thead>
-                <tr>
-                    <th data-sort="text" style='width:10%'><?= $controller->_('Nachname, Vorname') ?></th>
-                    <th data-sort="htmldata" style='width:10%'><?= $controller->_('Vertragsbeginn') ?></th>
-                    <th data-sort="htmldata" style='width:10%'><?= $controller->_('Vertragsende') ?></th>
-                    <th data-sort="digit" style='width:7%'><?= $controller->_('Monatsstunden/Tagessatz') ?></th>
-                    <th data-sort="digit" style='width:7%'><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
-                    <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Urlaub in Anspruch genommen %s'), date('Y')) ?></th>
-                    <th data-sort="digit" style='width:7%'><?= sprintf($controller->_('Resturlaub %s'), date('Y')) ?></th>
-                    <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Urlaubsanspruch %s'), date('Y')) ?></th>
-                    <th data-sort="digit" style='width:10%'><?= sprintf($controller->_('Resturlaub %s zu Jahresbeginn'), date('Y')-1) ?></th>
-                </tr>
-            </thead>
-            <tbody>
-            <? foreach ($stumis as $stumi): ?>
-                <? foreach ($stumi_contracts[$stumi->user_id] as $contract): ?>
-                <tr>
-                    <td><a href='<?=$this->controller->link_for('timesheet/index/' . $contract->id) ?>' title='<?= $controller->_('Stundenzettel einsehen') ?>'><?= htmlready($stumi->nachname) ?>, <?= htmlready($stumi->vorname) ?></a>
-                    </td>
-                    <td data-sort-value="<?= $contract->contract_begin ?>"><?= date('d.m.Y', $contract->contract_begin) ?>
-                        <? if ($contract->begin_digital_recording_month && $contract->begin_digital_recording_year) : ?>
-                            <?= Icon::create('info-circle', Icon::ROLE_CLICKABLE,
-                                    ['title' => $controller->_('Beginn der elektronischen Erfassung') . ': ' . $contract->begin_digital_recording_month . '/' . $contract->begin_digital_recording_year ]);?>
-                        <? endif ?>
-                    </td>
-                    <td data-sort-value="<?= $contract->contract_end ?>"><?= date('d.m.Y', $contract->contract_end) ?></td>
-                    <td><?= htmlready($contract->contract_hours) ?> / <?= htmlready($contract->default_workday_time) ?></td>
-                    <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getWorktimeBalance())) ?></td>
-                    <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getClaimedVacation(date('Y'))))?></td>
-                    <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacation(date('Y'))))?></td>
-                    <td><?= htmlready($contract->getVacationEntitlement(date('Y')))?></td>
-                    <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacationAtEndOfYear(date('Y')-1)))?></td>
-
-                </tr>
-                <? endforeach ?>
+    <table id='stumi-contract-entries' class="sortable-table default" data-sortlist="[[0,0]]">
+        <thead>
+            <tr>
+                <th data-sort="text"><?= $controller->_('Nachname, Vorname') ?></th>
+                <th data-sort="htmldata"><?= $controller->_('Vertragsbeginn') ?></th>
+                <th data-sort="htmldata"><?= $controller->_('Vertragsende') ?></th>
+                <th data-sort="digit"><?= $controller->_('Stunden') ?></th>
+                <th data-sort="digit"><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
+                <th data-sort="false"><?= sprintf($controller->_('Urlaub in %s'), date('Y')) ?></th>
+                <th data-sort="digit"><?= sprintf($controller->_('Resturlaub %s'), date('Y')) ?></th>
+                <th data-sort="false"><?= sprintf($controller->_('Urlaubsanspruch %s'), date('Y')) ?></th>
+            </tr>
+        </thead>
+        <tbody>
+        <? foreach ($stumis as $stumi): ?>
+            <? foreach ($stumi_contracts[$stumi->user_id] as $contract): ?>
+            <tr>
+                <td><a href='<?=$controller->link_for('timesheet/index/' . $contract->id) ?>' title='<?= $controller->_('Stundenzettel einsehen') ?>'><?= htmlready($stumi->nachname) ?>, <?= htmlready($stumi->vorname) ?></a>
+                </td>
+                <td data-sort-value="<?= $contract->contract_begin ?>"><?= date('d.m.Y', $contract->contract_begin) ?>
+                    <? if ($contract->begin_digital_recording_month && $contract->begin_digital_recording_year) : ?>
+                        <?= Icon::create('info-circle', Icon::ROLE_CLICKABLE,
+                                ['title' => $controller->_('Beginn der elektronischen Erfassung') . ': ' . $contract->begin_digital_recording_month . '/' . $contract->begin_digital_recording_year ]);?>
+                    <? endif ?>
+                </td>
+                <td data-sort-value="<?= $contract->contract_end ?>"><?= date('d.m.Y', $contract->contract_end) ?></td>
+                <td><?= htmlready($contract->contract_hours) ?></td>
+                <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getWorktimeBalance())) ?></td>
+                <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getClaimedVacation(date('Y'))))?></td>
+                <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacation(date('Y'))))?></td>
+                <td><?= htmlready($contract->getVacationEntitlement(date('Y')))?></td>
+            </tr>
             <? endforeach ?>
-            </tbody>
-        </table>
-
-
+        <? endforeach ?>
+        </tbody>
+    </table>
 <? elseif ($stumirole) : ?>
-    <h2> Meine Verträge </h2>
+    <h2><?= $controller->_('Meine Verträge') ?></h2>
     <table id='stumi-contract-entries' class="sortable-table default" data-sortlist="[[0,0]]">
         <thead>
             <tr>
-                <th data-sort="text" style='width:10%'><?= $controller->_('Institut/Organisationseinheit') ?></th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Vertragsbeginn') ?></th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Vertragsende') ?></th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Stunden lt. Vertrag') ?></th>
-                <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
-<!--                <th data-sort="false" style='width:10%'><?= sprintf($controller->_('Resturlaub/Urlaubsanspruch %s'), date('Y')) ?></th>                -->
-                <th data-sort="text" style='width:10%'><?= $controller->_('Verantwortliche/r MA') ?></th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Aktionen') ?></th>
+                <th data-sort="text"><?= $controller->_('Institut/Organisationseinheit') ?></th>
+                <th data-sort="false"><?= $controller->_('Vertragsbeginn') ?></th>
+                <th data-sort="false"><?= $controller->_('Vertragsende') ?></th>
+                <th data-sort="false"><?= $controller->_('Stunden lt. Vertrag') ?></th>
+                <th data-sort="false"><?= sprintf($controller->_('Stundenkonto (exkl. %s)'), strftime('%B')) ?></th>
+                <th data-sort="text"><?= $controller->_('Verantwortliche/r MA') ?></th>
+                <th class="actions"><?= $controller->_('Aktionen') ?></th>
             </tr>
         </thead>
         <tbody>
@@ -168,18 +167,16 @@
                     <td><?= date('d.m.Y', $contract->contract_end) ?></td>
                     <td><?= htmlready($contract->contract_hours) ?></td>
                     <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getWorktimeBalance())) ?></td>
-<!--                    <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getRemainingVacation(date('Y')))) ?>/<?= htmlready($contract->getVacationEntitlement(date('Y'))) ?></td>-->
-                    <td title='<?= User::find($contract->supervisor)->username ?>'><?= sprintf('%s %s', User::find($contract->supervisor)->vorname, User::find($contract->supervisor)->nachname) ?></td>
-                    <td>
-                        <a data-dialog
-                            href="<?= URLHelper::getLink('dispatch.php/messages/write', ['rec_uname' => $contract->supervisor->username]) ?>"
-                            title="<?= $controller->_('eMail an verantwortliche/n MA') ?>">
-                            <?= Icon::create('mail') ?>
-                        </a>
-                        <a href="<?=PluginEngine::getUrl($plugin, [], 'timesheet/index/' . $contract->id )?>"
-                            title="<?= $controller->_('Zu den Stundenzetteln') ?>">
-                            <?= Icon::create('files') ?>
-                        </a>
+                    <td><?= htmlready($contract->supervisor->getFullName('no_title_rev')) ?></td>
+                    <td class="actions">
+                        <? $menu = ActionMenu::get() ?>
+                        <? $menu->addLink(URLHelper::getURL('dispatch.php/messages/write', ['rec_uname' => $contract->supervisor->username]),
+                               $controller->_('Nachricht an verantwortliche/n MA'), Icon::create('mail'), ['data-dialog' => '']
+                           ) ?>
+                        <? $menu->addLink($controller->url_for('timesheet/index', $contract->id),
+                               $controller->_('Zu den Stundenzetteln'), Icon::create('files')
+                           ) ?>
+                        <?= $menu->render() ?>
                     </td>
                 </tr>
             <? endforeach ?>
diff --git a/views/index/new.php b/views/index/new.php
index 99f5095..0e96def 100644
--- a/views/index/new.php
+++ b/views/index/new.php
@@ -35,6 +35,11 @@ use Studip\Button, Studip\LinkButton;
                value='<?= ($contract) ? htmlready($contract->contract_hours) : ''?>'>
     </label>
 
+    <label>
+        <?= $controller->_('Beschreibung (optional)') ?>
+        <textarea name="description"><?= $contract ? htmlready($contract->description) : '' ?></textarea>
+    </label>
+
     <label>
         <?= $controller->_('Verantwortliche/r Mitarbeiter/in') ?>
         <?= $search ?>
diff --git a/views/timesheet/admin_index.php b/views/timesheet/admin_index.php
index 82dd48c..ac21153 100644
--- a/views/timesheet/admin_index.php
+++ b/views/timesheet/admin_index.php
@@ -20,10 +20,11 @@
     <table id='stumi-timesheet-entries' class="sortable-table default" data-sortlist="[[0,0]]">
         <thead>
             <tr>
-                <th data-sort="text" style='width:10%'><?= $controller->_('Nachname, Vorname') ?></th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Stundenkonto') ?></th>
-                <th data-sort="htmldata" style='width:10%'><?= $controller->_('Status') ?></br><?= $controller->_('Stundenzettel') ?></br><?= strftime("%B", mktime(0, 0, 0, $month, 10))?> </th>
-                <th data-sort="false" style='width:10%'><?= $controller->_('Aktionen') ?></th>
+                <th data-sort="text"><?= $controller->_('Nachname, Vorname') ?></th>
+                <th data-sort="digit"><?= $controller->_('Stundenkonto') ?></th>
+                <th data-sort="text"><?= $controller->_('Verantwortliche/r MA') ?></th>
+                <th data-sort="htmldata"><?= $controller->_('Status') ?></th>
+                <th class="actions"><?= $controller->_('Aktionen') ?></th>
             </tr>
         </thead>
         <tbody>
@@ -32,45 +33,49 @@
                 <tr>
                     <? $timesheet = $timesheets[$contract->id]; ?>
                     <td>
-                        <a href='<?=$this->controller->link_for('timesheet/select/' . $contract->id, $month, $year) ?>' title='<?= $controller->_('Stundenzettel einsehen') ?>'><?= htmlready($contract->stumi->nachname) ?>, <?= htmlready($contract->stumi->vorname) ?></a>
+                        <a href='<?=$controller->link_for('timesheet/select/' . $contract->id, $month, $year) ?>' title='<?= $controller->_('Stundenzettel einsehen') ?>'><?= htmlready($contract->stumi->nachname) ?>, <?= htmlready($contract->stumi->vorname) ?></a>
                     </td>
                     <td><?= htmlready(StundenzettelTimesheet::stundenzettel_strftimespan($contract->getWorktimeBalance())) ?></td>
-                    <td data-sort-value= <?= htmlready($timesheet->int_status) ?> >
+                    <td><?= htmlready($contract->supervisor->getFullName('no_title_rev')) ?></td>
+                    <td data-sort-value="<?= htmlready($timesheet->int_status) ?>">
                         <? if ($timesheet) : ?>
                             <?= Icon::create($status_infos['finished']['icon'], $status_infos[$timesheet->getCurrentState('finished', 'admin') . '_icon_role'], ['title' =>  $status_infos['finished'][$timesheet->getCurrentState('finished', 'admin') . '_tooltip']] )?>
                             <?= Icon::create($status_infos['approved']['icon'], $status_infos[$timesheet->getCurrentState('approved', 'admin') . '_icon_role'], ['title' =>  $status_infos['approved'][$timesheet->getCurrentState('approved', 'admin') . '_tooltip']] )?>
                             <?= Icon::create($status_infos['complete']['icon'], $status_infos[$timesheet->getCurrentState('complete', 'admin') . '_icon_role'], ['title' =>  $status_infos['complete'][$timesheet->getCurrentState('complete', 'admin') . '_tooltip']] )?>
                         <? else : ?>
                             <?= Icon::create($status_infos['finished']['icon'], Icon::ROLE_INACTIVE, ['title' => $controller->_('Stundenzettel noch nicht angelegt')])?>
-                            <?= Icon::create($status_infos['approved']['icon'], Icon::ROLE_INACTIVE, ['title' =>  $controller->_('Stundenzettel noch nicht angelegt')] )?>
-                            <?= Icon::create($status_infos['complete']['icon'], Icon::ROLE_INACTIVE, ['title' =>  $controller->_('Stundenzettel noch nicht angelegt')] )?>
+                            <?= Icon::create($status_infos['approved']['icon'], Icon::ROLE_INACTIVE, ['title' => $controller->_('Stundenzettel noch nicht angelegt')] )?>
+                            <?= Icon::create($status_infos['complete']['icon'], Icon::ROLE_INACTIVE, ['title' => $controller->_('Stundenzettel noch nicht angelegt')] )?>
                         <? endif ?>
                     </td>
-                    <td>
-                        <a data-dialog
-                            href="<?= URLHelper::getLink('dispatch.php/messages/write', ['rec_uname' => $contract->stumi->username]) ?>"
-                            title="<?= $controller->_('eMail an Hilfskraft') ?>">
-                            <?= Icon::create('mail') ?>
-                        </a>
+                    <td class="actions">
+                        <? $menu = ActionMenu::get() ?>
+                        <? $menu->addLink(URLHelper::getURL('dispatch.php/messages/write', ['rec_uname' => $contract->stumi->username]),
+                               $controller->_('Nachricht an Hilfskraft'), Icon::create('mail'), ['data-dialog' => '']
+                           ) ?>
+                        <? $menu->addLink(URLHelper::getURL('dispatch.php/messages/write', ['rec_uname' => $contract->supervisor->username]),
+                               $controller->_('Nachricht an verantwortlichen MA'), Icon::create('mail'), ['data-dialog' => '']
+                           ) ?>
                         <? if ($timesheet) : ?>
                             <? if ($timesheet->finished) : ?>
-                                <a href="<?= PluginEngine::getLink($plugin, [], 'timesheet/unlock/' . $timesheet->id ) ?>" data-confirm="<?= $controller->_('Einreichen Rückgängig machen? Der Stumi kann diesen Stundnezettel dann wieder bearbeiten und Sie haben erst wieder Zugriff wenn dieser erneut eingereicht wurde.') ?>">
-                                    <?= Icon::create('rotate-left', ['title' =>  $controller->_('Einreichen rückgängig machen')] )?>
-                                </a>
+                                <? $menu->addLink($controller->url_for('timesheet/unlock', $timesheet->id),
+                                       $controller->_('Einreichen rückgängig machen'), Icon::create('rotate-left'),
+                                       ['data-confirm' => $controller->_('Einreichen rückgängig machen? Der Stumi kann diesen Stundenzettel dann wieder bearbeiten und Sie haben erst Zugriff, wenn dieser erneut eingereicht wurde.')]
+                                   ) ?>
                                 <? if (!$timesheet->approved) : ?>
-                                    <a href='<?=$this->controller->link_for('timesheet/approve/' . $timesheet->id) ?>'
-                                        title='<?= $controller->_("Korrektheit der Angaben bestätigen") ?>'>
-                                        <?= Icon::create($status_infos['approved']['icon']) ?>
-                                    </a>
+                                    <? $menu->addLink($controller->url_for('timesheet/approve', $timesheet->id),
+                                           $controller->_('Korrektheit der Angaben bestätigen'), Icon::create($status_infos['approved']['icon'])
+                                       ) ?>
                                 <? endif ?>
                             <? endif ?>
                             <? if ($adminrole) : ?>
-                                <a href='<?=$this->controller->link_for('timesheet/complete/' . $timesheet->id) ?>'
-                                    title='<?= ($timesheet->complete) ? $controller->_('Vorgang wieder öffnen') : $controller->_('Vorgang abschließen') ?>'>
-                                    <?= Icon::create($status_infos['complete']['icon']) ?>
-                                </a>
+                                <? $menu->addLink($controller->url_for('timesheet/complete', $timesheet->id),
+                                       $timesheet->complete ? $controller->_('Vorgang wieder öffnen') : $controller->_('Vorgang abschließen'),
+                                       Icon::create($status_infos['complete']['icon'])
+                                   ) ?>
                             <? endif ?>
                         <? endif ?>
+                        <?= $menu->render() ?>
                     </td>
                 </tr>
                 <? endforeach ?>
diff --git a/views/timesheet/index.php b/views/timesheet/index.php
index 41af435..0bbead4 100644
--- a/views/timesheet/index.php
+++ b/views/timesheet/index.php
@@ -17,11 +17,11 @@
     <table id='stumi-timesheet-entries' class="default">
         <thead>
             <tr>
-                <th style='width:10%'><?= $controller->_('Monat/Jahr') ?></th>
-                <th style='width:10%'><?= $controller->_('Erfasste Stunden') ?></th>
-                <th style='width:10%'><?= $controller->_('davon Urlaub') ?></th>
-                <th style='width:10%'><?= $controller->_('Status') ?></th>
-                <th style='width:10%'><?= $controller->_('Aktionen') ?></th>
+                <th><?= $controller->_('Monat/Jahr') ?></th>
+                <th><?= $controller->_('Erfasste Stunden') ?></th>
+                <th><?= $controller->_('Urlaub') ?></th>
+                <th><?= $controller->_('Status') ?></th>
+                <th class="actions"><?= $controller->_('Aktionen') ?></th>
             </tr>
         </thead>
         <tbody>
@@ -29,7 +29,7 @@
                 <? foreach ($timesheets as $timesheet): ?>
                 <tr>
                     <td>
-                        <a href='<?=$this->controller->link_for('timesheet/timesheet/' . $timesheet->id) ?>' title='<?= $controller->_('Stundenzettel editieren') ?>'>
+                        <a href='<?=$controller->link_for('timesheet/timesheet/' . $timesheet->id) ?>' title='<?= $controller->_('Stundenzettel editieren') ?>'>
                             <?= strftime("%B", mktime(0, 0, 0, $timesheet->month, 10)) ?>
                             <?= htmlready($timesheet->year) ?>
                         </a>
@@ -41,25 +41,27 @@
                         <?= Icon::create($status_infos['approved']['icon'], $status_infos[$timesheet->getCurrentState('approved', $role) . '_icon_role'], ['title' =>  $status_infos['approved'][$timesheet->getCurrentState('approved', $role) . '_tooltip']] )?>
                         <?= Icon::create($status_infos['complete']['icon'], $status_infos[$timesheet->getCurrentState('complete', $role) . '_icon_role'], ['title' =>  $status_infos['complete'][$timesheet->getCurrentState('complete', $role) . '_tooltip']] )?>
                     </td>
-                    <td>
+                    <td class="actions">
                         <? if ($timesheet) : ?>
+                            <? $menu = ActionMenu::get() ?>
                             <? if ($timesheet->finished) : ?>
-                                <a href="<?= PluginEngine::getLink($plugin, [], 'timesheet/unlock/' . $timesheet->id ) ?>" data-confirm="<?= $controller->_('Einreichen Rückgängig machen? Der Stumi kann diesen Stundnezettel dann wieder bearbeiten und Sie haben erst wieder Zugriff wenn dieser erneut eingereicht wurde.') ?>">
-                                    <?= Icon::create('rotate-left', ['title' =>  $controller->_('Einreichen rückgängig machen')] )?>
-                                </a>
+                                <? $menu->addLink($controller->url_for('timesheet/unlock', $timesheet->id),
+                                       $controller->_('Einreichen rückgängig machen'), Icon::create('rotate-left'),
+                                       ['data-confirm' => $controller->_('Einreichen rückgängig machen? Der Stumi kann diesen Stundenzettel dann wieder bearbeiten und Sie haben erst Zugriff, wenn dieser erneut eingereicht wurde.')]
+                                   ) ?>
                                 <? if (!$timesheet->approved) : ?>
-                                    <a href='<?=$this->controller->link_for('timesheet/approve/' . $timesheet->id) ?>'
-                                        title='<?= $controller->_("Korrektheit der Angaben bestätigen") ?>'>
-                                        <?= Icon::create($status_infos['approved']['icon']) ?>
-                                    </a>
+                                    <? $menu->addLink($controller->url_for('timesheet/approve', $timesheet->id),
+                                           $controller->_('Korrektheit der Angaben bestätigen'), Icon::create($status_infos['approved']['icon'])
+                                       ) ?>
                                 <? endif ?>
                             <? endif ?>
                             <? if ($adminrole) : ?>
-                                <a href='<?=$this->controller->link_for('timesheet/complete/' . $timesheet->id) ?>'
-                                    title='<?= ($timesheet->complete) ? $controller->_('Vorgang wieder öffnen') : $controller->_('Vorgang abschließen') ?>'>
-                                    <?= Icon::create($status_infos['complete']['icon']) ?>
-                                </a>
+                                <? $menu->addLink($controller->url_for('timesheet/complete', $timesheet->id),
+                                       $timesheet->complete ? $controller->_('Vorgang wieder öffnen') : $controller->_('Vorgang abschließen'),
+                                       Icon::create($status_infos['complete']['icon'])
+                                   ) ?>
                             <? endif ?>
+                            <?= $menu->render() ?>
                         <? endif ?>
                     </td>
                 </tr>
@@ -83,12 +85,12 @@
     <table id='stumi-timesheet-entries' class="default">
         <thead>
             <tr>
-                <th style='width:10%'><?= $controller->_('Monat/Jahr') ?></th>
-                <th style='width:10%'><?= $controller->_('Stunden') ?></th>
-                <th style='width:10%'><?= $controller->_('davon Urlaub') ?></th>
-                <th style='width:10%'><?= $controller->_('Überstunden') ?></th>
-                <th style='width:10%'><?= $controller->_('Status') ?></th>
-                <th style='width:10%'><?= $controller->_('Aktionen') ?></th>
+                <th><?= $controller->_('Monat/Jahr') ?></th>
+                <th><?= $controller->_('Stunden') ?></th>
+                <th><?= $controller->_('Urlaub') ?></th>
+                <th><?= $controller->_('Überstunden') ?></th>
+                <th><?= $controller->_('Status') ?></th>
+                <th class="actions"><?= $controller->_('Aktionen') ?></th>
             </tr>
         </thead>
         <tbody>
@@ -96,7 +98,7 @@
                 <? foreach ($timesheets as $timesheet): ?>
                 <tr>
                     <td>
-                        <a href='<?=$this->controller->link_for('timesheet/timesheet/' . $timesheet->id) ?>' title='<?= $controller->_('Stundenzettel editieren') ?>'>
+                        <a href='<?=$controller->link_for('timesheet/timesheet/' . $timesheet->id) ?>' title='<?= $controller->_('Stundenzettel editieren') ?>'>
                             <?= strftime("%B", mktime(0, 0, 0, $timesheet->month, 10)) ?>
                             <?= htmlready($timesheet->year) ?>
                         </a>
@@ -111,11 +113,13 @@
                         -->
                         <?= Icon::create($status_infos['complete']['icon'], $status_infos[$timesheet->getCurrentState('complete', 'stumi') . '_icon_role'], ['title' =>  $status_infos['complete'][$timesheet->getCurrentState('complete', 'stumi') . '_tooltip']] )?>
                     </td>
-                    <td>
+                    <td class="actions">
                         <? if ($timesheet->finished) : ?>
-                        <a href="<?= PluginEngine::getLink($plugin, [], 'timesheet/pdf/' . $timesheet->id ) ?>">
-                            <?= Icon::create('file-pdf', ['title' =>  $controller->_('PDF zum Ausdruck generieren')] )?>
-                        </a>
+                            <? $menu = ActionMenu::get() ?>
+                            <? $menu->addLink($controller->url_for('timesheet/pdf', $timesheet->id),
+                                   $controller->_('PDF zum Ausdruck generieren'), Icon::create('file-pdf')
+                               ) ?>
+                            <?= $menu->render() ?>
                         <? endif ?>
                     </td>
                 </tr>
-- 
GitLab