entity action buttons re-designed (#746)

This commit is contained in:
Kevin Papst
2019-05-03 21:10:16 +02:00
committed by GitHub
parent 455d772095
commit e92c2d168e
22 changed files with 408 additions and 184 deletions

View File

@@ -58,7 +58,7 @@ $(function() {
// edit timesheet - date with time
this.activateDateTimePicker('.content-wrapper');
// some actions can be performed in a modal for a better UX
this.activateAjaxFormInModal('a.modal-ajax-form');
this.activateAjaxFormInModal('.modal-ajax-form');
// activate select boxes that load dynamic data via API
this.activateApiSelects('select[data-related-select]');
},
@@ -312,15 +312,38 @@ $(function() {
},
activateAjaxFormInModal: function(selector) {
$('body').on('click', selector, function(event) {
// just in case an inner element is editable, than this should not be triggered
if (event.target.parentNode.isContentEditable || event.target.isContentEditable) {
return;
}
// handles the "click" on table rows to open an entry for editing: when a button within a row is clicked,
// we don't want the table row event to be processed - so we intercept it
var target = event.target;
if (event.currentTarget.tagName === 'TR') {
while (target.tagName !== 'BODY') {
if (target.tagName === 'A' || target.tagName === 'BUTTON') {
return;
}
target = target.parentNode;
}
}
event.preventDefault();
event.stopPropagation();
// any element can open the modal - for none <a> elements use "data-href" instead of "href" attribute
var href = $(this).attr('data-href');
if (!href) {
href = $(this).attr('href');
}
$.ajax({
url: $(this).attr('href'),
url: href,
success: function(html) {
$.kimai.ajaxFormInModal(html);
},
error: function(xhr, err) {
window.location = $(this).attr('href');
window.location = href;
}
});
});

View File

@@ -266,11 +266,23 @@ div.dataTables_scrollHead table.table-bordered {
}
table.dataTable {
/* action column */
.actions {
width: 90px;
li.delete a {
color: #dd4b39;
}
}
/* summary row, like the timesheet table provides */
tr.summary td {
tr {
&.summary td {
font-weight: bold;
border-bottom: 1px solid #ccc;
}
&.open-edit {
cursor: pointer;
}
}
td {
/*
Make sure that the action buttons do not line-break if another column takes all available space

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"build/app.js": "./app.js?[contenthash]",
"build/app.css": "./app.css?230233ad08d74f0006abee781c0fa499",
"build/app.css": "./app.css?03894379d3cc9cde71d1ce7c0fe24573",
"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",

View File

@@ -9,15 +9,8 @@
namespace App\Twig;
use App\Constants;
use App\Entity\Timesheet;
use App\Utils\Duration;
use App\Utils\LocaleSettings;
use NumberFormatter;
use Symfony\Component\Intl\Intl;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class TitleExtension extends AbstractExtension

View File

@@ -10,7 +10,7 @@
'project': 'hidden-xs',
'comment': 'hidden-xs',
'visible': '',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
} %}
{% set tableName = 'activity_admin' %}
@@ -33,7 +33,7 @@
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_activity_edit', {'id': entry.id}) }}"{% endif %}>
<td>{{ entry.name }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">
{% if entry.project and entry.project.customer %}
@@ -51,7 +51,7 @@
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'comment') }}">{{ entry.comment }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'visible') }}">{{ widgets.label_visible(entry.visible) }}</td>
<td>
<td class="actions">
{{ actions.activity(entry, 'index') }}
</td>
</tr>

View File

@@ -11,7 +11,7 @@
'number': 'hidden-xs',
'currency': 'hidden-xs',
'visible': 'hidden-xs',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
} %}
{% set tableName = 'customer_admin' %}
@@ -33,14 +33,14 @@
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_customer_edit', {'id': entry.id}) }}"{% endif %}>
<td>{{ entry.name }} {% if entry.company is not empty %}({{ entry.company }}){% endif %}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'comment') }}">{{ entry.comment }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'country') }}">{{ entry.country|country }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'number') }}">{{ entry.number }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'currency') }}">{{ entry.currency }} {{ entry.currency|currency }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'visible') }}">{{ widgets.label_visible(entry.visible) }}</td>
<td>
<td class="actions">
{{ actions.customer(entry, 'index') }}
</td>
</tr>

View File

@@ -1,10 +1,10 @@
{% extends 'base.html.twig' %}
{% extends app.request.xmlHttpRequest ? 'form.html.twig' : 'base.html.twig' %}
{% block page_title %}{{ 'admin_invoice_template.title'|trans }}{% endblock %}
{% block page_subtitle %}{{ 'admin_invoice_template.subtitle'|trans }}{% endblock %}
{% block main %}
{{ include('default/_form.html.twig', {
{{ include(app.request.xmlHttpRequest ? 'default/_form_modal.html.twig' : 'default/_form.html.twig', {
'title': template.name|default('create'|trans),
'form': form,
'back': path('admin_invoice_template')

View File

@@ -5,6 +5,7 @@
{% block page_title %}{{ 'admin_invoice_template.title'|trans }}{% endblock %}
{% block page_subtitle %}{{ 'admin_invoice_template.subtitle'|trans }}{% endblock %}
{% block page_actions %}
{# TODO move me to actions macro #}
{% set actions = {} %}
{% if is_granted('create_invoice_template') %}
{% set actions = actions|merge({'create': path('admin_invoice_template_create')}) %}
@@ -12,6 +13,7 @@
{% if is_granted('view_invoice') %}
{% set actions = actions|merge({'invoice': path('invoice')}) %}
{% endif %}
{% set event = trigger('actions.invoice_templates', {'actions': actions, 'view': 'index'}) %}
{{ widgets.page_actions(actions) }}
{% endblock %}
@@ -20,32 +22,38 @@
{{ widgets.callout('warning', 'error.no_entries_found') }}
{% endif %}
{{ tables.data_table_header('invoice_template', {
{% set columns = {
'name': 'alwaysVisible',
'title': '',
'due_days': 'hidden-xs',
'vat': 'hidden-xs',
'actions': 'alwaysVisible',
}) }}
'title': 'hidden-xs',
'due_days': 'hidden-xs hidden-sm',
'vat': 'hidden-xs hidden-sm',
'actions': 'actions alwaysVisible',
} %}
{% set tableName = 'invoice_template' %}
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_invoice_template_edit', {'id' : entry.id, 'page': page}) }}"{% endif %}>
<td>{{ entry.name }}</td>
<td>{{ entry.title }}</td>
<td class="hidden-xs hidden-sm">{{ entry.dueDays }}</td>
<td class="hidden-xs hidden-sm">{{ entry.vat }}</td>
<td>
{% set actionButtons = {} %}
<td class="{{ tables.data_table_column_class(tableName, columns, 'title') }}">{{ entry.title }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'due_days') }}">{{ entry.dueDays }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'vat') }}">{{ entry.vat }}</td>
<td class="actions">
{# TODO move me to actions macro #}
{% set actions = {} %}
{% if is_granted('edit', entry) %}
{% set actionButtons = {'edit': path('admin_invoice_template_edit', {'id' : entry.id, 'page': page})} %}
{% set actions = {'edit': {'url': path('admin_invoice_template_edit', {'id' : entry.id, 'page': page}), 'class': 'modal-ajax-form'}} %}
{% endif %}
{% if is_granted('create_invoice_template') %}
{% set actionButtons = actionButtons|merge({'copy': path('admin_invoice_template_copy', {'id' : entry.id, 'page': page})}) %}
{% set actions = actions|merge({'copy': path('admin_invoice_template_copy', {'id' : entry.id, 'page': page})}) %}
{% endif %}
{% if is_granted('delete', entry) %}
{% set actionButtons = actionButtons|merge({'trash': path('admin_invoice_template_delete', {'id' : entry.id, 'page': page})}) %}
{% set actions = actions|merge({'trash': path('admin_invoice_template_delete', {'id' : entry.id, 'page': page})}) %}
{% endif %}
{{ widgets.button_group(actionButtons) }}
{% set event = trigger('actions.invoice_templates', {'actions': actions, 'view': 'index', 'template': entry}) %}
{{ widgets.table_actions(actions) }}
</td>
</tr>
{% endfor %}

View File

@@ -17,7 +17,11 @@
{% if activity.id is not empty %}
{% if is_granted('edit', activity) %}
{% set actions = actions|merge({'edit': path('admin_activity_edit', {'id': activity.id})}) %}
{% set class = '' %}
{% if view != 'edit' %}
{% set class = 'modal-ajax-form' %}
{% endif %}
{% set actions = actions|merge({'edit': {'url': path('admin_activity_edit', {'id': activity.id}), 'class': class}}) %}
{% 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'}}) %}
@@ -30,7 +34,49 @@
{% set event = trigger('actions.activity', {'actions': actions, 'view': view, 'activity': activity}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
{% endmacro %}
{% macro users(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'filter': '#collapseUserAdmin', 'visibility': '#modal_user_admin'} %}
{% if is_granted('create_user') %}
{% set actions = actions|merge({'create': path('admin_user_create')}) %}
{% endif %}
{% set event = trigger('actions.users', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro user(user, view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% if user.id is not empty %}
{% if is_granted('view', user) %}
{% set actions = {'profile-stats': {'url': path('user_profile', {'username' : user.username})}} %}
{% endif %}
{% if is_granted('edit', user) %}
{% set actions = actions|merge({'edit': path('user_profile_edit', {'username' : user.username})}) %}
{% endif %}
{% if is_granted('preferences', user) %}
{% set actions = actions|merge({'settings': {'url': path('user_profile_preferences', {'username' : user.username})}}) %}
{% endif %}
{% if is_granted('view_other_timesheet') %}
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'user' : user.id})}) %}
{% endif %}
{% if view == 'index' and is_granted('delete', user) %}
{% set actions = actions|merge({'trash': {'url': path('admin_user_delete', {'id': user.id}), 'class': 'modal-ajax-form'}}) %}
{% endif %}
{% endif %}
{% set event = trigger('actions.user', {'actions': actions, 'view': view, 'user': user}) %}
{% if view == 'index' %}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
@@ -54,7 +100,11 @@
{% if project.id is not empty %}
{% if is_granted('edit', project) %}
{% set actions = actions|merge({'edit': path('admin_project_edit', {'id': project.id})}) %}
{% set class = '' %}
{% if view != 'edit' %}
{% set class = 'modal-ajax-form' %}
{% endif %}
{% set actions = actions|merge({'edit': {'url': path('admin_project_edit', {'id': project.id}), 'class': class}}) %}
{% endif %}
{% if is_granted('view_activity') %}
{% set actions = actions|merge({'activity': path('admin_activity', {'customer': project.customer.id, 'project': project.id})}) %}
@@ -70,7 +120,7 @@
{% set event = trigger('actions.project', {'actions': actions, 'view': view, 'project': project}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
@@ -94,7 +144,11 @@
{% if customer.id is not empty %}
{% if is_granted('edit', customer) %}
{% set actions = actions|merge({'edit': path('admin_customer_edit', {'id': customer.id})}) %}
{% set class = '' %}
{% if view != 'edit' %}
{% set class = 'modal-ajax-form' %}
{% endif %}
{% set actions = actions|merge({'edit': {'url': path('admin_customer_edit', {'id': customer.id}), 'class': class}}) %}
{% endif %}
{% if is_granted('view_project') %}
{% set actions = actions|merge({'project': path('admin_project', {'customer': customer.id})}) %}
@@ -110,7 +164,7 @@
{% set event = trigger('actions.customer', {'actions': actions, 'view': view, 'customer': customer}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
@@ -134,6 +188,7 @@
{% endmacro %}
{% macro timesheet(timesheet, view) %}
{%- filter spaceless -%}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
@@ -167,10 +222,11 @@
{% set event = trigger('actions.timesheet', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
{%- endfilter -%}
{% endmacro %}
{% macro timesheets_team(view) %}
@@ -194,10 +250,6 @@
{% set actions = {} %}
{% if timesheet.id is not empty %}
{% if not timesheet.end and is_granted('stop', timesheet) %}
{% set actions = actions|merge({'stop': path('admin_timesheet_stop', {'id' : timesheet.id})}) %}
{% endif %}
{% if is_granted('edit', timesheet) %}
{% set class = '' %}
{% if view != 'edit' %}
@@ -206,6 +258,10 @@
{% set actions = actions|merge({'edit': {'url': path('admin_timesheet_edit', {'id': timesheet.id}), 'class': class}}) %}
{% endif %}
{% if not timesheet.end and is_granted('stop', timesheet) %}
{% set actions = actions|merge({'stop': path('admin_timesheet_stop', {'id' : timesheet.id})}) %}
{% endif %}
{% if view == 'index' and is_granted('delete', timesheet) %}
{% set actions = actions|merge({'trash': {'url': path('admin_timesheet_delete', {'id' : timesheet.id}), 'class': 'modal-ajax-form'}}) %}
{% endif %}
@@ -217,7 +273,7 @@
{% set event = trigger('actions.timesheet_team', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
@@ -239,7 +295,7 @@
{% set event = trigger('actions.plugin', {'actions': actions, 'view': view}) %}
{% if view == 'index' %}
{{ widgets.button_group(event.payload.actions) }}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.page_actions(event.payload.actions) }}
{% endif %}
@@ -256,19 +312,3 @@
{% set event = trigger('actions.about', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro profile(view, user) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'profile-stats': {'url': path('user_profile', {'username' : user.username})}} %}
{% if is_granted('edit', user) %}
{% set actions = actions|merge({'profile': {'url': path('user_profile_edit', {'username' : user.username})}}) %}
{% endif %}
{% if is_granted('preferences', user) %}
{% set actions = actions|merge({'settings': {'url': path('user_profile_preferences', {'username' : user.username})}}) %}
{% endif %}
{% set event = trigger('actions.profile', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -86,7 +86,7 @@
<thead>
<tr>
{%- for title, class in columns -%}
<th data-field="{{ title }}" class="{{ macro.data_table_column_class(name, columns, title) }}">{{ ('label.' ~ title)|trans }}</th>
<th data-field="{{ title }}" class="{{ macro.data_table_column_class(name, columns, title) }}">{% if title is not empty and title != 'actions' %}{{ ('label.' ~ title)|trans }}{% endif %}</th>
{%- endfor -%}
</tr>
</thead>

View File

@@ -140,18 +140,52 @@
</div>
{% endmacro %}
{% macro button_group(actions) %}
{% import _self as macro %}
{% macro table_actions(actions) %}
{%- import _self as macro -%}
{% if actions|length >= 1 %}
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ 'label.actions'|trans }}
<span class="fa fa-caret-down"></span></button>
<ul class="dropdown-menu dropdown-menu-right">
{%- filter spaceless -%}
{%- for icon,values in actions %}
{% spaceless %}
{% set class = '' %}
{% if icon == 'trash' %}
{% set class = 'delete' %}
<li class="divider"></li>
{% endif %}
<li class="{{ class }}">
{% if values is iterable %}
{{ macro.action_button(icon, values|merge({'title': icon|trans({}, 'actions')}), false) }}
{% else %}
{{ macro.action_button(icon, {'url': values, 'title': icon|trans({}, 'actions')}, false) }}
{% endif %}
</li>
{% endfor -%}
{% endfilter %}
</ul>
</div>
{% endif %}
{% endmacro %}
{% macro action_button(icon, values, type) %}
{%- import _self as macro -%}
{%- filter spaceless -%}
{% set id = null %}
{% set onclick = null %}
{% set modal = null %}
{% set toggle = null %}
{% set url = null %}
{% set target = null %}
{% set title = null %}
{% set disabled = false %}
{% if type is same as (false) %}
{% set class = "" %}
{% elseif type is null %}
{% set class = "btn btn-default btn-" ~ icon ~ " " %}
{% else %}
{% set class = "btn btn-" ~ type ~ " btn-" ~ icon ~ " " %}
{% endif %}
{% if not values is iterable %}
{% set url = values %}
@@ -167,16 +201,25 @@
{% set url = '#' %}
{% endif %}
{% else %}
{% set disabled = values.disabled ?? false %}
{% set url = values.url ?? '#' %}
{% set onclick = values.onclick ?? null %}
{% set modal = values.modal ?? null %}
{% set toggle = values.toggle ?? null %}
{% set target = values.target ?? null %}
{% set id = values.id ?? null %}
{% set title = values.title ?? null %}
{% set class = class ~ ( values.class | default("")) %}
{% endif %}
{% endspaceless %}
{% if disabled is same as (true) %}
{% set class = class ~ " disabled" %}
{% endif %}
<a class="{{ class | trim }}" href="{{ url }}"
{%- if disabled is same as (true) -%}
disabled="disabled"
{%- endif -%}
{%- if id is not empty -%}
id="{{ id }}"
{%- endif -%}
@@ -192,8 +235,18 @@
{%- if target is not empty -%}
target="{{ target }}"
{%- endif -%}
>{{ macro.icon(icon) }}</a>
>{% if title is not null %}{{ title }}{% else %}{{ macro.icon(icon) }}{% endif %}</a>
{% endfilter %}
{% endmacro %}
{% macro button_group(actions, type) %}
{%- import _self as macro -%}
<div class="btn-group">
{%- filter spaceless -%}
{%- for icon,values in actions %}
{{ macro.action_button(icon, values, type) }}
{% endfor -%}
{% endfilter %}
</div>
{% endmacro %}

View File

@@ -23,7 +23,7 @@
<th>{{ 'label.version'|trans({}, 'plugins') }}</th>
<th class="hidden-xs">{{ 'label.description'|trans }}</th>
<th class="hidden-xs hidden-sm">{{ 'label.required_version'|trans({}, 'plugins') }}</th>
<th>{{ 'label.actions'|trans }}</th>
<th class="actions"></th>
</tr>
</thead>
<tbody>

View File

@@ -10,7 +10,7 @@
'comment': 'hidden-xs hidden-sm',
'budget': 'hidden-xs',
'visible': '',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
} %}
{% set tableName = 'project_admin' %}
@@ -32,7 +32,7 @@
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_project_edit', {'id': entry.id}) }}"{% endif %}>
<td>{{ entry.name }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">
<a href="{{ path('admin_customer_edit', {'id' : entry.customer.id}) }}">{{ widgets.label_customer(entry.customer) }}</a>
@@ -40,7 +40,7 @@
<td class="{{ tables.data_table_column_class(tableName, columns, 'comment') }}">{{ entry.comment }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'budget') }}">{{ entry.budget|money(entry.customer.currency) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'visible') }}">{{ widgets.label_visible(entry.visible) }}</td>
<td>
<td class="actions">
{{ actions.project(entry, 'index') }}
</td>
</tr>

View File

@@ -5,7 +5,9 @@
{% import "macros/actions.html.twig" as actions %}
{% set duration_only = is_duration_only() %}
{% set columns = {'date': ''} %}
{% set columns = {
'date': 'alwaysVisible',
} %}
{% if not duration_only %}
{% set columns = columns|merge({'starttime': 'hidden-xs', 'endtime': 'hidden-xs'}) %}
@@ -14,12 +16,12 @@
{% set columns = columns|merge({
'duration': '',
'rate': '',
'customer': 'hidden-xs hidden-sm',
'project': 'hidden-xs hidden-sm',
'customer': 'hidden-xs hidden-sm hidden-md',
'project': 'hidden-xs hidden-sm hidden-md',
'activity': 'hidden-xs hidden-sm',
'username': 'hidden-xs',
'description': 'hidden-xs hidden-sm',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
}) %}
{% set tableName = 'timesheet_admin' %}
@@ -41,7 +43,7 @@
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_timesheet_edit', {'id': entry.id}) }}"{% endif %}>
<td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'date') }}">{{ entry.begin|date_short }}</td>
{% if not duration_only %}
@@ -79,7 +81,7 @@
{{ widgets.label_user(entry.user) }}
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }}">{{ entry.description|nl2br }}</td>
<td>
<td class="actions">
{{ actions.timesheet_team(entry, 'index') }}
</td>
</tr>

View File

@@ -3,24 +3,30 @@
{% import "macros/datatables.html.twig" as tables %}
{% import "macros/toolbar.html.twig" as toolbar %}
{% import "macros/actions.html.twig" as actions %}
{% import _self as timesheet %}
{% set tableName = 'timesheet' %}
{% set duration_only = is_duration_only() %}
{% set canSeeRate = is_granted('view_rate_own_timesheet') %}
{% set columns = {'date': 'alwaysVisible'} %}
{% set columns = {
'date': 'alwaysVisible',
} %}
{% if not duration_only %}
{% set columns = columns|merge({'starttime': '', 'endtime': 'hidden-xs'}) %}
{% set columns = columns|merge({
'starttime': '',
'endtime': 'hidden-xs'
}) %}
{% endif %}
{% set columns = columns|merge({'duration': ''}) %}
{% if canSeeRate %}
{% set columns = columns|merge({'rate': 'hidden-xs'}) %}
{% endif %}
{% set columns = columns|merge({
'customer': 'hidden-xs hidden-sm',
'project': 'hidden-xs hidden-sm',
'customer': 'hidden-xs hidden-sm hidden-md',
'project': 'hidden-xs hidden-sm hidden-md',
'activity': 'hidden-xs hidden-sm',
'description': 'hidden-xs hidden-sm',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
}) %}
{% block page_title %}{{ 'timesheet.title'|trans }}{% endblock %}
@@ -33,7 +39,6 @@
{% endblock %}
{% block main %}
{% import _self as timesheet %}
{% if entries.count == 0 %}
{{ widgets.callout('warning', 'error.no_entries_found') }}
{% else %}
@@ -43,17 +48,17 @@
{% set dayDuration = 0 %}
{% set dayRate = {} %}
{% for entry in entries %}
{% set customerCurrency = entry.project.customer.currency %}
{% if day is same as(null) %}
{%- set customerCurrency = entry.project.customer.currency -%}
{%- if day is same as(null) -%}
{% set day = entry.begin|date_short %}
{% endif %}
{% if showSummary and day is not same as(entry.begin|date_short) %}
{{ timesheet.summary(day, dayDuration, dayRate, columns, canSeeRate) }}
{%- if showSummary and day is not same as(entry.begin|date_short) -%}
{{ timesheet.summary(day, dayDuration, dayRate, columns, canSeeRate, duration_only, tableName) }}
{% set day = entry.begin|date_short %}
{% set dayDuration = 0 %}
{% set dayRate = {} %}
{% endif %}
<tr>
{%- endif -%}
<tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit" data-href="{{ path('timesheet_edit', {'id': entry.id}) }}"{% endif %}>
<td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'date') }}">{{ entry.begin|date_short }}</td>
{% if not duration_only %}
@@ -82,21 +87,21 @@
<td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}">{{ widgets.label_project(entry.project) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}">{{ widgets.label_activity(entry.activity) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }} timesheet-description">{{ entry.description|desc2html }}</td>
<td>
{{ actions.timesheet(entry, 'index') }}
<td class="actions">
{{- actions.timesheet(entry, 'index') -}}
</td>
</tr>
{% if entry.end %}
{%- if entry.end -%}
{% if dayRate[customerCurrency] is not defined %}
{% set dayRate = dayRate|merge({(customerCurrency): 0}) %}
{% endif %}
{% set dayRate = dayRate|merge({(customerCurrency): dayRate[customerCurrency] + entry.rate}) %}
{% endif %}
{% set dayDuration = dayDuration + entry.duration %}
{%- endif -%}
{%- set dayDuration = dayDuration + entry.duration -%}
{% endfor %}
{% if showSummary %}
{{ timesheet.summary(day, dayDuration, dayRate, columns, canSeeRate) }}
{{ timesheet.summary(day, dayDuration, dayRate, columns, canSeeRate, duration_only, tableName) }}
{% endif %}
{{ tables.data_table_footer(entries, 'timesheet_paginated') }}
@@ -118,14 +123,17 @@
</script>
{% endblock %}
{% macro summary(day, duration, dayRates, columns, canSeeRate) %}
{% macro summary(day, duration, dayRates, columns, canSeeRate, duration_only, tableName) %}
{% import "macros/datatables.html.twig" as tables %}
<tr class="summary info">
<td class="text-nowrap">{{ day }}</td>
<td></td>
<td></td>
<td class="text-nowrap">{{ duration|duration }}</td>
{% if not duration_only %}
<td class="{{ tables.data_table_column_class(tableName, columns, 'starttime') }}"></td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}"></td>
{% endif %}
<td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'duration') }}">{{ duration|duration }}</td>
{% if canSeeRate %}
<td class="text-nowrap">
<td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'rate') }}">
{% for currency, rate in dayRates %}
{{ rate|money(currency) }}
{% if not loop.last %}
@@ -133,9 +141,11 @@
{% endif %}
{% endfor %}
</td>
<td colspan="{{ (columns|length) - 5 }}"></td>
{% else %}
<td colspan="{{ (columns|length) - 4 }}"></td>
{% endif %}
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}"></td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}"></td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}"></td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }}"></td>
<td class="actions"></td>
</tr>
{% endmacro %}

View File

@@ -2,6 +2,7 @@
{% import "macros/datatables.html.twig" as tables %}
{% import "macros/widgets.html.twig" as widgets %}
{% import "macros/toolbar.html.twig" as toolbar %}
{% import "macros/actions.html.twig" as actions %}
{% set columns = {
'alias': 'alwaysVisible',
@@ -10,20 +11,14 @@
'title': 'hidden-xs',
'roles': 'hidden-xs',
'active': '',
'actions': 'alwaysVisible',
'actions': 'actions alwaysVisible',
} %}
{% set tableName = 'user_admin' %}
{% block page_title %}{{ 'admin_user.title'|trans }}{% endblock %}
{% block page_subtitle %}{{ 'admin_user.subtitle'|trans }}{% endblock %}
{% block page_actions %}
{% set actions = {'filter': '#collapseUserAdmin', 'visibility': '#modal_user_admin'} %}
{% if is_granted('create_user') %}
{% set actions = actions|merge({'create': path('admin_user_create')}) %}
{% endif %}
{{ widgets.page_actions(actions) }}
{% endblock %}
{% block page_actions %}{{ actions.users('index') }}{% endblock %}
{% block main_before %}
{{ toolbar.toolbar(toolbarForm, 'collapseUserAdmin', showFilter) }}
@@ -38,7 +33,7 @@
{{ tables.data_table_header(tableName, columns) }}
{% for entry in entries %}
<tr>
<tr{% if is_granted('edit', entry) %} class="open-edit" onclick="location.href='{{ path('user_profile_edit', {'username': entry.username}) }}'"{% endif %}>
<td>{{ widgets.username(entry) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'username') }}">{{ entry.username }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'email') }}">{{ entry.email }}</td>
@@ -49,18 +44,8 @@
{% endfor %}
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'active') }}">{{ widgets.label_visible(entry.enabled) }}</td>
<td>
{% set actionButtons = {} %}
{% if is_granted('edit', entry) %}
{% set actionButtons = actionButtons|merge({'edit': path('user_profile', {'username' : entry.username})}) %}
{% endif %}
{% if is_granted('view_other_timesheet') %}
{% set actionButtons = actionButtons|merge({'timesheet': path('admin_timesheet', {'user' : entry.id})}) %}
{% endif %}
{% if is_granted('delete', entry) %}
{% set actionButtons = actionButtons|merge({'trash': {'url': path('admin_user_delete', {'id': entry.id}), 'class': 'modal-ajax-form'}}) %}
{% endif %}
{{ widgets.button_group(actionButtons) }}
<td class="actions">
{{ actions.user(entry, 'index') }}
</td>
</tr>
{% endfor %}

View File

@@ -3,7 +3,7 @@
{% block page_title %}{{ 'profile.title'|trans }}{% endblock %}
{% block page_subtitle %}{{ 'profile.subtitle'|trans }}{% endblock %}
{% block page_actions %}{{ actions.profile(tab, user) }}{% endblock %}
{% block page_actions %}{{ actions.user(user, tab) }}{% endblock %}
{% block main %}
{% import _self as macro %}

View File

@@ -1,10 +1,6 @@
{% extends 'user/layout.html.twig' %}
{% import "macros/actions.html.twig" as actions %}
{% block main %}
{% import _self as macro %}
{% import "macros/widgets.html.twig" as widgets %}
<div class="row">
<div class="col-md-12">
<div class="nav-tabs-custom">

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="de" datatype="plaintext" original="actions.en.xliff">
<body>
<trans-unit id="stop">
<source>stop</source>
<target>Beenden</target>
</trans-unit>
<trans-unit id="edit">
<source>edit</source>
<target>Bearbeiten</target>
</trans-unit>
<trans-unit id="trash">
<source>trash</source>
<target>Löschen</target>
</trans-unit>
<trans-unit id="repeat">
<source>repeat</source>
<target>Neu starten</target>
</trans-unit>
<trans-unit id="profile-stats">
<source>profile-stats</source>
<target>Statistiken</target>
</trans-unit>
<trans-unit id="settings">
<source>settings</source>
<target>Einstellungen</target>
</trans-unit>
<trans-unit id="timesheet">
<source>timesheet</source>
<target>Stundenzettel</target>
</trans-unit>
<trans-unit id="project">
<source>project</source>
<target>Projekte</target>
</trans-unit>
<trans-unit id="activity">
<source>activity</source>
<target>Tätigkeiten</target>
</trans-unit>
<trans-unit id="copy">
<source>copy</source>
<target>Kopie erstellen</target>
</trans-unit>
<trans-unit id="home">
<source>home</source>
<target>Homepage</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="en" datatype="plaintext" original="none">
<body>
<trans-unit id="stop">
<source>stop</source>
<target>Stop</target>
</trans-unit>
<trans-unit id="edit">
<source>edit</source>
<target>Edit</target>
</trans-unit>
<trans-unit id="trash">
<source>trash</source>
<target>Delete</target>
</trans-unit>
<trans-unit id="repeat">
<source>repeat</source>
<target>Start again</target>
</trans-unit>
<trans-unit id="profile-stats">
<source>profile-stats</source>
<target>Statistics</target>
</trans-unit>
<trans-unit id="settings">
<source>settings</source>
<target>Settings</target>
</trans-unit>
<trans-unit id="timesheet">
<source>timesheet</source>
<target>Timesheet</target>
</trans-unit>
<trans-unit id="project">
<source>project</source>
<target>Projects</target>
</trans-unit>
<trans-unit id="activity">
<source>activity</source>
<target>Activities</target>
</trans-unit>
<trans-unit id="copy">
<source>copy</source>
<target>Create copy</target>
</trans-unit>
<trans-unit id="home">
<source>home</source>
<target>Homepage</target>
</trans-unit>
</body>
</file>
</xliff>