User profile layout (#2402)

This commit is contained in:
Kevin Papst
2021-03-06 12:34:34 +01:00
committed by GitHub
parent d3099aca39
commit 5583caa9e4
30 changed files with 550 additions and 268 deletions

View File

@@ -28,80 +28,17 @@
{% endmacro %}
{% macro user_permissions(view) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% if view != 'index' and is_granted('role_permissions') %}
{% set actions = actions|merge({'permissions': path('admin_user_permissions')}) %}
{% endif %}
{% if view != 'role' and is_granted('role_permissions') %}
{% set actions = actions|merge({'create': {'url': path('admin_user_roles'), 'class': 'modal-ajax-form'}}) %}
{% endif %}
{% set actions = actions|merge({'help': {'url': 'permissions.html'|docu_link, 'target': '_blank'}}) %}
{% set event = trigger('actions.user_permissions', {'actions': actions, 'view': view}) %}
{{ widgets.page_actions(event.payload.actions) }}
{% deprecated 'The "user_permissions" macro from user/action.html.twig is deprecated since 1.14 and will be removed with 2.0. Use "permission/actions.html.twig" instead.' %}
{% import "permission/actions.html.twig" as realMacro %}
{{ realMacro.user_permissions(view) }}
{% endmacro %}
{% macro user(user, view, options) %}
{% import "macros/widgets.html.twig" as widgets %}
{% set actions = {} %}
{% if user.id is not empty %}
{% set view_other = is_granted('view_other_timesheet') %}
{% if is_granted('view', user) %}
{% set actions = actions|merge({'profile-stats': {'url': path('user_profile', {'username' : user.username})}}) %}
{% endif %}
{% if actions|length > 0 %}
{% set actions = actions|merge({'divider': null}) %}
{% endif %}
{% set subActions = {} %}
{% if is_granted('edit', user) %}
{% set subActions = subActions|merge({'edit': path('user_profile_edit', {'username' : user.username})}) %}
{% endif %}
{% if is_granted('preferences', user) %}
{% set subActions = subActions|merge({'settings': {'url': path('user_profile_preferences', {'username' : user.username})}}) %}
{% endif %}
{% if is_granted('password', user) %}
{% set subActions = subActions|merge({'password': {'url': path('user_profile_password', {'username' : user.username}), 'title': ('profile.password'|trans)}}) %}
{% endif %}
{% if is_granted('api-token', user) %}
{% set subActions = subActions|merge({'api-token': {'url': path('user_profile_api_token', {'username' : user.username}), 'title': ('profile.api-token'|trans)}}) %}
{% endif %}
{% if is_granted('teams', user) %}
{% set subActions = subActions|merge({'teams': {'url': path('user_profile_teams', {'username' : user.username}), 'title': ('profile.teams'|trans)}}) %}
{% endif %}
{% if is_granted('roles', user) %}
{% set subActions = subActions|merge({'roles': {'url': path('user_profile_roles', {'username' : user.username}), 'title': ('profile.roles'|trans)}}) %}
{% endif %}
{% if subActions|length > 0 %}
{% set actions = actions|merge(subActions) %}
{% set actions = actions|merge({'divider2': null}) %}
{% endif %}
{% if is_granted('view_reporting') %}
{% if view_other or app.user.id == user.id %}
{% set actions = actions|merge({'report': path('report_user_month', {'user': user.id})}) %}
{% endif %}
{% endif %}
{% if view_other and user.enabled %}
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'users': [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 %}
{% if options.back is defined %}
{% set actions = actions|merge({'back': options.back}) %}
{% endif %}
{% set event = trigger('actions.user', {'actions': actions, 'view': view, 'user': user}) %}
{% set event = actions(app.user, 'user', {'view': view, 'user': user}) %}
{% if view == 'index' %}
{{ widgets.table_actions(event.payload.actions) }}
{{ widgets.table_actions(event.actions) }}
{% else %}
{{ widgets.entity_actions(event.payload.actions) }}
{{ widgets.page_actions(event.actions) }}
{% endif %}
{% endmacro %}

View File

@@ -1,6 +1,6 @@
{% extends 'user/layout.html.twig' %}
{% block main %}
{% block profile_content %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}

View File

@@ -1,6 +1,7 @@
{% extends 'user/layout.html.twig' %}
{% block main %}
{% block profile_content %}
{{ form_start(form) }}
{% for section in sections %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}

View File

@@ -5,8 +5,9 @@
{% import "user/actions.html.twig" as actions %}
{% set columns = {
'avatar': {'class': 'alwaysVisible w-min', 'title': null, 'orderBy': false},
'alias': {'class': 'alwaysVisible'},
'title': {'class': 'hidden-xs hidden-sm'},
'title': {'class': 'hidden-xs hidden-sm hidden'},
'email': {'class': 'hidden-xs hidden-sm hidden', 'orderBy': false},
'lastLogin': {'class': 'hidden-xs hidden-sm hidden', 'orderBy': false},
'roles': {'class': 'hidden-sm', 'orderBy': false},
@@ -27,9 +28,10 @@
{% block page_title %}{{ 'admin_user.title'|trans }}{% endblock %}
{% block page_search %}{{ toolbar.dropDownSearch(toolbarForm) }}{% endblock %}
{% block page_actions %}{{ actions.users('index') }}{% endblock %}
{% block page_icon %}{{ 'user'|icon }}{% endblock %}
{% block main_before %}
{{ tables.data_table_column_modal(tableName, columns) }}
{{ tables.data_table_column_modal(tableName, columns, 'kimai.userUpdate') }}
{% endblock %}
{% block main %}
@@ -41,7 +43,8 @@
{% for entry in entries %}
<tr{% if is_granted('view', entry) %} class="open-edit alternative-link" data-href="{{ path('user_profile', {'username': entry.username}) }}"{% endif %}>
<td class="{{ tables.data_table_column_class(tableName, columns, 'alias') }}">{{ widgets.user_avatar(entry) }} {{ widgets.username(entry) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'avatar') }}">{{ widgets.user_avatar(entry) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'alias') }}">{{ widgets.username(entry) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'title') }}">{{ entry.title }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'email') }}">{{ entry.email }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'lastLogin') }}">{% if entry.lastLogin is not null %}{{ entry.lastLogin|date_full }}{% endif %}</td>

View File

@@ -1,111 +1,31 @@
{% extends 'base.html.twig' %}
{% import "user/actions.html.twig" as actions %}
{% import "macros/widgets.html.twig" as widgets %}
{% block page_title %}{% if not user.alias is empty %}{{ user.alias }}{% else %}{{ user.username }}{% endif %}{% endblock %}
{% block page_subtitle %}{% if not user.alias is empty %}{{ user.username }}{% endif %}{% endblock %}
{% block page_title %}{{ 'admin_user.title'|trans }}{% endblock %}
{% block page_actions %}{{ actions.user(user, tab) }}{% endblock %}
{% block page_icon %}{{ 'user'|icon }}{% endblock %}
{% block main %}
<div class="row">
<div class="col-md-8">
<div class="col-xs-12 col-sm-9 col-md-9 col-lg-10">
{% block profile_intro %}
<div class="panel panel-default">
<div class="panel-body">
{{ widgets.user_avatar(user, false, 'avatar-md') }}
{{ user.displayName }}
{% if user.title is not empty %} &ndash; {{ user.title }} {% endif %}
</div>
</div>
{% endblock %}
{% block profile_content %}{% endblock %}
</div>
<div class="col-md-4">
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block box_body_class %}box-profile{% endblock %}
{% block box_body %}
<div class="text-center">
{{ widgets.user_avatar(user) }}
<h3 class="profile-username">{{ widgets.username(user) }}</h3>
<p class="text-muted">{{ user.title }}</p>
</div>
{% set seeOwnRate = is_granted('view_rate_own_timesheet') %}
<table class="table">
<tr>
<th>{{ 'stats.durationMonth'|trans }}</th>
<td class="text-nowrap pull-right">{{ stats.durationThisMonth|duration }}</td>
</tr>
{% if seeOwnRate %}
<tr>
<th>{{ 'stats.amountMonth'|trans }}</th>
{# TODO which currency shall we use here? #}
<td class="text-nowrap pull-right">{{ stats.amountThisMonth|money }}</td>
</tr>
{% endif %}
<tr>
<th>{{ 'stats.durationTotal'|trans }}</th>
<td class="text-nowrap pull-right">{{ stats.durationTotal|duration }}</td>
</tr>
{% if seeOwnRate %}
<tr>
<th>{{ 'stats.amountTotal'|trans }}</th>
{# TODO which currency shall we use here? #}
<td class="text-nowrap pull-right">{{ stats.amountTotal|money }}</td>
</tr>
{% endif %}
</table>
{% endblock %}
{% endembed %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% block box_title %}{{ 'profile.about_me'|trans }}{% endblock %}
{% block box_body %}
{# colors = purple, blue, aqua, red, green #}
<table class="table no-border">
<tr>
<th>{{ 'label.id'|trans }}</th>
<td class="text-nowrap pull-right">{{ user.id }}</td>
</tr>
<tr>
<th>{{ 'label.username'|trans }}</th>
<td class="text-nowrap pull-right">{{ user.username }}</td>
</tr>
<tr>
<th>{{ 'profile.first_entry'|trans }}</th>
<td class="text-nowrap pull-right">{{ stats.firstEntry|date_short }}</td>
</tr>
<tr>
<th>{{ 'profile.registration_date'|trans }}</th>
<td class="text-nowrap pull-right">{{ user.registeredAt|date_short }}</td>
</tr>
{% if is_granted('hourly-rate', user) %}
<tr>
<th>{{ 'label.hourlyRate'|trans }}</th>
<td class="text-nowrap pull-right">{{ user.preferenceValue('hourly_rate') }}</td>
</tr>
{% endif %}
</table>
{% endblock %}
{% endembed %}
{% if user.teams is not empty and (is_granted('teams', user) or (app.user == user and is_granted('view_team_member'))) %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block box_title %}{{ 'label.my_teams'|trans }}{% endblock %}
{% block box_tools %}
{% if is_granted('roles', user) %}
<a class="btn-box-tool" href="{{ path('user_profile_teams', {'username': user.username}) }}"><i class="{{ 'edit'|icon }}"></i></a>
{% endif %}
{% endblock %}
{% block box_body %}
{{ widgets.team_list(user.teams) }}
{% endblock %}
{% endembed %}
{% endif %}
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-2">
<div class="hidden-xs">
{% set event = actions(app.user, 'user', {'view': tab, 'user': user}) %}
{{ widgets.list_group_actions(event.actions, app.request.requestUri) }}
</div>
{% block profile_navbar %}{% endblock %}
</div>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
document.addEventListener('kimai.initialized', function() {
KimaiReloadPageWidget.create('kimai.teamUpdate', true);
});
</script>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends 'user/layout.html.twig' %}
{% block main %}
{% block profile_content %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}

View File

@@ -11,8 +11,16 @@
{{ encore_entry_script_tags('chart') }}
{% endblock %}
{% block profile_navbar %}
{{ _self.about_me(user, stats) }}
{% endblock %}
{% block profile_intro %}{% endblock %}
{% block profile_content %}
{{ _self.profile_box_horizontal(user, stats) }}
{% if years is empty %}
{{ widgets.nothing_found() }}
{% endif %}
@@ -49,14 +57,13 @@
}
}
}
{%- if is_granted('view_reporting') and (app.user.id == user.id or is_granted('view_other_timesheet')) -%}
{%- if user.enabled and is_granted('view_reporting') and (app.user.id == user.id or is_granted('view_other_timesheet')) -%}
,
onClick: function(event, elements) {
var element = elements[0];
var month = this.data.datasets[0].monthData[element._index];
var formattedMonth = moment(month).format('{{ stat_date_format }}');
var reportUrl = '{{ path('report_user_month', {'user': user.id, 'date': 'XXXXX'})|raw }}'.replace('XXXXX', formattedMonth);
document.location = reportUrl;
document.location = '{{ path('report_user_month', {'user': user.id, 'date': 'XXXXX'})|raw }}'.replace('XXXXX', formattedMonth);
}
{% endif %}
};
@@ -116,4 +123,147 @@
{% endfor %}
{% if user.teams is not empty and (is_granted('teams', user) or (app.user == user and is_granted('view_team_member'))) %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block box_title %}{{ 'label.my_teams'|trans }}{% endblock %}
{% block box_body %}
{{ widgets.team_list(user.teams) }}
{% endblock %}
{% endembed %}
{% endif %}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
document.addEventListener('kimai.initialized', function() {
KimaiReloadPageWidget.create('kimai.teamUpdate', true);
});
</script>
{% endblock %}
{% macro about_me(user, stats) %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block box_title %}
<a href="mailto:{{ user.email }}" title="{{ 'label.email'|trans }}">{{ widgets.icon('mail') }}</a>
<span data-toggle="tooltip" title="{{ 'label.id'|trans }}: {{ user.id }}">{{ 'profile.about_me'|trans }}</span>
{% endblock %}
{% block box_body %}
<p>
<strong>{{ 'profile.first_entry'|trans }}</strong><br>
{# FIXME use a configuration for it #}
{{ stats.firstEntry|date_short }}
</p>
<p>
<strong>{{ 'profile.registration_date'|trans }}</strong><br>
{{ user.registeredAt|date_short }}
</p>
{% if is_granted('hourly-rate', user) and user.preferenceValue('hourly_rate') is not null %}
<p>
<strong>{{ 'label.hourlyRate'|trans }}</strong><br>
{{ user.preferenceValue('hourly_rate') }}
</p>
{% endif %}
{% endblock %}
{% endembed %}
{% endmacro %}
{% macro profile_box_vertical(user, stats) %}
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block box_body_class %}box-profile box-user-profile{% endblock %}
{% block box_body %}
<div class="text-center">
{{ widgets.user_avatar(user) }}
<h3 class="profile-username">{{ widgets.username(user) }}</h3>
<p class="text-muted">{{ user.title }}</p>
</div>
{% set seeOwnRate = is_granted('view_rate_own_timesheet') %}
<table class="table">
<tr>
<th>{{ 'stats.durationMonth'|trans }}</th>
<td class="text-nowrap pull-right">{{ stats.durationThisMonth|duration }}</td>
</tr>
{% if seeOwnRate %}
<tr>
<th>{{ 'stats.amountMonth'|trans }}</th>
{# TODO which currency shall we use here? #}
<td class="text-nowrap pull-right">{{ stats.amountThisMonth|money }}</td>
</tr>
{% endif %}
<tr>
<th>{{ 'stats.durationTotal'|trans }}</th>
<td class="text-nowrap pull-right">{{ stats.durationTotal|duration }}</td>
</tr>
{% if seeOwnRate %}
<tr>
<th>{{ 'stats.amountTotal'|trans }}</th>
{# TODO which currency shall we use here? #}
<td class="text-nowrap pull-right">{{ stats.amountTotal|money }}</td>
</tr>
{% endif %}
</table>
{% endblock %}
{% endembed %}
{% endmacro %}
{% macro profile_box_horizontal(user, stats) %}
{% import "@AdminLTE/Macros/default.html.twig" as macro %}
{% import "macros/widgets.html.twig" as widgets %}
{% set color = kimai_context.chart.background_color %}
{% set event = trigger('user.profile_background', {'color': color, 'font': color|font_contrast, 'user': user, 'image': null}) %}
{% set config = event.payload %}
<div class="box box-widget widget-user box-user-profile">
<div class="widget-user-header" style="{% if config.image is not null %}background: url('{{ config.image }}') center center;{% else %}background-color: {{ config.color }}{% endif %}">
<h3 class="widget-user-username" style="color: {{ config.font }}">
{{ widgets.username(user) }}
</h3>
<h5 class="widget-user-desc" style="color: {{ config.font }}">{{ user.title }}</h5>
</div>
<div class="widget-user-image">
{{ widgets.user_avatar(user) }}
</div>
<div class="box-footer">
{% if stats is not null %}
{% set seeOwnRate = is_granted('view_rate_own_timesheet') %}
{% set columnLength = seeOwnRate ? 3 : 6 %}
<div class="row">
<div class="col-sm-{{ columnLength }} border-right">
<div class="description-block">
<h5 class="description-header">{{ stats.durationThisMonth|duration }}</h5>
<span class="description-text">{{ 'stats.durationMonth'|trans }}</span>
</div>
</div>
{% if seeOwnRate %}
<div class="col-sm-{{ columnLength }} border-right">
<div class="description-block">
<h5 class="description-header">{{ stats.amountThisMonth|money }}</h5>
<span class="description-text">{{ 'stats.amountMonth'|trans }}</span>
</div>
</div>
{% endif %}
<div class="col-sm-{{ columnLength }} border-right">
<div class="description-block">
<h5 class="description-header">{{ stats.durationTotal|duration }}</h5>
<span class="description-text">{{ 'stats.durationTotal'|trans }}</span>
</div>
</div>
{% if seeOwnRate %}
<div class="col-sm-{{ columnLength }} border-right">
<div class="description-block">
<h5 class="description-header">{{ stats.amountTotal|money }}</h5>
<span class="description-text">{{ 'stats.amountTotal'|trans }}</span>
</div>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endmacro %}

View File

@@ -1,7 +1,7 @@
{% extends 'user/layout.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% block main %}
{% block profile_content %}
<div class="row">
<div class="col-md-12">