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 }})"> {% 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 %}