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,10 +266,22 @@ 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 {
font-weight: bold;
border-bottom: 1px solid #ccc;
tr {
&.summary td {
font-weight: bold;
border-bottom: 1px solid #ccc;
}
&.open-edit {
cursor: pointer;
}
}
td {
/*

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,60 +140,113 @@
</div>
{% endmacro %}
{% macro button_group(actions) %}
{% import _self as macro %}
<div class="btn-group">
{%- for icon,values in actions %}
{% spaceless %}
{% set id = null %}
{% set onclick = null %}
{% set modal = null %}
{% set toggle = null %}
{% set url = null %}
{% set target = null %}
{% set class = "btn btn-default btn-" ~ icon ~ " " %}
{% 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 %}
{% 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 %}
{% if not values is iterable %}
{% set url = values %}
{% if 'onclick:' in url %}
{% set onclick = url|replace({'onclick:': ''}) %}
{% set url = '#' %}
{% endif %}
{% if '#collapse' in url %}
{% set toggle = 'collapse' %}
{% endif %}
{% if '#modal' in url %}
{% set modal = url %}
{% set url = '#' %}
{% endif %}
{% else %}
{% 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 class = class ~ ( values.class | default("")) %}
{% endif %}
{% endspaceless %}
<a class="{{ class | trim }}" href="{{ url }}"
{%- if id is not empty -%}
id="{{ id }}"
{%- endif -%}
{%- if toggle is not empty -%}
data-toggle="{{ toggle }}"
{%- endif -%}
{%- if modal is not empty -%}
data-toggle="modal" data-target="{{ modal }}"
{%- endif -%}
{%- if onclick is not empty -%}
onclick="{{ onclick }}"
{%- endif -%}
{%- if target is not empty -%}
target="{{ target }}"
{%- endif -%}
>{{ macro.icon(icon) }}</a>
{% 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 %}
{% if 'onclick:' in url %}
{% set onclick = url|replace({'onclick:': ''}) %}
{% set url = '#' %}
{% endif %}
{% if '#collapse' in url %}
{% set toggle = 'collapse' %}
{% endif %}
{% if '#modal' in url %}
{% set modal = url %}
{% 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 %}
{% 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 -%}
{%- if toggle is not empty -%}
data-toggle="{{ toggle }}"
{%- endif -%}
{%- if modal is not empty -%}
data-toggle="modal" data-target="{{ modal }}"
{%- endif -%}
{%- if onclick is not empty -%}
onclick="{{ onclick }}"
{%- endif -%}
{%- if target is not empty -%}
target="{{ target }}"
{%- endif -%}
>{% 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>