added avatars, show user teams in list, new team dashboard widgets (#1150)

This commit is contained in:
Kevin Papst
2019-10-03 13:44:16 +02:00
committed by GitHub
parent 718ad4b398
commit e8c25d8ac5
120 changed files with 2585 additions and 642 deletions

View File

@@ -0,0 +1,6 @@
{% macro about(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% set event = trigger('actions.about', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -1,5 +1,5 @@
{% extends 'base.html.twig' %}
{% import "macros/actions.html.twig" as actions %}
{% import "about/actions.html.twig" as actions %}
{% block page_title %}{{ 'about.title'|trans({}, 'about') }}{% endblock %}
{% block page_actions %}{{ actions.about('index') }}{% endblock %}

View File

@@ -21,7 +21,6 @@
<ul>
<li>AdminLTE: <a href="https://adminlte.io" target="_blank">https://adminlte.io</a></li>
<li>Bootstrap: <a href="https://getbootstrap.com" target="_blank">https://getbootstrap.com</a></li>
<li>Bootstrap-Select: <a href="https://developer.snapappointments.com/bootstrap-select" target="_blank">https://developer.snapappointments.com/bootstrap-select</a></li>
<li>chart.js: <a href="https://www.chartjs.org" target="_blank">https://www.chartjs.org</a></li>
<li>DateRangePicker: <a href="http://www.daterangepicker.com/" target="_blank">http://www.daterangepicker.com/</a></li>
<li>Doctrine: <a href="https://www.doctrine-project.org" target="_blank">https://www.doctrine-project.org</a></li>
@@ -31,9 +30,10 @@
<li>jQuery UI: <a href="https://jqueryui.com" target="_blank">http://jqueryui.com</a></li>
<li>MomentJS: <a href="https://momentjs.com" target="_blank">https://momentjs.com</a></li>
<li>PHPOffice: <a href="https://github.com/PHPOffice" target="_blank">https://github.com/PHPOffice</a></li>
<li>Select2: <a href="https://select2.org/" target="_blank">https://select2.org/</a></li>
<li>SweetAlert 2: <a href="https://sweetalert2.github.io" target="_blank">https://sweetalert2.github.io</a></li>
<li>Symfony: <a href="https://symfony.com" target="_blank">https://symfony.com</a></li>
<li>…</li>
<li>… </li>
</ul>
{% endblock %}
{% endembed %}

View File

@@ -1,51 +0,0 @@
{% extends 'about/layout.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block about_box %}
{% endblock %}
{% block about %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% block box_title %}Environment{% endblock %}
{% block box_body %}
<dl>
{% for name, value in dotenv %}
<dt>{{ name }}</dt>
<dd>{{ value }}</dd>
{% endfor %}
</dl>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% block box_title %}PHP{% endblock %}
{% block box_body %}
<dl>
<dt>Version</dt><dd>{{ constant('PHP_VERSION') }}</dd>
<dt>Modules</dt><dd>{{ modules|join(', ') }}</dd>
{% for name, value in settings %}
<dt>{{ name }}</dt>
<dd>
{% if value is empty %}
<i>unknown</i>
{% else %}
{{ value }}
{% endif %}
</dd>
{% endfor %}
</dl>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% block box_title %}Server{% endblock %}
{% block box_body %}
<dl>
{% for name, value in info %}
<dt>{{ name }}</dt>
<dd>{{ value|raw }}</dd>
{% endfor %}
</dl>
{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -117,7 +117,7 @@
{% import "macros/widgets.html.twig" as widgets %}
<li class="dropdown user-menu">
<a href="#" class="dropdown-toggle ddt-large" data-toggle="dropdown">
<i class="{{ 'avatar'|icon }} fa-2x"></i>
{{ widgets.user_avatar(app.user, false) }}
</a>
<ul class="dropdown-menu">
{% if app.user is not null %}
@@ -125,8 +125,8 @@
<li>
<a href="{{ path('user_profile', {'username' : app.user.username}) }}">
<h4 class="control-sidebar-subheading">
<i class="{{ 'profile-stats'|icon }}"></i>
{{ widgets.username(app.user) }}
<i class="{{ 'avatar'|icon }}"></i>
{{ 'my.profile'|trans }}
</h4>
</a>
</li>
@@ -136,7 +136,7 @@
<a href="{{ path('user_profile_edit', {'username' : app.user.username}) }}">
<h4 class="control-sidebar-subheading">
<i class="{{ 'profile'|icon }}"></i>
{{ 'profile.title'|trans }}
{{ 'action.edit'|trans }}
</h4>
</a>
</li>

View File

@@ -0,0 +1,11 @@
{% macro calendar(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% if is_granted('create_own_timesheet') %}
{% set actions = actions|merge({'create': {'url': path('timesheet_create'), 'class': 'modal-ajax-form'}}) %}
{% endif %}
{% set event = trigger('actions.calendar', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -1,6 +1,6 @@
{% extends 'base.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% import "macros/actions.html.twig" as actions %}
{% import "calendar/actions.html.twig" as actions %}
{% block page_title %}{{ 'calendar.title'|trans }}{% endblock %}
{% block page_actions %}{{ actions.calendar('index') }}{% endblock %}

View File

@@ -0,0 +1,8 @@
{% macro doctor(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% set event = trigger('actions.doctor', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -0,0 +1,156 @@
{% extends 'base.html.twig' %}
{% import "doctor/actions.html.twig" as actions %}
{% block page_title %}{{ 'menu.doctor'|trans }}{% endblock %}
{% block page_actions %}{{ actions.doctor('index') }}{% endblock %}
{% block main %}
{% set permissionOpts = {collapsed: true, boxtype: 'success'} %}
{% for name, value in directories %}
{% if value is same as (false) %}
{% set permissionOpts = {boxtype: 'danger'} %}
{% endif %}
{% endfor %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with permissionOpts %}
{% block box_title %}File permissions{% endblock %}
{% block box_body %}
<p>
If you see a warning icon <i class="{{ 'warning'|icon }} text-red"></i> in the list below, you should talk to your administrator.
The path is either not readable or not writable and Kimai might not work as expected.
</p>
<table class="table">
{% for name, value in directories %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>
{% if value is same as (false) %}
<i class="{{ 'warning'|icon }} text-red"></i>
{% else %}
<i class="{{ 'success'|icon }} text-green"></i>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% set extensionOpts = {collapsed: true, boxtype: 'success'} %}
{% for name, value in extensions %}
{% if value is same as (false) %}
{% set extensionOpts = {boxtype: 'danger'} %}
{% endif %}
{% endfor %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with extensionOpts %}
{% block box_title %}Required PHP extensions{% endblock %}
{% block box_body %}
<p>
If you see a warning icon <i class="{{ 'warning'|icon }} text-red"></i> in the list below, you should talk to your administrator.
There is a missing PHP extension and Kimai might not work as expected.
</p>
<table class="table">
{% for name, value in extensions %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>
{% if value is same as (false) %}
<i class="{{ 'warning'|icon }} text-red"></i>
{% else %}
<i class="{{ 'success'|icon }} text-green"></i>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% set logOpts = {collapsed: true} %}
{% if logSize > 52428800 %}
{% set logOpts = {boxtype: 'danger'} %}
{% endif %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with logOpts %}
{% block box_title %}Logfile (max. {{ logLines }} last lines){% endblock %}
{% block box_body %}
{% if logSize > 52428800 %}
<p>Your logfile is larger than 50 MB, consider deleting it (it will be re-created automatically).</p>
{% endif %}
<pre>{% for logLine in logs %}
{{- logLine -}}
{% endfor %}</pre>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {collapsed: true} %}
{% block box_title %}Composer packages{% endblock %}
{% block box_body %}
<table class="table">
{% for name, value in composer %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {collapsed: true} %}
{% block box_title %}Environment variables{% endblock %}
{% block box_body %}
<table class="table">
{% for name, value in dotenv %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {collapsed: true} %}
{% block box_title %}PHP{% endblock %}
{% block box_body %}
<table class="table">
<tr>
<th style="width:15%">Version</th>
<td>{{ constant('PHP_VERSION') }}</td>
</tr>
<tr>
<th style="width:15%;max-width:25%">Modules</th>
<td>{{ modules|join(', ') }}</td>
</tr>
{% for name, value in settings %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>
{% if value is empty %}
<i>unknown</i>
{% else %}
{{ value }}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {collapsed: true} %}
{% block box_title %}Server{% endblock %}
{% block box_body %}
<table class="table">
{% for name, value in info %}
<tr>
<th style="width:15%">{{ name }}</th>
<td>{{ value|raw }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -77,7 +77,7 @@
<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 }}
{{ entry.description|escape|desc2html }}
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'unit_price') }} text-nowrap">
{{ rate|money(currency) }}

View File

@@ -1,56 +0,0 @@
{% macro calendar(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% if is_granted('create_own_timesheet') %}
{% set actions = actions|merge({'create': {'url': path('timesheet_create'), 'class': 'modal-ajax-form'}}) %}
{% endif %}
{% set event = trigger('actions.calendar', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro plugins(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'shop': {'url': constant('App\\Constants::HOMEPAGE') ~ '/store/', 'target': '_blank'}} %}
{% set actions = actions|merge({'help': {'url': 'plugins.html'|docu_link, 'target': '_blank'}}) %}
{% set event = trigger('actions.plugins', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro plugin(plugin, view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'home': {'url': plugin.metadata.homepage, 'target': '_blank'}} %}
{% set event = trigger('actions.plugin', {'actions': actions, 'view': view, 'plugin': plugin}) %}
{% if view == 'index' %}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.entity_actions(event.payload.actions) }}
{% endif %}
{% endmacro %}
{% macro about(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'about': {'url': path('about')}} %}
{% if is_granted('system_information') %}
{% set actions = actions|merge({'debug': path('about_debug')}) %}
{% endif %}
{% set event = trigger('actions.about', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro system_configuration(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% set actions = actions|merge({'help': {'url': 'configurations.html'|docu_link, 'target': '_blank'}}) %}
{% set event = trigger('actions.system_configuration', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -29,3 +29,37 @@
</div>
</div>
{% endmacro %}
{% macro progressbar_small(max, current, leftValue, leftFormatted) %}
{% set percentReached = 0 %}
{% if max > 0 %}
{% set percentReached = (current / (max / 100)) %}
{% endif %}
{% set class = "progress-bar-info" %}
{% set width = percentReached|number_format(1, '.', '') %}
{% if percentReached > 90 %}
{% set class = "progress-bar-danger" %}
{% elseif percentReached > 70 %}
{% set class = "progress-bar-warning" %}
{% elseif percentReached > 50 %}
{% set class = "progress-bar-success" %}
{% elseif percentReached > 30 %}
{% set class = "progress-bar-primary" %}
{% endif %}
{% if width > 100 %}
{% set width = 100 %}
{% endif %}
<div class="progress-group">
<div class="progress progress-sm">
<div class="progress-bar {{ class }}" role="progressbar" aria-valuenow="{{ width }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ width }}%"></div>
</div>
{% if leftValue is not null and leftValue > 0 %}
<small>{{ 'stats.percentUsedLeft'|trans({'%percent%': percentReached|number_format(0), '%left%': leftFormatted}) }}</small>
{% else %}
<small>{{ 'stats.percentUsed'|trans({'%percent%': percentReached|number_format(0)}) }}</small>
{% endif %}
</div>
{% endmacro %}

View File

@@ -44,6 +44,10 @@
{{ macro.label(role, 'danger') }}
{% elseif role == 'ROLE_ADMIN' %}
{{ macro.label(role, 'warning') }}
{% elseif role == 'ROLE_TEAMLEAD' %}
{{ macro.label(role, 'success') }}
{% elseif role == 'ROLE_USER' %}
{{ macro.label(role, 'gray') }}
{% else %}
{{ macro.label(role, 'primary') }}
{% endif %}
@@ -58,6 +62,21 @@
{{ macro.label(user.displayName, 'primary') }}
{% endmacro %}
{% macro label_team(team, class) %}
{% import _self as macro %}
{{ macro.label(team.name, class|default('primary')) }}
{% endmacro %}
{% macro user_avatar(user, tooltip) %}
{% set avatar = avatar(user, admin_lte_context.default_avatar) %}
{% set showTooltip = tooltip|default(true) %}
{% if tooltip is not defined or tooltip is same as (false)%}
<img src="{{ avatar }}" class="{{ class|default('img-circle') }}" alt="{{ user.displayName }}" />
{% else %}
<img src="{{ avatar }}" class="{{ class|default('img-circle') }}" data-toggle="tooltip" data-placement="top" alt="{{ user.displayName }}" title="{{ user.displayName }}" />
{% endif %}
{% endmacro %}
{% macro label_activity(activity, url) %}
{% import _self as macro %}
{% set isVisible = activity.visible %}

View File

@@ -0,0 +1,22 @@
{% macro plugins(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'shop': {'url': constant('App\\Constants::HOMEPAGE') ~ '/store/', 'target': '_blank'}} %}
{% set actions = actions|merge({'help': {'url': 'plugins.html'|docu_link, 'target': '_blank'}}) %}
{% set event = trigger('actions.plugins', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}
{% macro plugin(plugin, view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {'home': {'url': plugin.metadata.homepage, 'target': '_blank'}} %}
{% set event = trigger('actions.plugin', {'actions': actions, 'view': view, 'plugin': plugin}) %}
{% if view == 'index' %}
{{ widgets.table_actions(event.payload.actions) }}
{% else %}
{{ widgets.entity_actions(event.payload.actions) }}
{% endif %}
{% endmacro %}

View File

@@ -1,6 +1,6 @@
{% extends 'base.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% import "macros/actions.html.twig" as actions %}
{% import "plugin/actions.html.twig" as actions %}
{% import "macros/datatables.html.twig" as tables %}
{% block page_title %}{{ 'plugins.title'|trans({}, 'plugins') }}{% endblock %}

View File

@@ -0,0 +1,9 @@
{% macro system_configuration(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% set actions = actions|merge({'help': {'url': 'configurations.html'|docu_link, 'target': '_blank'}}) %}
{% set event = trigger('actions.system_configuration', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% endmacro %}

View File

@@ -1,5 +1,5 @@
{% extends 'base.html.twig' %}
{% import "macros/actions.html.twig" as actions %}
{% import "system-configuration/actions.html.twig" as actions %}
{% block page_title %}{{ 'title'|trans({}, 'system-configuration') }}{% endblock %}
{% block page_subtitle %}{{ 'subtitle'|trans({}, 'system-configuration') }}{% endblock %}

View File

@@ -17,7 +17,7 @@
{% set columns = {
'name': '',
'teamlead': '',
'user': {'class': '', 'orderBy': false},
'user': {'class': 'hidden-xs', 'orderBy': false},
'actions': 'actions alwaysVisible',
} %}
@@ -26,9 +26,9 @@
{{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.teamUpdate'}) }}
{% for team in teams %}
<tr{% if is_granted('edit', team) %} class="open-edit alternative-link" data-href="{{ path('admin_team_edit', {'id': team.id}) }}"{% endif %}>
<td>{{ team.name }}</td>
<td>{{ widgets.label_user(team.teamlead) }}</td>
<td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'name') }}">{{ team.name }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'teamlead') }}">{{ widgets.label_user(team.teamlead) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'user') }}">
{% for user in team.users %}
{{ widgets.label_user(user) }}&nbsp;
{% endfor %}

View File

@@ -46,7 +46,7 @@
{% if user.id is not empty %}
{% if is_granted('view', user) %}
{% set actions = {'profile-stats': {'url': path('user_profile', {'username' : user.username})}} %}
{% set actions = actions|merge({'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})}) %}

View File

@@ -7,8 +7,8 @@
{% set columns = {
'alias': 'alwaysVisible',
'username': 'hidden-xs',
'email': 'hidden-xs hidden-sm',
'title': 'hidden-xs',
'email': 'hidden-xs hidden-md hidden-sm',
'title': 'hidden-xs hidden-sm',
} %}
{% for pref in preferences %}
{% set columns = columns|merge({
@@ -16,7 +16,8 @@
}) %}
{% endfor %}
{% set columns = columns|merge({
'roles': {'class': 'hidden-xs', 'orderBy': false},
'roles': {'class': 'hidden-xs hidden-sm', 'orderBy': false},
'team': {'class': 'hidden-xs', 'orderBy': false},
'active': {'class': '', 'orderBy': false},
'actions': 'actions alwaysVisible',
}) %}
@@ -40,7 +41,7 @@
{% for entry in entries %}
<tr{% if is_granted('edit', entry) %} class="open-edit alternative-link" data-href="{{ path('user_profile_edit', {'username': entry.username}) }}"{% endif %}>
<td>{{ widgets.username(entry) }}</td>
<td>{{ widgets.user_avatar(entry) }} {{ 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>
<td class="{{ tables.data_table_column_class(tableName, columns, 'title') }}">{{ entry.title }}</td>
@@ -53,12 +54,22 @@
</td>
{% endfor %}
<td class="{{ tables.data_table_column_class(tableName, columns, 'roles') }}">
{% set showUserRole = entry.roles|length == 1 %}
{% for role in entry.roles %}
{% if role != 'ROLE_USER' %}
{% if showUserRole or role != 'ROLE_USER' %}
{{ widgets.label_role(role) }}
{% endif %}
{% endfor %}
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'team') }}">
{% for team in entry.teams %}
{% if entry.isTeamleadOf(team) %}
{{ widgets.label_team(team, 'success') }}
{% else %}
{{ widgets.label_team(team) }}
{% endif %}
{% endfor %}
</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'active') }}">{{ widgets.label_visible(entry.enabled) }}</td>
<td class="actions">
{{ actions.user(entry, 'index') }}

View File

@@ -48,10 +48,11 @@
<div class="box box-{{ admin_lte_context.widget.type }}">
<div class="box-body box-profile">
{{ macro.avatar(user.avatar, user.username, 'profile-user-img img-responsive img-circle') }}
<h3 class="profile-username text-center">{{ widgets.username(user) }}</h3>
<p class="text-muted text-center">{{ user.title }}</p>
<div class="text-center">
{{ widgets.user_avatar(user) }}
<h3 class="profile-username">{{ widgets.username(user) }}</h3>
<p class="text-muted">{{ user.title }}</p>
</div>
<ul class="list-group list-group-unbordered">

View File

@@ -0,0 +1,54 @@
{% extends 'user/layout.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block main %}
<div class="row">
<div class="col-md-12">
<div class="box box-{{ admin_lte_context.widget.type }} data_table">
<div class="box-body no-padding">
<div class="dataTables_wrapper form-inline dt-bootstrap">
<div class="row">
<div class="col-sm-12">
<table class="table table-hover dataTable" role="grid">
<thead>
<tr>
<th>{{ 'label.team'|trans }}</th>
<th>{{ 'label.teamlead'|trans }}</th>
<th>{{ 'label.user'|trans }}</th>
</tr>
</thead>
<tbody>
{% for team in user.teams %}
<tr>
<td>
{{ team.name }}
</td>
<td>
{{ widgets.user_avatar(team.teamlead) }}
{#
{{ widgets.label(team.teamlead.displayName, 'success', 'label.teamlead'|trans) }}
#}
</td>
<td class="avatars">
{% for user in team.users %}
{{ widgets.user_avatar(user) }}
{#
{{ widgets.label_user(user) }}
#}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,9 +1,10 @@
<div class="row">
<div class="col-md-12">
<div class="box">
{#
{% if not title is empty %}
<div class="box-header with-border">
<h3 class="box-title">{{ title|trans }}</h3>
{#
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
</button>
@@ -20,8 +21,9 @@
</div>
<button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
</div>
</div>
#}
</div>
{% endif %}
<div class="box-body">
<div class="row">
<div class="col-md-12">

View File

@@ -1,20 +1,22 @@
{% import "macros/widgets.html.twig" as widgets %}
{% if not title is empty %}
{{ widgets.page_header(title) }}
{% endif %}
{% set width = widgets|length %}
{% set rawWidth = 12 / width %}
{% set columnWidth = rawWidth|round(0, 'floor') %}
<div class="row">
{% for widget in widgets %}
{% set columnSize = columnWidth %}
{% if width == 5 and (loop.first or loop.last) %}
{% set columnSize = columnWidth + 1 %}
{% endif %}
<div class="col-md-{{ columnSize }} col-sm-{{ columnSize * 2 }} col-xs-{{ columnSize * 4 }}">
{{ render_widget(widget) }}
</div>
{% endfor %}
</div>
{% if width > 0 %}
{% if not title is empty %}
{{ widgets.page_header(title) }}
{% endif %}
{% set rawWidth = 12 / width %}
{% set columnWidth = rawWidth|round(0, 'floor') %}
<div class="row">
{% for widget in widgets %}
{% set columnSize = columnWidth %}
{% if width == 5 and (loop.first or loop.last) %}
{% set columnSize = columnWidth + 1 %}
{% endif %}
<div class="col-md-{{ columnSize }} col-sm-{{ columnSize * 2 }} col-xs-{{ columnSize * 4 }}">
{{ render_widget(widget) }}
</div>
{% endfor %}
</div>
{% endif %}

View File

@@ -15,14 +15,6 @@
{{ encore_entry_link_tags('chart') }}
{{ encore_entry_script_tags('chart') }}
{% if not title is empty %}
<p class="text-center">
<strong>
{{ title|trans }}
</strong>
</p>
{% endif %}
<div class="chart">
<canvas id="{{ chart_id }}" style="height: {{ kimai_context.chart.height }}px;"></canvas>
</div>

View File

@@ -0,0 +1,60 @@
{% import "macros/widgets.html.twig" as widgets %}
{% import "macros/progressbar.html.twig" as progress %}
{% set projectStats = data %}
{% set title = options.title|default('label.my_team_projects') %}
{% set widgetId = options.id %}
{% if projectStats|length > 0 %}
<div class="row">
<div class="col-md-12">
<div class="box box-{{ admin_lte_context.widget.type }} WidgetUserTeamProjects" id="{{ widgetId }}">
{% if not title is empty %}
<div class="box-header with-border">
<h3 class="box-title">{{ title|trans }}</h3>
</div>
{% endif %}
<div class="box-body">
<table class="table table-hover dataTable" role="grid">
<thead>
<tr>
<th>{{ 'label.project'|trans }}</th>
<th class="hidden-xs">{{ 'label.team'|trans }}</th>
<th style="width:50%">{{ 'label.progress'|trans }}</th>
</tr>
</thead>
<tbody>
{% for stats in projectStats %}
{% set project = stats.project %}
<tr>
<td>
{{ widgets.label_project(stats.project) }}
<br>
<small>{{ widgets.label_customer(stats.project.customer) }}</small>
</td>
<td class="hidden-xs">
{% for team in project.teams %}
{% if app.user.isInTeam(team) %}
{{ widgets.label_team(team) }}
{% endif %}
{% endfor %}
</td>
<td style="width:50%">
{% if project.timeBudget is not empty and project.timeBudget > 0 %}
{% set budgetLeft = project.timeBudget - stats.recordDuration %}
{{ progress.progressbar_small(project.timeBudget, stats.recordDuration, budgetLeft, budgetLeft|duration) }}
{% elseif project.budget is not empty and project.budget > 0 %}
{% set budgetLeft = project.budget - stats.recordRate %}
{{ progress.progressbar_small(project.budget, stats.recordRate, budgetLeft, budgetLeft|money(project.customer.currency)) }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,58 @@
{% import "macros/widgets.html.twig" as widgets %}
{% set teams = data %}
{% set title = options.title|default('label.my_teams') %}
{% set widgetId = options.id %}
{% if teams|length > 0 %}
<div class="row">
<div class="col-md-12">
<div class="box box-{{ admin_lte_context.widget.type }} WidgetUserTeams" id="{{ widgetId }}">
{% if not title is empty %}
<div class="box-header with-border">
<h3 class="box-title">{{ title|trans }}</h3>
</div>
{% endif %}
<div class="box-body">
<table class="table table-hover dataTable" role="grid">
<thead>
<tr>
<th>{{ 'label.team'|trans }}</th>
<th class="text-center">{{ 'label.teamlead'|trans }}</th>
<th>{{ 'label.user'|trans }}</th>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td>
{{ team.name }}
</td>
<td class="text-center">
{{ widgets.user_avatar(team.teamlead) }}
</td>
<td class="avatars">
{% set userTeamCount = team.users|length %}
{% for user in team.users %}
{% set teamHiddenId = widgetId ~ '_' ~ team.id ~ '_hiddenUser' %}
{{ widgets.user_avatar(user) }}
{% if userTeamCount > 5 and loop.index == 5 and not loop.last %}
<a href="#" onclick="$('#{{ teamHiddenId }}').toggleClass('hidden');$(this).hide();return false;" class="badge">{{ 'label.plus_more'|trans({'%count%': (userTeamCount - 5)}) }}</a>
<span class="hidden" id="{{ teamHiddenId }}">
{% endif %}
{% if userTeamCount > 5 and loop.index != 5 and loop.last %}
</span>
{% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endif %}