Redmine/templates/config_form.html.twig
Gemini 1ea7af6435 fix: compat GLPI 11.0.4 — remove macro csrfField do form de config (1.5.1)
- config_form usava fields.csrfField() (inexistente no 11.0.4) -> erro fatal
- token CSRF agora via csrf_token_value (PHP); URL usa textField
- compatível com 11.0.0+

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:26:04 -03:00

135 lines
6.9 KiB
Twig

{% import 'components/form/fields_macros.html.twig' as fields %}
<form method="post" action="{{ action_url }}">
<input type="hidden" name="_glpi_csrf_token" value="{{ csrf_token_value }}">
<input type="hidden" name="id" value="1">
{# --- Conexão --- #}
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h4 class="card-title mb-0">
<i class="ti ti-plug-connected me-1"></i>{{ __('Conexão com o Redmine', 'redmine') }}
</h4>
<button type="submit" name="sync" value="1" class="btn btn-sm btn-outline-secondary">
<i class="ti ti-refresh me-1"></i>{{ __('Sincronizar Metadados', 'redmine') }}
</button>
</div>
<div class="card-body">
<div class="row">
{{ fields.textField('redmine_url', redmine_url, __('URL do Redmine', 'redmine'), {
'helper': 'https://redmine.exemplo.com.br'
}) }}
{{ fields.passwordField('api_key', '', __('Chave de API (Admin)', 'redmine'), {
'helper': has_key
? __('Deixe em branco para manter a chave atual', 'redmine')
: __('Chave de API de um usuário administrador do Redmine', 'redmine')
}) }}
</div>
</div>
</div>
{# --- Valores padrão da issue --- #}
<div class="card mb-3">
<div class="card-header">
<h4 class="card-title mb-0"><i class="ti ti-settings me-1"></i>{{ __('Valores padrão da tarefa (issue) Redmine', 'redmine') }}</h4>
</div>
<div class="card-body">
{% if not has_metadata %}
<div class="alert alert-warning">{{ __('Salve a URL e a chave e clique em "Sincronizar Metadados" para carregar as opções.', 'redmine') }}</div>
{% endif %}
<div class="row">
{{ fields.dropdownArrayField('default_tracker_id', default_tracker_id, tracker_options, __('Tipo (Tracker) padrão', 'redmine'), {'display_emptychoice': true}) }}
{{ fields.dropdownArrayField('default_priority_id', default_priority_id, priority_options, __('Prioridade padrão', 'redmine'), {'display_emptychoice': true}) }}
{{ fields.dropdownArrayField('default_activity_id', default_activity_id, activity_options, __('Atividade padrão (lançamento de tempo)', 'redmine'), {'display_emptychoice': true}) }}
</div>
</div>
</div>
{# --- Autores e observadores --- #}
<div class="card mb-3">
<div class="card-header">
<h4 class="card-title mb-0"><i class="ti ti-users me-1"></i>{{ __('Autores e observadores', 'redmine') }}</h4>
</div>
<div class="card-body">
<div class="alert alert-info">
{{ __('O autor (técnico atribuído) é adicionado automaticamente como membro do projeto Redmine com o papel abaixo, para permitir a impersonation.', 'redmine') }}
</div>
<div class="row">
{{ fields.dropdownArrayField('default_role_id', default_role_id, role_options, __('Papel padrão para membros (auto-membership)', 'redmine'), {'display_emptychoice': true}) }}
{{ fields.dropdownArrayField('default_watcher_ids', '', redmine_user_options, __('Observadores padrão', 'redmine'), {
'multiple': true,
'values': default_watcher_ids
}) }}
</div>
</div>
</div>
{# --- Mapa de status --- #}
<div class="card mb-3">
<div class="card-header">
<h4 class="card-title mb-0"><i class="ti ti-arrows-exchange me-1"></i>{{ __('Mapa de status: Chamado GLPI → Issue Redmine', 'redmine') }}</h4>
</div>
<div class="card-body">
<div class="row">
{% for sid, slabel in glpi_ticket_statuses %}
{{ fields.dropdownArrayField('status_map[' ~ sid ~ ']', attribute(status_map, sid)|default(''), status_options, slabel, {'display_emptychoice': true}) }}
{% endfor %}
</div>
</div>
</div>
<div class="d-flex justify-content-end mb-3">
<button type="submit" name="update" value="1" class="btn btn-primary">
<i class="ti ti-device-floppy me-1"></i>{{ _x('button', 'Save') }}
</button>
</div>
</form>
{# --- Mapeamento de usuários (overrides) — fora do form principal --- #}
<div class="card mb-3">
<div class="card-header">
<h4 class="card-title mb-0"><i class="ti ti-user-cog me-1"></i>{{ __('Mapeamento de usuários (GLPI → Redmine)', 'redmine') }}</h4>
</div>
<div class="card-body">
<div class="alert alert-info">
{{ __('Usuários com o mesmo e-mail nos dois sistemas são associados automaticamente. Use a tabela abaixo apenas para exceções (e-mails diferentes).', 'redmine') }}
</div>
<table class="table table-sm align-middle">
<thead><tr>
<th>{{ __('Usuário GLPI', 'redmine') }}</th>
<th>{{ __('Usuário Redmine', 'redmine') }}</th>
<th class="text-end">{{ _x('button', 'Delete') }}</th>
</tr></thead>
<tbody>
{% for m in usermap %}
<tr>
<td>{{ m.glpi_name }}</td>
<td>{{ m.redmine_name }}</td>
<td class="text-end">
<form method="post" action="{{ action_url }}" class="d-inline">
<input type="hidden" name="_glpi_csrf_token" value="{{ csrf_token_value }}">
<input type="hidden" name="del_usermap" value="{{ m.id }}">
<button type="submit" class="btn btn-sm btn-outline-danger"><i class="ti ti-trash"></i></button>
</form>
</td>
</tr>
{% else %}
<tr><td colspan="3" class="text-muted">{{ __('Nenhum override cadastrado.', 'redmine') }}</td></tr>
{% endfor %}
</tbody>
</table>
<form method="post" action="{{ action_url }}" class="mt-3">
<input type="hidden" name="_glpi_csrf_token" value="{{ csrf_token_value }}">
<input type="hidden" name="add_usermap" value="1">
<div class="row">
{{ fields.dropdownField('User', 'override_users_id', 0, __('Usuário GLPI', 'redmine'), {'display_emptychoice': true}) }}
{{ fields.dropdownArrayField('override_redmine_user_id', '', redmine_user_options, __('Usuário Redmine', 'redmine'), {'display_emptychoice': true}) }}
</div>
<div class="text-end">
<button type="submit" class="btn btn-outline-primary"><i class="ti ti-plus me-1"></i>{{ _x('button', 'Add') }}</button>
</div>
</form>
</div>
</div>