Subversion Repositories web.kimai2

Rev

Blame | Last modification | View Log | Download

{%- macro page_actions(actions) -%}
    {% set large = true %}
    {% set btnClasses = 'btn-primary' %}
    {% set helpClasses = '' %}
    {% if tabler_bundle.isNavbarOverlapping() %}
        {% set helpClasses = 'btn-dark' %}
    {% elseif not tabler_bundle.isDarkMode() %}
        {% set btnClasses = 'btn-white' %}
    {% endif %}
    {% set later = {} %}
    {% set help = null %}
    <div class="page-actions">
        <div class="pa-desktop d-none d-sm-inline-flex btn-list">
        {%- for icon, values in actions  %}
            {% if 'help' in icon %}
                {% set help = values %}
            {% elseif 'divider' in icon and values is null %}
                {# what to do here ? #}
            {% else %}
                {% if values.children is defined and values.children|length > 0 %}
                        <div class="dropdown">
                            <button type="button" class="btn {{ btnClasses}} dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                {{ icon(icon, true) }}{% if large %} {{ values.title is defined ? values.title|trans : icon|trans({}, 'actions') }}{% endif %}
                            </button>
                            <div class="dropdown-menu">
                            {%- for icon, values in values.children %}
                                {% set values = values|merge({class: 'dropdown-item action-' ~ icon ~ ' ' ~ (values.class|default(''))}) %}
                                {{ _self.action_button(false, values, false) }}
                                {% endfor %}
                            </div>
                        </div>
                {% else %}
                    {% set values = values|merge({combined: large, class: btnClasses ~ ' action-' ~ icon ~ ' ' ~ (values.class|default(''))}) %}
                    {{ _self.action_button(icon, values) }}
                {% endif %}
            {% endif %}
        {% endfor -%}
        {% if help is not null %}
            {% set help = help|merge({class: helpClasses ~ ' action-help ' ~ (help.class|default(''))}) %}
            {{ _self.action_button('help', help) }}
        {% endif %}
        </div>
        <div class="pa-mobile d-inline-flex d-sm-none btn-list">
            {% set btnClass = 'btn btn-icon ' %}
            {% if tabler_bundle.isNavbarOverlapping() %}
                {% set btnClass = 'btn btn-icon btn-dark' %}
            {% elseif not tabler_bundle.isDarkMode() %}
                {% set btnClass = 'btn btn-icon btn-white' %}
            {% endif %}
            {{ _self.table_actions(actions, btnClass) }}
        </div>
    </div>
{%- endmacro -%}

{% macro page_header(title) %}
    <h2 class="page-header">{{ title|trans }}</h2>
{% endmacro %}

{% macro label_boolean(visible) %}
    {% if visible %}
        {{ _self.label('yes'|trans, 'success') }}
    {% else %}
        {{ _self.label('no'|trans, 'default') }}
    {% endif %}
{% endmacro %}

{% macro label_visible(visible) %}
    {{ _self.label_boolean(visible) }}
{% endmacro %}

{% macro label_role(role) %}
    {% set color = 'primary' %}
    {% if role == 'ROLE_SUPER_ADMIN' %}
        {% set color = 'danger' %}
    {% elseif role == 'ROLE_ADMIN' %}
        {% set color = 'warning' %}
    {% elseif role == 'ROLE_TEAMLEAD' %}
        {% set color = 'success' %}
    {% elseif role == 'ROLE_USER' %}
        {% set color = 'gray' %}
    {% endif %}
    {{ _self.label(role|trans, color) }}
{% endmacro %}

{% macro username(user) %}
    {{- user.displayName -}}
{% endmacro %}

{% macro label_user(user) %}
    {{ _self.label_color(user.displayName, user.color|colorize(user.displayName)) }}
{% endmacro %}

{% macro label_team(team) %}
    {{ _self.label_color(team.name, team.color|colorize(team.name)) }}
{% endmacro %}

{% macro user_avatar(user, tooltip, class, badge) %}
    {% set avatar = null %}
    {% if user.avatar is not empty and kimai_config.themeAllowAvatarUrls %}
        {% set avatar = asset(user.avatar, 'avatars') %}
    {% endif %}
    {% if not user.enabled %}
        {% set badge = 'danger' %}
    {% endif %}
    {% set color = user.color|colorize(user.displayName) %}
    <span class="avatar {{ class }}"
        {%- if tooltip is not same as (false) %} data-toggle="tooltip" data-placement="top" title="{{ tooltip|default(user.displayName) }}"{% endif -%}
        {% if avatar is not null %}
            style="background-image: url({{ avatar }})">&nbsp;
        {% else %}
            style="background-color: {{ color }}; color: {{ color|font_contrast }}">{{ user.initials }}
        {% endif %}
        {%- if badge is not null -%}<span class="badge bg-{{ badge }}"></span>{%-endif -%}
    </span>
{% endmacro %}

{% macro avatar(initials, color, tooltip, class) %}
    {% set color = color|colorize(initials) %}
    <span class="avatar {{ class ?? '' }}" style="background-color: {{ color }}; color: {{ color|font_contrast }}"
    {%- if tooltip is not same as null %} data-toggle="tooltip" data-placement="top" title="{{ tooltip }}"{% endif -%}>{{ initials }}</span>
{% endmacro %}

{% macro avatar_deleted(tooltip) %}
    {% set initials = tooltip ?? '??' %}
    {% set tooltip = 'deleted'|trans %}
    {% set color = null|colorize(initials) %}
    <span class="avatar {{ class ?? '' }}" style="background-color: {{ color }}; color: {{ color|font_contrast }}"
    {%- if tooltip is not same as null %} data-toggle="tooltip" data-placement="top" title="{{ tooltip }}"{% endif -%}>{{ initials }}</span>
{% endmacro %}

{#
    options = {'inherit': true}
#}
{% macro label_activity(activity, options) %}
    {% set inherit = options.inherit ?? true %}
    {% set isVisible = activity.visible %}
    {% set color = activity.color %}
    {% if color is empty and inherit and activity.project is not null %}
        {% set color = activity.project.color ?? activity.project.customer.color %}
    {% endif %}
    {% if color is empty %}
        {% set color = color|colorize(activity.name) %}
    {% endif %}
    {% if isVisible and not activity.project is null %}
        {% set isVisible = activity.project.visible %}
        {% if isVisible and not activity.project.customer is null %}
            {% set isVisible = activity.project.customer.visible %}
        {% endif %}
    {% endif %}
    {{ _self.label_color_dot('activity', isVisible, activity.name, null, color) }}
{% endmacro %}

{#
    options = {'inherit': true}
#}
{% macro label_project(project, options) %}
    {% set inherit = options.inherit ?? true %}
    {% set isVisible = false %}
    {% if project.visible and project.customer.visible %}
        {% set isVisible = true %}
    {% endif %}
    {% set color = project.color %}
    {% if color is empty and inherit %}
        {% set color = project.customer.color %}
    {% endif %}
    {% if color is empty %}
        {% set color = color|colorize(project.name) %}
    {% endif %}
    {{ _self.label_color_dot('project', isVisible, project.name, null, color) }}
{% endmacro %}

{% macro label_customer(customer) %}
    {% set color = customer.color %}
    {% if color is empty %}
        {% set color = color|colorize(customer.name) %}
    {% endif %}
    {{ _self.label_color_dot('customer', customer.visible, customer.name, null, color) }}
{% endmacro %}

{# Use for list views and the main column (if the entity has something like a name) #}
{% macro label_name(label, color, isVisible) %}
    {{ _self.label_color_dot('color', isVisible, label, null, color) }}
{% endmacro %}

{# Use in datatables to show linked entity names #}
{% macro label_dot(label, color, isVisible) %}
    {{ _self.label_color_dot('color', isVisible, label, null, color|colorize(label)) }}
{% endmacro %}

{# for @internal use only #}
{% macro label_color_dot(type, isVisible, name, url, color) %}
    {%- if url is not empty -%}<a href="{{ url }}">{% endif %}
    <span class="pe-1 label-{{ type }}{{ isVisible is same as (false) ? ' label-invisible' : '' }}">
        <span class="badge me-1" {% if color is not empty %} style="background-color:{{ color }}"{% endif %}></span>
        {{- name -}}
    </span>
    {%- if url is not empty -%}</a>{% endif %}
{% endmacro %}

{% macro badge_team_access(teams) %}
    {% if teams|length > 0 %}
        {{ _self.badge_counter(teams|length) }}
    {% else %}
        {{ _self.badge_counter(0, null, 'bg-gray') }}
    {% endif %}
{% endmacro %}

{% macro badge_counter(count, url, type) %}
    {% if url %}
        <a href="{{ url }}"><span class="badge {{ type|default('bg-blue') }}">{{ count }}</span></a>
    {% else %}
        <span class="badge {{ type|default('bg-blue') }}">{{ count }}</span>
    {% endif %}
{% endmacro %}

{% macro label(title, type, tooltip) %}
    <span {% if tooltip %}data-toggle="tooltip" data-placement="top" title="{{ tooltip }}" {% endif %}class="badge bg-{{ type|default('success') }}">{{ title }}</span>
{% endmacro %}

{% macro label_color(title, color) %}
    <span class="badge" style="background-color: {{ color|default_color }};color: {{ color|default_color|font_contrast }}">{{ title }}</span>
{% endmacro %}

{% macro badge(title, color) %}
    <span class="badge"{% if color is not null %} style="background-color:{{ color }}; color:{{ color|font_contrast }}"{% endif %}>{{ title }}</span>
{% endmacro %}

{% macro form_errors(form) %}
    {% if form.vars.errors|length > 0 %}
        {% set message = '' %}
        {% for error in form.vars.errors %}
            {% set message = message ~ error.message %}
            {% if not loop.last %}
                {% set message = message ~ '<br>'  %}
            {% endif %}
        {% endfor %}
        {% if message != '' %}
            {{ _self.alert('danger', message) }}
        {% endif %}
    {% endif %}
{% endmacro %}

{% macro alert(type, description, title, icon, dismissible) %}
    {% from '@theme/components/alert.html.twig' import alert %}
    {{ alert({type: type, description: description|trans, title: title|trans, icon: icon, dismissible: dismissible, important: true}) }}
{% endmacro %}

{% macro callout(type, description, title, icon) %}
    {% from '@theme/components/alert.html.twig' import alert %}
    {{ alert({type: type|default('danger'), description: description|trans, title: title|trans, icon: icon, dismissible: false, important: true}) }}
{% endmacro %}

{% macro table_actions(actions, class) %}
    {% if actions|length >= 1 %}
        {% import '@theme/components/actions.html.twig' as macro %}
        {{ macro.actions(actions, {'class': class|default('btn-sm'), translationDomain: 'actions'}) }}
    {% endif %}
{% endmacro %}

{% macro card_tool_visibility(tableName) %}
    {{ _self.card_tool_button('visibility', {'modal': ('#modal_' ~ tableName)}) }}
{% endmacro %}

{% macro card_tool_button(icon, values) %}
    {% import '@theme/components/buttons.html.twig' as macro %}
    {% set values = values|merge({'tooltip_attr': 'data-toggle'}) %}
    {{ macro.action_cardtoolbutton(icon, values) }}
{% endmacro %}

{% macro card_tool_create(create_url) %}
    {{ _self.card_tool_button('create', {'url': create_url, 'class': 'modal-ajax-form open-edit', 'title': 'create'|trans}) }}
{% endmacro %}

{% macro action_button(icon, values, type) %}
    {% import '@theme/components/button.html.twig' as macro %}
    {% set values = (values ?? {})|merge({'tooltip_attr': 'data-toggle'}) %}
    {{ macro.button(icon, values, type) }}
{% endmacro %}

{% macro tag_list(taglist) %}
    {% for tag in taglist %}
        {{ _self.badge(tag.name, tag.color|colorize(tag.name)) }}
    {% endfor %}
{% endmacro %}

{% macro meta_field_value(entity, field) %}
    {% set metaField = entity.metaField(field.name) %}
    {% if not metaField is null and metaField.value is not null and metaField.value is not empty %}
        {% set metaField = metaField.merge(field) %}
        {{ _self.form_type_value(metaField.type, metaField.value, entity) }}
    {% endif %}
{% endmacro %}

{% macro form_type_value(type, value, entity) %}
    {% if 'ColorPickerType' in type or 'ColorChoiceType' in type %}
        {% if value is not empty %}
            <span class="label-color" data-toggle="tooltip" data-placement="top" title="{{ value }}">
                <i class="dot {{ 'dot'|icon(true) }} fa-fw" style="color:{{ value }}"></i>
            </span>
        {% endif %}
    {% elseif 'DurationType' in type %}
        {{ value|duration }}
    {% elseif 'YesNoType' in type or 'CheckBoxType' in type %}
        {{ _self.label_boolean(value) }}
    {% elseif 'DatePickerType' in type %}
        {{ value|date_short }}
    {% elseif 'DateTimePickerType' in type %}
        {{ value|date_time }}
    {% elseif 'CountryType' in type %}
        {{ value|country_name }}
    {% elseif 'CurrencyType' in type %}
        {{ value|currency_name }}
    {% elseif 'LanguageType' in type %}
        {{ value|locale_name }}
    {% elseif 'TagsType' in type %}
        {% for tag in value|split(',') %}
            {% if tag is not empty %}
                {{ _self.badge(tag, null|colorize(tag)) }}
            {% endif %}
        {% endfor %}
    {% elseif 'MoneyType' in type %}
        {% set classname = class_name(entity) %}
        {% if entity is null %}
            {{ value }}
        {% elseif classname == 'App\\Entity\\Timesheet' %}
            {{ value|money(entity.project.customer.currency) }}
        {% elseif classname == 'App\\Entity\\Customer' %}
            {{ value|money(entity.currency) }}
        {% elseif classname == 'App\\Entity\\Project' %}
            {{ value|money(entity.customer.currency) }}
        {% elseif classname == 'App\\Entity\\Activity' and entity.project is not null %}
            {{ value|money(entity.project.customer.currency) }}
        {% else %}
            {{ value }}
        {% endif %}
    {% elseif 'TextareaType' in type %}
        {{ value|nl2br }}
    {% elseif 'EmailType' in type %}
        <a href="mailto:{{ value }}">{{ value }}</a>
    {% elseif 'UrlType' in type %}
        <a href="{{ value }}" target="_blank">{{ value }}</a>
    {% else %}
        {{ value }}
    {% endif %}
{% endmacro %}

{% macro team_list(teams, options) %}
    {% set showTitle = options['title'] ?? true %}
    {% set collapseAt = options['collapse'] ?? 12 %}
    {% set nameClass = options['name_class'] ?? '' %}
    {% set viewTeam = is_granted('view_team') %}
    <table class="table table-hover dataTable" role="grid">
        {% if showTitle %}
        <thead>
            <tr>
                <th class="hw-min">{{ 'team'|trans }}</th>
                <th class="d-none d-sm-table-cell">{{ 'team.member'|trans({}, 'teams') }}</th>
            </tr>
        </thead>
        {% endif %}
        <tbody>
        {% for team in teams|sort((a, b) => a.name <=> b.name) %}
            {% set members = team.members|filter(m => m.user.enabled) %}
            {% set class = 'avatar-rounded' %}
            <tr{% if viewTeam and is_granted('edit', team) %} class="modal-ajax-form open-edit" data-href="{{ path('admin_team_member', {'id': team.id}) }}"{% endif %}>
                <td class="{{ nameClass }}">
                    {{ _self.label_color_dot('color', true, team.name, null, team.color|colorize(team.name)) }}
                </td>
                <td class="d-none d-sm-table-cell avatars avatar-list avatar-list-stacked">
                    {% for member in members|sort((a, b) => b.teamlead <=> a.teamlead) %}
                        {% set user = member.user %}
                        {% if member.teamlead %}
                            {{ _self.user_avatar(user, ('teamlead'|trans ~ ': ' ~ user.displayName), (class ~ ' teamlead'), 'info') }}
                        {% else %}
                            {{ _self.user_avatar(user, null, class) }}
                        {% endif %}
                    {% endfor %}
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endmacro %}

{% macro nothing_found(events) %}
    {{ _self.callout('warning', 'error.no_entries_found') }}
    {% if events is not empty %}
    <script type="text/javascript">
        document.addEventListener('kimai.initialized', function() {
            KimaiReloadPageWidget.create('{{ events }}');
        });
    </script>
    {% endif %}
{% endmacro %}

{#
    To be used like this:
    <tr class="{{ class_customer_row(customer, now) }}">
#}
{% macro class_customer_row(customer, now) %}
    {%- if not customer.visible %}bg-orange-lt{% endif -%}
{% endmacro %}

{#
    To be used like this:
    <tr class="{{ class_tag_row(tag) }}">
#}
{% macro class_tag_row(tag) %}
    {%- if not tag.visible %}bg-orange-lt{% endif -%}
{% endmacro %}

{#
    To be used like this:
    <tr {{ customer_row_attr(customer, now) }}>
#}
{% macro customer_row_attr(customer, now) %}
    {%- set class = _self.class_customer_row(customer, now) %}
    {% set dataHref = '' %}
    {% if is_granted('view', customer) %}
        {% set class = class ~ ' alternative-link open-edit' %}
        {% set dataHref = path('customer_details', {'id': customer.id}) %}
    {% endif -%}
    class="{{ class }}" data-href="{{ dataHref }}"
{% endmacro %}

{#
    To be used like this:
    <tr class="{{ class_project_row(project, now) }}">
#}
{% macro class_project_row(project, now) %}
    {%- if not project.visible or (project.end is not null and project.end < now) %}bg-orange-lt{% endif -%}
{% endmacro %}

{#
    To be used like this:
    <tr {{ project_row_attr(project, now) }}>
#}
{% macro project_row_attr(project, now) %}
    {%- set class = _self.class_project_row(project, now) %}
    {% set dataHref = '' %}
    {% if is_granted('view', project) %}
        {% set class = class ~ ' alternative-link open-edit' %}
        {% set dataHref = path('project_details', {'id': project.id}) %}
    {% endif -%}
    class="{{ class }}" data-href="{{ dataHref }}"
{% endmacro %}

{#
    To be used like this:
    <tr {{ class_activity_row(activity, now) }}>
#}
{% macro class_activity_row(activity, now) %}
    {%- if not activity.visible %}bg-orange-lt{% endif -%}
{% endmacro %}

{#
    To be used like this:
    <tr {{ activity_row_attr(activity, now) }}>
#}
{% macro activity_row_attr(activity, now) %}
    {%- set class = _self.class_activity_row(activity, now) %}
    {% set dataHref = '' %}
    {% if is_granted('view', activity) %}
        {% set class = class ~ ' alternative-link open-edit' %}
        {% set dataHref = path('activity_details', {'id': activity.id}) %}
    {% endif -%}
    class="{{ class }}" data-href="{{ dataHref }}"
{% endmacro %}

{#
    To be used like this:
    <tr class="{{ class_user_row(user, now) }}">
#}
{% macro class_user_row(user) %}
    {%- if not user.enabled %}bg-orange-lt{% endif -%}
{% endmacro %}

{#
    To be used like this:
    <tr {{ user_row_attr(user) }}>
#}
{% macro user_row_attr(user) %}
    {%- set class = _self.class_user_row(user) %}
    {% set dataHref = '' %}
    {% if is_granted('view', user) %}
        {% set class = class ~ ' alternative-link open-edit' %}
        {% set dataHref = path('user_profile', {'username': user.username}) %}
    {% endif -%}
    class="{{ class }}" data-href="{{ dataHref }}"
{% endmacro %}

{# To be used mainly in <tr class="{{ class_user_row(user, now) }}"> #}
{% macro short_stats_row(stats) %}
    <div class="row">
        {% set colLength = 12 / stats|length %}
        {% for title, value in stats %}
        <div class="col-sm-{{ colLength }} border-right">
            <div class="description-block">
                <h5 class="description-header">{{ value }}</h5>
                <span class="description-text">{{ title }}</span>
            </div>
        </div>
        {% endfor %}
    </div>
{% endmacro %}

{% macro percent(maximum, current) %}
    {% if maximum > 0 %}
        {{ (current / (maximum / 100))|number_format(2) }} %
    {% else %}
        {{ 0|number_format(2) }} %
    {% endif %}
{% endmacro %}

{% macro page_reloader(events, full_reload) %}
    <script type="text/javascript">
        document.addEventListener('kimai.initialized', function() {
            KimaiReloadPageWidget.create('{{ events }}', {% if full_reload is same as true %}true{% else %}false{% endif %});
        });
    </script>
{% endmacro %}

{% macro work_times_result(should, actual, decimal) %}
    {% set result = actual - should %}
    {% if result == 0 %}
        <span class="work_time_exact">{{ result|duration(decimal) }}</span>
    {% elseif should == 0 and actual > 0 %}
        <span class="work_time_positive text-green">+{{ actual|duration(decimal) }}</span>
    {% elseif result < 0 %}
        <span class="work_time_negative text-red">{{ result|duration(decimal) }}</span>
    {% else %}
        <span class="work_time_positive text-green">+{{ result|duration(decimal) }}</span>
    {% endif %}
{% endmacro %}