use dropdown for entity actions on detail pages (#801)
This commit is contained in:
@@ -29,7 +29,7 @@ export default class KimaiAPILink extends KimaiClickHandlerReducedInTableRow {
|
||||
const self = this;
|
||||
document.addEventListener('click', function(event) {
|
||||
let target = event.target;
|
||||
while (!target.matches('body')) {
|
||||
while (target !== null && !target.matches('body')) {
|
||||
if (target.classList.contains(self.selector)) {
|
||||
const attributes = target.dataset;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class KimaiClickHandlerReducedInTableRow extends KimaiPlugin {
|
||||
// we don't want the table row event to be processed - so we intercept it
|
||||
let target = event.target;
|
||||
if (event.currentTarget.matches('tr')) {
|
||||
while (!target.matches('body')) {
|
||||
while (target !== null && !target.matches('body')) {
|
||||
if (target.matches('a') || target.matches ('button')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class KimaiToolbarAction extends KimaiPlugin {
|
||||
const self = this;
|
||||
document.addEventListener('click', function(event) {
|
||||
let target = event.target;
|
||||
while (!target.matches('body')) {
|
||||
while (target !== null && !target.matches('body')) {
|
||||
if (target.classList.contains(self.selector)) {
|
||||
const form = document.querySelector('div.toolbar form.navbar-form');
|
||||
if (form === null) {
|
||||
|
||||
@@ -5,6 +5,19 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
span.label-activity,
|
||||
span.label-project,
|
||||
span.label-customer {
|
||||
display: inline-block;
|
||||
.dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
background-color: $gray-lte;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
table.dataTable {
|
||||
/* action column */
|
||||
.actions {
|
||||
@@ -39,14 +52,6 @@ table.dataTable {
|
||||
span.label-activity,
|
||||
span.label-project,
|
||||
span.label-customer {
|
||||
display: inline-block;
|
||||
.dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
background-color: $gray-lte;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
a {
|
||||
color: unset;
|
||||
padding-bottom: 2px;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"build/app.js": "./app.js?4d1c16b6cec885d40370",
|
||||
"build/app.css": "./app.css?e4b4080f26821060103657b889a6b1cd",
|
||||
"build/app.js": "./app.js?dad0cc8443da0d5789c7",
|
||||
"build/app.css": "./app.css?954c34ace3717cfb9d9c80d2be5f8c68",
|
||||
"build/fonts/fa-solid-900.woff2": "./fonts/fa-solid-900.woff2?e8a92a29",
|
||||
"build/images/fa-solid-900.svg": "./images/fa-solid-900.svg?666a82cb",
|
||||
"build/images/glyphicons-halflings-regular.svg": "./images/glyphicons-halflings-regular.svg?89889688",
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\User;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
/**
|
||||
* Entity specific twig extensions.
|
||||
* Should be used with caution, as they can trigger a lot of DB queries.
|
||||
*/
|
||||
class EntityExtensions extends AbstractExtension
|
||||
{
|
||||
private const UNKNOWN_NAME = '-unknown-';
|
||||
|
||||
/**
|
||||
* @var UserRepository|null
|
||||
*/
|
||||
private $users = null;
|
||||
/**
|
||||
* @var CustomerRepository|null
|
||||
*/
|
||||
private $customers = null;
|
||||
/**
|
||||
* @var ProjectRepository|null
|
||||
*/
|
||||
private $projects = null;
|
||||
/**
|
||||
* @var ActivityRepository|null
|
||||
*/
|
||||
private $activities = null;
|
||||
|
||||
/**
|
||||
* @param UserRepository $users
|
||||
* @param CustomerRepository $customers
|
||||
* @param ProjectRepository $projects
|
||||
* @param ActivityRepository $activities
|
||||
*/
|
||||
public function __construct(UserRepository $users, CustomerRepository $customers, ProjectRepository $projects, ActivityRepository $activities)
|
||||
{
|
||||
$this->users = $users;
|
||||
$this->customers = $customers;
|
||||
$this->projects = $projects;
|
||||
$this->activities = $activities;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('user', [$this, 'getUser']),
|
||||
new TwigFilter('customer', [$this, 'getCustomer']),
|
||||
new TwigFilter('project', [$this, 'getProject']),
|
||||
new TwigFilter('activity', [$this, 'getActivity']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|User $user
|
||||
* @param bool $allowEmpty
|
||||
* @return User|null
|
||||
*/
|
||||
public function getUser($user, $allowEmpty = true)
|
||||
{
|
||||
if ($user instanceof User) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
$entity = $this->users->getById($user);
|
||||
|
||||
if (null === $entity) {
|
||||
$entity = $this->users->loadUserByUsername($user);
|
||||
}
|
||||
|
||||
if (null === $entity && false === $allowEmpty) {
|
||||
$entity = new User();
|
||||
$entity->setUsername(self::UNKNOWN_NAME);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|Customer $customer
|
||||
* @param bool $allowEmpty
|
||||
* @return Customer|null
|
||||
*/
|
||||
public function getCustomer($customer, $allowEmpty = true)
|
||||
{
|
||||
if ($customer instanceof Customer) {
|
||||
return $customer;
|
||||
}
|
||||
|
||||
$entity = $this->customers->getById($customer);
|
||||
|
||||
if (null === $entity && false === $allowEmpty) {
|
||||
$entity = new Customer();
|
||||
$entity->setName(self::UNKNOWN_NAME);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|Project $project
|
||||
* @param bool $allowEmpty
|
||||
* @return Project|null
|
||||
*/
|
||||
public function getProject($project, $allowEmpty = true)
|
||||
{
|
||||
if ($project instanceof Project) {
|
||||
return $project;
|
||||
}
|
||||
|
||||
$entity = $this->projects->getById($project);
|
||||
|
||||
if (null === $entity && false === $allowEmpty) {
|
||||
$entity = new Project();
|
||||
$entity->setName(self::UNKNOWN_NAME);
|
||||
$entity->setCustomer((new Customer())->setName(self::UNKNOWN_NAME));
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|Activity $activity
|
||||
* @param bool $allowEmpty
|
||||
* @return Activity|null
|
||||
*/
|
||||
public function getActivity($activity, $allowEmpty = true)
|
||||
{
|
||||
if ($activity instanceof Activity) {
|
||||
return $activity;
|
||||
}
|
||||
|
||||
$entity = $this->activities->getById($activity);
|
||||
|
||||
if (null === $entity && false === $allowEmpty) {
|
||||
$entity = new Activity();
|
||||
$entity->setName(self::UNKNOWN_NAME);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'customer': activity.project ? activity.project.customer.id : null, 'project': activity.project ? activity.project.id : null, 'activity': activity.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('create_other_timesheet') %}
|
||||
{% set actions = actions|merge({'create-timesheet': path('admin_timesheet_create', {'project': activity.project ? activity.project.id : null, 'activity': activity.id})}) %}
|
||||
{% set actions = actions|merge({'create-timesheet': {'url': path('admin_timesheet_create', {'project': activity.project ? activity.project.id : null, 'activity': activity.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% if view == 'index' and is_granted('delete', activity) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_activity_delete', {'id': activity.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
@@ -35,14 +35,14 @@
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'list': path('admin_activity')}) %}
|
||||
{% set actions = actions|merge({'activity': path('admin_activity')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.activity', {'actions': actions, 'view': view, 'activity': activity}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -127,14 +127,14 @@
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'list': path('admin_project')}) %}
|
||||
{% set actions = actions|merge({'project': path('admin_project')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.project', {'actions': actions, 'view': view, 'project': project}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -180,14 +180,14 @@
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'list': path('admin_customer')}) %}
|
||||
{% set actions = actions|merge({'customer': path('admin_customer')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.customer', {'actions': actions, 'view': view, 'customer': customer}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -247,14 +247,14 @@
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'list': path('timesheet')}) %}
|
||||
{% set actions = actions|merge({'timesheet': path('timesheet')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.timesheet', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{%- endfilter -%}
|
||||
{% endmacro %}
|
||||
@@ -302,14 +302,14 @@
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'list': path('admin_timesheet')}) %}
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.timesheet_team', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
@@ -11,6 +11,15 @@
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro entity_actions(tools) -%}
|
||||
{% import _self as macro %}
|
||||
<div class="breadcrumb">
|
||||
<div class="box-tools">
|
||||
{{ macro.table_actions(tools) }}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro page_header(title) %}
|
||||
<h2 class="page-header">{{ title|trans }}</h2>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
<source>timesheet</source>
|
||||
<target>Stundenzettel</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="customer">
|
||||
<source>customer</source>
|
||||
<target>Kunden</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="project">
|
||||
<source>project</source>
|
||||
<target>Projekte</target>
|
||||
|
||||
@@ -28,7 +28,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="timesheet">
|
||||
<source>timesheet</source>
|
||||
<target>Timesheet</target>
|
||||
<target>Timesheets</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="customer">
|
||||
<source>customer</source>
|
||||
<target>Customers</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="project">
|
||||
<source>project</source>
|
||||
|
||||
Reference in New Issue
Block a user