81dee5cba2
- ad_connector: страницы управления OU и импорта из AD, поле ad_ou_dn в Directory, ADSyncLog; расширение sync-сервиса и клиента - mattermost_connector: personal access token шифруется (Fernet, token_service), бот-сервис, команды создания бота и синхронизации; публикация постов в каналы. Тесты (19) - core: ConnectorConfig, Directory (ad_ou_dn), обновления админки Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
126 lines
8.9 KiB
HTML
126 lines
8.9 KiB
HTML
<div class="page-content" id="ad-import-page">
|
|
|
|
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:1rem; gap:1rem; flex-wrap:wrap;">
|
|
<div>
|
|
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">Імпорт співробітників з Active Directory</h1>
|
|
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">Облікові записи AD, яким ще не відповідає жоден співробітник у системі</p>
|
|
</div>
|
|
<a href="#" class="btn btn-primary"
|
|
hx-get="/ad-import/" hx-target="#main-content" hx-push-url="/ad-import/" hx-indicator="#loader">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/>
|
|
</svg>
|
|
Оновити
|
|
</a>
|
|
</div>
|
|
|
|
{% include "partials/ad_connector_tabs.html" with active="import" %}
|
|
|
|
{% if imported %}
|
|
<div style="background:rgba(22,163,74,0.08); border:1px solid rgba(22,163,74,0.3); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:1.5rem; font-size:0.875rem; color:#16a34a;">
|
|
Імпортовано: {{ imported|join:", " }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if errors %}
|
|
<div style="background:color-mix(in srgb, var(--color-destructive) 8%, transparent); border:1px solid color-mix(in srgb, var(--color-destructive) 30%, transparent); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:1.5rem; font-size:0.875rem; color:var(--color-destructive);">
|
|
{% for err in errors %}<div>{{ err }}</div>{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if ad_error %}
|
|
<div style="background:color-mix(in srgb, var(--color-destructive) 8%, transparent); border:1px solid color-mix(in srgb, var(--color-destructive) 30%, transparent); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:1.5rem; display:flex; align-items:center; gap:0.75rem;">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--color-destructive)" stroke-width="2" style="flex-shrink:0;">
|
|
<circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/>
|
|
</svg>
|
|
<div style="font-size:0.875rem; color:var(--color-destructive);">{{ ad_error }}</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form hx-post="/ad-import/" hx-target="#main-content" hx-indicator="#loader">
|
|
{% csrf_token %}
|
|
|
|
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0 / 0.05); margin-bottom:1.5rem; padding:1.25rem 1.5rem; display:flex; align-items:flex-end; gap:1rem; flex-wrap:wrap;">
|
|
<div>
|
|
<label style="display:block; font-size:0.8125rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Дата прийняття</label>
|
|
<input type="date" name="hire_date" value="{{ today }}" class="input" style="max-width:12rem;">
|
|
</div>
|
|
<div>
|
|
<label style="display:block; font-size:0.8125rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Локація (офіс)</label>
|
|
<select name="user_location" class="input" style="max-width:20rem;">
|
|
<option value="">— оберіть —</option>
|
|
{% for loc in locations %}
|
|
<option value="{{ loc.pk }}">{{ loc.address|default:loc.pk }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">
|
|
Однакові для всього пакету імпорту. Відділ і посаду можна вказати окремо для кожного рядка.
|
|
</div>
|
|
</div>
|
|
|
|
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0 / 0.05); margin-bottom:1.5rem;">
|
|
<div style="padding:1.25rem 1.5rem; border-bottom:1px solid var(--color-border);">
|
|
<h3 style="font-weight:600; color:var(--color-card-foreground); font-size:0.9375rem;">Кандидати на імпорт</h3>
|
|
<p style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ candidates_total }} облікових записів AD без співробітника</p>
|
|
</div>
|
|
<div style="overflow-x:auto;">
|
|
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
|
|
<thead>
|
|
<tr style="border-bottom:1px solid var(--color-border);">
|
|
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;"></th>
|
|
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">Обліковий запис</th>
|
|
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">Відділ</th>
|
|
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">Посада</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for candidate in candidates %}
|
|
<tr style="border-bottom:1px solid var(--color-border);" class="tr-hover">
|
|
<td style="padding:0.875rem 1rem; vertical-align:middle;">
|
|
<input type="checkbox" name="import_{{ candidate.username }}" value="1">
|
|
</td>
|
|
<td style="padding:0.875rem 1rem; vertical-align:middle;">
|
|
<div style="font-weight:500; color:var(--color-card-foreground);">
|
|
{{ candidate.last_name }} {{ candidate.first_name }}
|
|
{% if candidate.is_disabled %}
|
|
<span style="display:inline-flex; align-items:center; padding:0.125rem 0.5rem; border-radius:9999px; font-size:0.6875rem; font-weight:500; background:var(--color-muted); color:var(--color-muted-foreground); margin-left:0.375rem;">Відключений</span>
|
|
{% endif %}
|
|
</div>
|
|
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ candidate.username }} · {{ candidate.email }}</div>
|
|
</td>
|
|
<td style="padding:0.875rem 1rem; vertical-align:middle;">
|
|
<select name="department_{{ candidate.username }}" class="input" style="font-size:0.8125rem; padding:0.3rem 0.5rem; height:auto; max-width:14rem;">
|
|
<option value="">— оберіть —</option>
|
|
{% for dep in departments %}
|
|
<option value="{{ dep.pk }}">{{ dep.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</td>
|
|
<td style="padding:0.875rem 1rem; vertical-align:middle;">
|
|
<select name="post_{{ candidate.username }}" class="input" style="font-size:0.8125rem; padding:0.3rem 0.5rem; height:auto; max-width:14rem;">
|
|
<option value="">— оберіть —</option>
|
|
{% for post in posts %}
|
|
<option value="{{ post.pk }}">{{ post.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="4" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Немає нових облікових записів для імпорту</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% include "partials/pagination.html" with page=candidates base_url="/ad-import/" page_param="candidates_page" size_param="candidates_per_page" item_label="кандидатів" %}
|
|
</div>
|
|
|
|
{% if candidates %}
|
|
<button type="submit" class="btn btn-primary">Імпортувати відмічені</button>
|
|
{% endif %}
|
|
</form>
|
|
|
|
</div>
|