@@ -28,6 +28,7 @@ require('../../vendor/almasaeed2010/adminlte/dist/js/app.js');
|
||||
|
||||
// ------ Kimai itself ------
|
||||
require('./kimai.js');
|
||||
require('./datatable.js');
|
||||
require('./toolbar.js');
|
||||
require('../images/default_avatar.png');
|
||||
|
||||
|
||||
66
assets/js/datatable.js
Normal file
66
assets/js/datatable.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** global: Cookies */
|
||||
global.Cookies = require('js-cookie');
|
||||
|
||||
if (typeof jQuery === 'undefined') {
|
||||
throw new Error('Kimai requires jQuery');
|
||||
}
|
||||
|
||||
/* datatable
|
||||
*
|
||||
* @type Object
|
||||
* @description $.datatable is the main object for views with data-tables.
|
||||
* It's used for implementing functions and options related
|
||||
* to the datatables.
|
||||
*/
|
||||
$.datatable = {};
|
||||
|
||||
$(function() {
|
||||
"use strict";
|
||||
|
||||
$.datatable = {
|
||||
saveVisibility: function (modalSelector) {
|
||||
var settings = {};
|
||||
var cookieName = $(modalSelector).find('form').attr('name');
|
||||
$(modalSelector).find('form').find('input:checkbox:not(:checked)').each(
|
||||
function () {
|
||||
settings[$(this).attr('name')] = $(this).is(':checked');
|
||||
}
|
||||
);
|
||||
if (jQuery.isEmptyObject(settings)) {
|
||||
Cookies.remove(cookieName);
|
||||
} else {
|
||||
Cookies.set(cookieName, JSON.stringify(settings), {expires: 365});
|
||||
}
|
||||
$(modalSelector).modal('toggle');
|
||||
location.reload();
|
||||
},
|
||||
changeVisibility: function (column) {
|
||||
var tbl = $('table.dataTable');
|
||||
var amount = tbl.find('th').length -1;
|
||||
if (column < 0 || column >= amount) {
|
||||
return;
|
||||
}
|
||||
var header = $(tbl.find('th').get(column));
|
||||
if (header.css("display") === "none") {
|
||||
header.show();
|
||||
tbl.find('tr').each(function(){
|
||||
$($(this).find('td').get(column)).show('ease');
|
||||
});
|
||||
} else {
|
||||
header.hide();
|
||||
tbl.find('tr').each(function(){
|
||||
$($(this).find('td').get(column)).hide('ease');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
@@ -16,6 +16,7 @@
|
||||
"jquery": "^3.3.1",
|
||||
"jquery-slimscroll": "^1.3.8",
|
||||
"jquery-ui": "^1.12.1",
|
||||
"js-cookie": "^2.2.0",
|
||||
"node-sass": "^4.9.0",
|
||||
"sass-loader": "^7.0.2",
|
||||
"webpack-notifier": "^1.5.1"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"build/app.js": "/build/app.js?aa153be6f298fddd7ee1",
|
||||
"build/app.js": "/build/app.js?604773492e023a83c73b",
|
||||
"build/app.css": "/build/app.css?ec2e5a6f655d60e8c23adb0967d24d6f",
|
||||
"build/fonts/fa-solid-900.woff": "/build/fonts/fa-solid-900.woff?128d2b0b",
|
||||
"build/images/boxed-bg.jpg": "/build/images/boxed-bg.jpg?7799dece",
|
||||
|
||||
@@ -46,6 +46,41 @@ class Extensions extends \Twig_Extension
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $cookies = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $icons = [
|
||||
'user' => 'fas fa-user',
|
||||
'customer' => 'fas fa-users',
|
||||
'project' => 'fas fa-project-diagram',
|
||||
'activity' => 'fas fa-tasks',
|
||||
'admin' => 'fas fa-wrench',
|
||||
'invoice' => 'fas fa-file-invoice',
|
||||
'timesheet' => 'far fa-clock',
|
||||
'dashboard' => 'fas fa-tachometer-alt',
|
||||
'logout' => 'fas fa-sign-out-alt',
|
||||
'trash' => 'far fa-trash-alt',
|
||||
'delete' => 'far fa-trash-alt',
|
||||
'repeat' => 'fas fa-redo-alt',
|
||||
'edit' => 'far fa-edit',
|
||||
'manual' => 'fas fa-book',
|
||||
'help' => 'far fa-question-circle',
|
||||
'start' => 'fas fa-play-circle',
|
||||
'start-small' => 'fas fa-play-circle',
|
||||
'stop' => 'fas fa-stop',
|
||||
'stop-small' => 'far fa-stop-circle',
|
||||
'filter' => 'fas fa-filter',
|
||||
'create' => 'far fa-plus-square',
|
||||
'list' => 'fas fa-list',
|
||||
'print' => 'fas fa-print',
|
||||
'visibility' => 'far fa-eye',
|
||||
];
|
||||
|
||||
/**
|
||||
* Extensions constructor.
|
||||
* @param string $locales
|
||||
@@ -79,9 +114,42 @@ class Extensions extends \Twig_Extension
|
||||
{
|
||||
return [
|
||||
new \Twig_SimpleFunction('locales', [$this, 'getLocales']),
|
||||
new \Twig_SimpleFunction('is_visible_column', [$this, 'isColumnVisible']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only for datatables, do not use it outside this context.
|
||||
*
|
||||
* @param string $dataTable
|
||||
* @param string $column
|
||||
* @return bool
|
||||
*/
|
||||
public function isColumnVisible(string $dataTable, string $column)
|
||||
{
|
||||
// TODO name handling could be improved, as now this info is spread in datatables.html.twig and here
|
||||
$dataTable = $dataTable . '_visibility';
|
||||
|
||||
if (!isset($this->cookies[$dataTable])) {
|
||||
$visibility = false;
|
||||
if ($this->requestStack->getCurrentRequest()->cookies->has($dataTable)) {
|
||||
$visibility = json_decode($this->requestStack->getCurrentRequest()->cookies->get($dataTable), true);
|
||||
}
|
||||
$this->cookies[$dataTable] = $visibility;
|
||||
}
|
||||
$values = $this->cookies[$dataTable];
|
||||
|
||||
if (empty($values) || !is_array($values)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($values[$column]) && $values[$column] === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms seconds into a duration string.
|
||||
*
|
||||
@@ -127,33 +195,7 @@ class Extensions extends \Twig_Extension
|
||||
*/
|
||||
public function icon($name, $default = '')
|
||||
{
|
||||
$icons = [
|
||||
'user' => 'fas fa-user',
|
||||
'customer' => 'fas fa-users',
|
||||
'project' => 'fas fa-project-diagram',
|
||||
'activity' => 'fas fa-tasks',
|
||||
'admin' => 'fas fa-wrench',
|
||||
'invoice' => 'fas fa-file-invoice',
|
||||
'timesheet' => 'far fa-clock',
|
||||
'dashboard' => 'fas fa-tachometer-alt',
|
||||
'logout' => 'fas fa-sign-out-alt',
|
||||
'trash' => 'far fa-trash-alt',
|
||||
'delete' => 'far fa-trash-alt',
|
||||
'repeat' => 'fas fa-redo-alt',
|
||||
'edit' => 'far fa-edit',
|
||||
'manual' => 'fas fa-book',
|
||||
'help' => 'far fa-question-circle',
|
||||
'start' => 'fas fa-play-circle',
|
||||
'start-small' => 'fas fa-play-circle',
|
||||
'stop' => 'fas fa-stop',
|
||||
'stop-small' => 'far fa-stop-circle',
|
||||
'filter' => 'fas fa-filter',
|
||||
'create' => 'far fa-plus-square',
|
||||
'list' => 'fas fa-list',
|
||||
'print' => 'fas fa-print',
|
||||
];
|
||||
|
||||
return $icons[$name] ?? $default;
|
||||
return self::$icons[$name] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'admin_activity.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_activity.subtitle'|trans }} {{ 'subtitle.amount'|trans({'%count%': entries.count}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseActivityAdmin', 'create': path('admin_activity_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseActivityAdmin', 'visibility': '#modal_activity_admin', 'create': path('admin_activity_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseActivityAdmin') }}
|
||||
@@ -16,26 +16,30 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header({
|
||||
'label.name': '',
|
||||
'label.customer': 'hidden-xs',
|
||||
'label.project': '',
|
||||
'label.comment': 'hidden-xs',
|
||||
'label.visible': 'hidden-xs',
|
||||
'label.actions': '',
|
||||
}) }}
|
||||
{% set columns = {
|
||||
'name': 'alwaysVisible',
|
||||
'customer': 'hidden-xs',
|
||||
'project': '',
|
||||
'comment': 'hidden-xs',
|
||||
'visible': 'hidden-xs',
|
||||
'actions': 'alwaysVisible',
|
||||
} %}
|
||||
|
||||
{% set tableName = 'activity_admin' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td>{{ entry.name }}</td>
|
||||
<td class="hidden-xs">
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">
|
||||
<a href="{{ path('admin_customer_edit', {'id' : entry.project.customer.id}) }}">{{ widgets.label_customer(entry.project.customer) }}</a>
|
||||
</td>
|
||||
<td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}">
|
||||
<a href="{{ path('admin_project_edit', {'id' : entry.project.id}) }}">{{ widgets.label_project(entry.project) }}</a>
|
||||
</td>
|
||||
<td class="hidden-xs">{{ entry.comment }}</td>
|
||||
<td class="hidden-xs">{{ widgets.label_visible(entry.visible) }}</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>
|
||||
{% set actionButtons = {} %}
|
||||
{% if is_granted('edit', entry) %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'admin_customer.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_customer.subtitle'|trans }} {{ 'subtitle.amount'|trans({'%count%': entries.count}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseCustomerAdmin', 'create': path('admin_customer_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseCustomerAdmin', 'visibility': '#modal_customer_admin', 'create': path('admin_customer_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseCustomerAdmin') }}
|
||||
@@ -16,31 +16,35 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header({
|
||||
'label.name': '',
|
||||
'label.project': '',
|
||||
'label.comment': 'hidden-xs',
|
||||
'label.country': 'hidden-xs',
|
||||
'label.customer_number': 'hidden-xs',
|
||||
'label.currency': 'hidden-xs',
|
||||
'label.visible': 'hidden-xs',
|
||||
'label.actions': '',
|
||||
}) }}
|
||||
{% set columns = {
|
||||
'name': 'alwaysVisible',
|
||||
'project': '',
|
||||
'comment': 'hidden-xs',
|
||||
'country': 'hidden-xs',
|
||||
'customer_number': 'hidden-xs',
|
||||
'currency': 'hidden-xs',
|
||||
'visible': 'hidden-xs',
|
||||
'actions': 'alwaysVisible',
|
||||
} %}
|
||||
|
||||
{% set tableName = 'customer_admin' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td>{{ entry.name }} {% if entry.company is not empty %}({{ entry.company }}){% endif %}</td>
|
||||
<td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}">
|
||||
{% for project in entry.projects %}
|
||||
<a href="{{ path('admin_project_edit', {'id' : project.id}) }}">{{ widgets.label_project(project) }}</a>
|
||||
<br class="visible-xs-block">
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="hidden-xs">{{ entry.comment }}</td>
|
||||
<td class="hidden-xs">{{ entry.country|country }}</td>
|
||||
<td class="hidden-xs">{{ entry.number }}</td>
|
||||
<td class="hidden-xs">{{ entry.currency }} {{ entry.currency|currency }}</td>
|
||||
<td class="hidden-xs">{{ widgets.label_visible(entry.visible) }}</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, 'customer_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>
|
||||
{% set actionButtons = {} %}
|
||||
{% if is_granted('edit', entry) %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'admin_project.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_project.subtitle'|trans }} {{ 'subtitle.amount'|trans({'%count%': entries.count}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseProjectAdmin', 'create': path('admin_project_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseProjectAdmin', 'visibility': '#modal_project_admin', 'create': path('admin_project_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseProjectAdmin') }}
|
||||
@@ -16,24 +16,28 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header({
|
||||
'label.name': '',
|
||||
'label.customer': '',
|
||||
'label.comment': 'hidden-xs hidden-sm',
|
||||
'label.budget': 'hidden-xs',
|
||||
'label.visible': 'hidden-xs',
|
||||
'label.actions': '',
|
||||
}) }}
|
||||
{% set columns = {
|
||||
'name': 'alwaysVisible',
|
||||
'customer': '',
|
||||
'comment': 'hidden-xs hidden-sm',
|
||||
'budget': 'hidden-xs',
|
||||
'visible': 'hidden-xs',
|
||||
'actions': 'alwaysVisible',
|
||||
} %}
|
||||
|
||||
{% set tableName = 'project_admin' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td>{{ entry.name }}</td>
|
||||
<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>
|
||||
</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.comment }}</td>
|
||||
<td class="hidden-xs">{{ entry.budget|money(entry.customer.currency) }}</td>
|
||||
<td class="hidden-xs">{{ widgets.label_visible(entry.visible) }}</td>
|
||||
<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>
|
||||
{% set actionButtons = {} %}
|
||||
{% if is_granted('edit', entry) %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'admin_timesheet.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_timesheet.subtitle'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseTimesheetAdmin', 'create': path('admin_timesheet_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseTimesheetAdmin', 'visibility': '#modal_timesheet_admin', 'create': path('admin_timesheet_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseTimesheetAdmin') }}
|
||||
@@ -16,48 +16,52 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{% set columns = {'label.date': ''} %}
|
||||
{% set columns = {'date': 'alwaysVisible'} %}
|
||||
|
||||
{% if not duration_only %}
|
||||
{% set columns = columns|merge({'label.starttime': 'hidden-xs', 'label.endtime': 'hidden-xs'}) %}
|
||||
{% set columns = columns|merge({'starttime': 'hidden-xs', 'endtime': 'hidden-xs'}) %}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header(columns|merge({
|
||||
'label.duration': '',
|
||||
'label.rate': '',
|
||||
'label.activity': 'hidden-xs hidden-sm',
|
||||
'label.username': 'hidden-xs',
|
||||
'label.description': 'hidden-xs hidden-sm',
|
||||
'label.actions': '',
|
||||
})) }}
|
||||
{% set columns = columns|merge({
|
||||
'duration': '',
|
||||
'rate': '',
|
||||
'activity': 'hidden-xs hidden-sm',
|
||||
'username': 'hidden-xs',
|
||||
'description': 'hidden-xs hidden-sm',
|
||||
'actions': 'alwaysVisible',
|
||||
}) %}
|
||||
|
||||
{% set tableName = 'timesheet_admin' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date_short }}</td>
|
||||
|
||||
{% if not duration_only %}
|
||||
<td class="hidden-xs">{{ entry.begin|date("H:i") }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'starttime') }}">{{ entry.begin|date("H:i") }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.end %}
|
||||
{% if not duration_only %}
|
||||
<td class="hidden-xs">{{ entry.end|date("H:i") }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}">{{ entry.end|date("H:i") }}</td>
|
||||
{% endif %}
|
||||
<td>{{ entry.duration|duration }}</td>
|
||||
<td>{{ entry.rate|money(entry.activity.project.customer.currency) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'duration') }}">{{ entry.duration|duration }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'rate') }}">{{ entry.rate|money(entry.activity.project.customer.currency) }}</td>
|
||||
{% else %}
|
||||
{% if not duration_only %}
|
||||
<td class="hidden-xs">‐</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}">‐</td>
|
||||
{% endif %}
|
||||
<td><i>{{ entry|duration }}</i></td>
|
||||
<td>‐</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'duration') }}"><i>{{ entry|duration }}</i></td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'rate') }}">‐</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="hidden-xs hidden-sm">
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}">
|
||||
<a href="{{ path('admin_activity_edit', {'id': entry.activity.id}) }}">{{ widgets.label_activity(entry.activity) }}</a>
|
||||
</td>
|
||||
<td class="hidden-xs"><a href="{{ path('profile'|route_alias, {'username' : entry.user.username}) }}">{{ widgets.label_user(entry.user) }}</a></td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.description }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'username') }}"><a href="{{ path('profile'|route_alias, {'username' : entry.user.username}) }}">{{ widgets.label_user(entry.user) }}</a></td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }}">{{ entry.description }}</td>
|
||||
<td>
|
||||
{% set actionButtons = {} %}
|
||||
{% if is_granted('edit', entry) %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'admin_user.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_user.subtitle'|trans }} {{ 'subtitle.amount'|trans({'%count%': entries.count}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseUserAdmin', 'create': path('admin_user_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseUserAdmin', 'visibility': '#modal_user_admin', 'create': path('admin_user_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseUserAdmin') }}
|
||||
@@ -16,26 +16,30 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header({
|
||||
'label.id': 'hidden-xs',
|
||||
'label.alias': '',
|
||||
'label.username': 'hidden-xs',
|
||||
'label.email': 'hidden-xs hidden-sm',
|
||||
'label.title': 'hidden-xs',
|
||||
'label.active': '',
|
||||
'label.roles': '',
|
||||
'label.actions': '',
|
||||
}) }}
|
||||
{% set columns = {
|
||||
'id': 'hidden-xs',
|
||||
'alias': 'alwaysVisible',
|
||||
'username': 'hidden-xs',
|
||||
'email': 'hidden-xs hidden-sm',
|
||||
'title': 'hidden-xs',
|
||||
'active': '',
|
||||
'roles': '',
|
||||
'actions': 'alwaysVisible',
|
||||
} %}
|
||||
|
||||
{% set tableName = 'user_admin' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td class="hidden-xs">{{ entry.id }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'id') }}">{{ entry.id }}</td>
|
||||
<td>{{ widgets.username(entry) }}</td>
|
||||
<td class="hidden-xs">{{ entry.username }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.email }}</td>
|
||||
<td class="hidden-xs">{{ entry.title }}</td>
|
||||
<td>{{ widgets.label_visible(entry.active) }}</td>
|
||||
<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>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'title') }}">{{ entry.title }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'active') }}">{{ widgets.label_visible(entry.active) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'roles') }}">
|
||||
{% for role in entry.roles %}
|
||||
{{ widgets.label_role(role) }}
|
||||
{% endfor %}
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{{ tables.data_table_header({
|
||||
'label.name': '',
|
||||
'label.title': '',
|
||||
'label.due_days': 'hidden-xs',
|
||||
'label.vat': 'hidden-xs',
|
||||
'label.invoice_renderer': 'hidden-xs',
|
||||
'label.actions': '',
|
||||
{{ tables.data_table_header('invoice_template', {
|
||||
'name': 'alwaysVisible',
|
||||
'title': '',
|
||||
'due_days': 'hidden-xs',
|
||||
'vat': 'hidden-xs',
|
||||
'invoice_renderer': 'hidden-xs',
|
||||
'actions': 'alwaysVisible',
|
||||
}) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
|
||||
@@ -1,10 +1,62 @@
|
||||
|
||||
{% macro data_table_header(entries, form, collapseClass) %}
|
||||
<div class="box data_table">
|
||||
{% macro data_table_column_modal(name, entries) %}
|
||||
<div class="modal fade" id="modal_{{ name }}" tabindex="-1" role="dialog" aria-labelledby="data_table_modal_label">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">{{ 'modal.columns.title'|trans }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="{{ name }}_visibility">
|
||||
{% for title, class in entries %}
|
||||
{% if 'alwaysVisible' not in class %}
|
||||
<div class="form-group {{ class }}">
|
||||
<input type="checkbox" id="column_{{ title }}" name="{{ title }}"{% if is_visible_column(name, title) %} checked="checked"{% endif %}>
|
||||
<label class="control-label required" for="column_{{ title }}">{{ ('label.' ~ title)|trans }}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</form>
|
||||
<p>{{ 'modal.columns.description'|trans }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'action.close'|trans }}</button>
|
||||
<button type="button" class="btn btn-primary" onclick="$.datatable.saveVisibility('#modal_{{ name }}')">{{ 'action.save'|trans }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro data_table_column_class(name, entries, column) %}
|
||||
{% spaceless %}
|
||||
{% set class = '' %}
|
||||
{% set always = false %}
|
||||
{% if entries[column] is defined %}
|
||||
{% set class = entries[column] %}
|
||||
{% if 'alwaysVisible' in entries[column] %}
|
||||
{% set always = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (always == false) and (not is_visible_column(name, column)) %}
|
||||
{% set class = class ~ ' hidden' %}
|
||||
{% endif %}
|
||||
{% if not class is empty %}
|
||||
{{ class }}
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro data_table_header(name, entries, form, collapseClass) %}
|
||||
{% import _self as macro %}
|
||||
{{ macro.data_table_column_modal(name, entries) }}
|
||||
<div class="box data_table" id="datatable_{{ name }}">
|
||||
{% if form %}
|
||||
{% import "macros/toolbar.html.twig" as macro %}
|
||||
{{ macro.toolbar(form, collapseClass) }}
|
||||
{% endif %}
|
||||
|
||||
<div class="box-body no-padding">
|
||||
<div class="dataTables_wrapper form-inline dt-bootstrap">
|
||||
<div class="row">
|
||||
@@ -17,9 +69,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
{% for title, class in entries %}
|
||||
<th{% if class %} class="{{ class }}"{% endif %}>
|
||||
{{ title|trans }}
|
||||
</th>
|
||||
<th class="{{ macro.data_table_column_class(name, entries, title) }}">
|
||||
{{ ('label.' ~ title)|trans }}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
<div class="breadcrumb">
|
||||
<div class="box-tools">
|
||||
<div class="btn-group">
|
||||
{% for icon,url in tools %}
|
||||
<a class="btn btn-default" href="{{ url }}"{% if '#collapse' in url %} data-toggle="collapse" {% endif %}><i class="{{ icon|icon(icon) }}"></i></a>
|
||||
{% endfor %}
|
||||
{%- for icon,url in tools %}
|
||||
<a class="btn btn-default" href="{{ url }}"
|
||||
{% if '#collapse' in url %}
|
||||
data-toggle="collapse"
|
||||
{% elseif '#modal' in url %}
|
||||
data-toggle="modal" data-target="{{ url }}"
|
||||
{% endif %}
|
||||
><i class="{{ icon|icon(icon) }}"></i></a>
|
||||
{% endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block page_title %}{{ 'timesheet.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'timesheet.subtitle'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseTimesheet', 'create': path('timesheet_create')}) }}{% endblock %}
|
||||
{% block page_actions %}{{ widgets.page_actions({'filter': '#collapseTimesheet', 'visibility': '#modal_timesheet', 'create': path('timesheet_create')}) }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ toolbar.toolbar(toolbarForm, 'collapseTimesheet') }}
|
||||
@@ -17,46 +17,48 @@
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% endif %}
|
||||
|
||||
{% set columns = {'label.date': ''} %}
|
||||
{% set columns = {'date': 'alwaysVisible'} %}
|
||||
|
||||
{% if not duration_only %}
|
||||
{% set columns = columns|merge({'label.starttime': '', 'label.endtime': ''}) %}
|
||||
{% set columns = columns|merge({'starttime': '', 'endtime': ''}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set columns = columns|merge({
|
||||
'label.duration': 'hidden-xs',
|
||||
'label.rate': 'hidden-xs',
|
||||
'label.activity': 'hidden-xs hidden-sm',
|
||||
'label.description': 'hidden-xs hidden-sm',
|
||||
'label.actions': '',
|
||||
'duration': 'hidden-xs',
|
||||
'rate': 'hidden-xs',
|
||||
'activity': 'hidden-xs hidden-sm',
|
||||
'description': 'hidden-xs hidden-sm',
|
||||
'actions': 'alwaysVisible',
|
||||
}) %}
|
||||
|
||||
{{ tables.data_table_header(columns) }}
|
||||
{% set tableName = 'timesheet' %}
|
||||
|
||||
{{ tables.data_table_header(tableName, columns) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date_short }}</td>
|
||||
|
||||
{% if not duration_only %}
|
||||
<td>{{ entry.begin|date("H:i") }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'starttime') }}">{{ entry.begin|date("H:i") }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.end %}
|
||||
{% if not duration_only %}
|
||||
<td>{{ entry.end|date("H:i") }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}">{{ entry.end|date("H:i") }}</td>
|
||||
{% endif %}
|
||||
<td class="hidden-xs">{{ entry.duration|duration }}</td>
|
||||
<td class="hidden-xs">{{ entry.rate|money(entry.activity.project.customer.currency) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'duration') }}">{{ entry.duration|duration }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'rate') }}">{{ entry.rate|money(entry.activity.project.customer.currency) }}</td>
|
||||
{% else %}
|
||||
{% if not duration_only %}
|
||||
<td>‐</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}">‐</td>
|
||||
{% endif %}
|
||||
<td class="hidden-xs"><i>{{ entry|duration }}</i></td>
|
||||
<td class="hidden-xs">‐</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'duration') }}"><i>{{ entry|duration }}</i></td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'rate') }}">‐</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="hidden-xs hidden-sm">{{ widgets.label_activity(entry.activity) }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.description }}</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') }}">{{ entry.description }}</td>
|
||||
<td>
|
||||
{% set actionButtons = {'edit': path('timesheet_edit', {'id' : entry.id, 'page': page})} %}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class ExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFunctions()
|
||||
{
|
||||
$functions = ['locales'];
|
||||
$functions = ['locales', 'is_visible_column'];
|
||||
$sut = $this->getSut('de');
|
||||
$twigFunctions = $sut->getFunctions();
|
||||
$this->assertCount(count($functions), $twigFunctions);
|
||||
@@ -184,6 +184,7 @@ class ExtensionsTest extends TestCase
|
||||
'create' => 'far fa-plus-square',
|
||||
'list' => 'fas fa-list',
|
||||
'print' => 'fas fa-print',
|
||||
'visibility' => 'far fa-eye',
|
||||
];
|
||||
|
||||
$sut = $this->getSut('en');
|
||||
|
||||
@@ -235,6 +235,10 @@
|
||||
<source>action.back</source>
|
||||
<target>Zurück</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="action.close">
|
||||
<source>action.close</source>
|
||||
<target>Schließen</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Dashboard
|
||||
@@ -303,6 +307,14 @@
|
||||
<source>label.end</source>
|
||||
<target>Bis</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.title">
|
||||
<source>modal.columns.title</source>
|
||||
<target>Ändere Spalten-Sichtbarkeit</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.description">
|
||||
<source>modal.columns.description</source>
|
||||
<target>Beim Speichern werden die nicht ausgewählten Spalten ausgeblendet und diese Einstellungen in einem Browser Cookie hinterlegt. Sollten Sie Ihre Cookies löschen, werden die Einstellungen rückgängig gemacht.</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
User profile
|
||||
|
||||
@@ -243,6 +243,10 @@
|
||||
<source>action.back</source>
|
||||
<target>Back</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="action.close">
|
||||
<source>action.close</source>
|
||||
<target>Close</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Dashboard
|
||||
@@ -311,6 +315,14 @@
|
||||
<source>label.end</source>
|
||||
<target>To</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.title">
|
||||
<source>modal.columns.title</source>
|
||||
<target>Change column visibility</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.description">
|
||||
<source>modal.columns.description</source>
|
||||
<target>Upon saving the un-checked columns will be hidden and this setting will be stored in a browser cookie. If you delete your cookies, the settings will be reversed.</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
User profile
|
||||
|
||||
@@ -275,6 +275,10 @@
|
||||
<source>action.back</source>
|
||||
<target>Назад</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="action.close">
|
||||
<source>action.close</source>
|
||||
<target>Close</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Dashboard
|
||||
@@ -343,6 +347,14 @@
|
||||
<source>label.end</source>
|
||||
<target>До</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.title">
|
||||
<source>modal.columns.title</source>
|
||||
<target>Change column visibility</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="modal.columns.description">
|
||||
<source>modal.columns.description</source>
|
||||
<target>Upon saving the un-checked columns will be hidden and this setting will be stored in a browser cookie. If you delete your cookies, the settings will be reversed.</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
User profile
|
||||
|
||||
@@ -2958,6 +2958,10 @@ js-base64@^2.1.8, js-base64@^2.1.9:
|
||||
version "2.4.5"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.5.tgz#e293cd3c7c82f070d700fc7a1ca0a2e69f101f92"
|
||||
|
||||
js-cookie@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
|
||||
|
||||
js-tokens@^3.0.0, js-tokens@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||
|
||||
Reference in New Issue
Block a user