User profile layout (#2402)
This commit is contained in:
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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' %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %} – {{ 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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user