mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-04-26 06:29:25 -05:00
5e61ed382a
- Remove confusing trello_token field from Trello setup (replaced with api_secret) - Add required field indicators (*) and HTML validation for all OAuth credentials - Add backend validation for required fields (Client ID, API Key, API Secret) - Improve GitLab instance URL validation with proper defaults and URL format checking - Enhance help text for Microsoft integrations (Outlook, Teams) tenant_id field - Clarify when fields are required vs optional with better placeholder text - Ensure setup pages only show necessary fields for each integration type All integration setup pages now have: - Clear required field indicators - Proper validation (frontend and backend) - Simplified, intuitive forms - Better help text and instructions - No unnecessary or confusing fields
211 lines
11 KiB
HTML
211 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
{% from "components/ui.html" import page_header %}
|
|
|
|
{% block title %}{{ display_name }} {{ _('Setup') }} - {{ app_name }}{% endblock %}
|
|
|
|
{% block content %}
|
|
{% set breadcrumbs = [
|
|
{'text': 'Admin', 'url': url_for('admin.admin_dashboard')},
|
|
{'text': 'Integrations', 'url': url_for('admin.list_integrations_admin')},
|
|
{'text': display_name + ' Setup'}
|
|
] %}
|
|
|
|
{{ page_header(
|
|
icon_class='fas fa-plug',
|
|
title_text=display_name + ' ' + _('Setup'),
|
|
subtitle_text=description,
|
|
breadcrumbs=breadcrumbs
|
|
) }}
|
|
|
|
<div class="bg-card-light dark:bg-card-dark p-6 rounded-lg shadow mb-6">
|
|
<form method="POST">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
|
|
{% if provider == 'trello' %}
|
|
<!-- Trello API Key Setup -->
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label for="trello_api_key" class="block text-sm font-medium mb-2">
|
|
{{ _('Trello API Key') }} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text"
|
|
name="trello_api_key"
|
|
id="trello_api_key"
|
|
value="{{ current_creds.get('api_key', '') }}"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="{{ _('Get from https://trello.com/app-key') }}"
|
|
required>
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('Get your API key from') }} <a href="https://trello.com/app-key" target="_blank" class="text-primary hover:underline">trello.com/app-key</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="trello_api_secret" class="block text-sm font-medium mb-2">
|
|
{{ _('Trello API Secret') }} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="password"
|
|
name="trello_api_secret"
|
|
id="trello_api_secret"
|
|
value="{{ current_creds.get('api_secret', '') }}"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="{{ _('Leave empty to keep current value') }}">
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('Get your API secret from') }} <a href="https://trello.com/app-key" target="_blank" class="text-primary hover:underline">trello.com/app-key</a>
|
|
{{ _('(shown after generating API key)') }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<p class="text-sm text-blue-800 dark:text-blue-200">
|
|
<i class="fas fa-info-circle mr-2"></i>
|
|
{{ _('After saving API Key and Secret, you can connect Trello using OAuth flow. The token will be generated automatically during connection.') }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{% else %}
|
|
<!-- OAuth-based Integrations -->
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label for="{{ provider }}_client_id" class="block text-sm font-medium mb-2">
|
|
{{ _('OAuth Client ID') }} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text"
|
|
name="{{ provider }}_client_id"
|
|
id="{{ provider }}_client_id"
|
|
value="{{ current_creds.get('client_id', '') }}"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="{{ _('OAuth Client ID') }}"
|
|
required>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="{{ provider }}_client_secret" class="block text-sm font-medium mb-2">
|
|
{{ _('OAuth Client Secret') }} <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="password"
|
|
name="{{ provider }}_client_secret"
|
|
id="{{ provider }}_client_secret"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="{{ _('Leave empty to keep current value') }}">
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('Required for new setup. Leave empty to keep existing secret.') }}
|
|
</p>
|
|
</div>
|
|
|
|
{% if provider in ['outlook_calendar', 'microsoft_teams'] %}
|
|
<div>
|
|
<label for="{{ provider }}_tenant_id" class="block text-sm font-medium mb-2">
|
|
{{ _('Tenant ID') }} <span class="text-text-muted-light dark:text-text-muted-dark">({{ _('optional') }})</span>
|
|
</label>
|
|
<input type="text"
|
|
name="{{ provider }}_tenant_id"
|
|
id="{{ provider }}_tenant_id"
|
|
value="{{ current_creds.get('tenant_id', '') }}"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="{{ _('Leave empty for "common" (multi-tenant)') }}">
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('Leave empty to use "common" (multi-tenant). Enter your Azure AD tenant ID for single-tenant apps.') }}
|
|
</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if provider == 'gitlab' %}
|
|
<div>
|
|
<label for="gitlab_instance_url" class="block text-sm font-medium mb-2">
|
|
{{ _('GitLab Instance URL') }}
|
|
</label>
|
|
<input type="url"
|
|
name="gitlab_instance_url"
|
|
id="gitlab_instance_url"
|
|
value="{{ current_creds.get('instance_url', 'https://gitlab.com') }}"
|
|
class="w-full px-3 py-2 border border-border-light dark:border-border-dark rounded-lg bg-card-light dark:bg-card-dark"
|
|
placeholder="https://gitlab.com"
|
|
required>
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('URL of your GitLab instance. Use "https://gitlab.com" for GitLab.com or your self-hosted GitLab URL.') }}
|
|
</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<h3 class="font-semibold mb-2">{{ _('OAuth Redirect URI') }}</h3>
|
|
<p class="text-sm text-text-muted-light dark:text-text-muted-dark mb-2">
|
|
{{ _('Add this URL as an authorized redirect URI in your OAuth app settings:') }}
|
|
</p>
|
|
<code class="block p-2 bg-gray-100 dark:bg-gray-800 rounded text-xs break-all">
|
|
{{ url_for('integrations.oauth_callback', provider=provider, _external=True) }}
|
|
</code>
|
|
{% if provider == 'google_calendar' %}
|
|
<div class="mt-4 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded">
|
|
<p class="text-sm text-green-800 dark:text-green-200 font-semibold mb-2">
|
|
<i class="fas fa-magic mr-2"></i>{{ _('Automatic Connection Flow') }}
|
|
</p>
|
|
<ul class="text-sm text-green-700 dark:text-green-300 space-y-1 list-disc list-inside">
|
|
<li>{{ _('After you save these credentials, users can click "Connect Google Calendar"') }}</li>
|
|
<li>{{ _('They will be automatically redirected to Google OAuth') }}</li>
|
|
<li>{{ _('No manual credential entry needed - fully automatic!') }}</li>
|
|
<li>{{ _('Each user connects their own Google Calendar account') }}</li>
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mt-6 flex gap-4">
|
|
<button type="submit" class="bg-primary text-white px-6 py-2 rounded-lg hover:bg-primary/90 transition-colors">
|
|
<i class="fas fa-save mr-2"></i>{{ _('Save Credentials') }}
|
|
</button>
|
|
<a href="{{ url_for('admin.list_integrations_admin') }}" class="bg-gray-200 dark:bg-gray-700 px-6 py-2 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">
|
|
{{ _('Cancel') }}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{% if provider == 'google_calendar' %}
|
|
<div class="bg-card-light dark:bg-card-dark p-6 rounded-lg shadow mt-6">
|
|
<h3 class="text-lg font-semibold mb-4">{{ _('How Google Calendar Works') }}</h3>
|
|
<div class="space-y-3 text-sm text-text-muted-light dark:text-text-muted-dark">
|
|
<p>
|
|
<i class="fas fa-info-circle text-blue-500 mr-2"></i>
|
|
{{ _('After you save the OAuth credentials above, users can connect their Google Calendar by clicking "Connect Google Calendar" on the Integrations page.') }}
|
|
</p>
|
|
<p>
|
|
<i class="fas fa-arrow-right text-green-500 mr-2"></i>
|
|
{{ _('They will be automatically redirected to Google to authorize access - no manual credential entry needed!') }}
|
|
</p>
|
|
<p>
|
|
<i class="fas fa-user text-purple-500 mr-2"></i>
|
|
{{ _('Each user connects their own Google Calendar account (per-user integration).') }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{% elif integration and integration.is_active %}
|
|
<div class="bg-card-light dark:bg-card-dark p-6 rounded-lg shadow mt-6">
|
|
<h3 class="text-lg font-semibold mb-4">{{ _('Connection Status') }}</h3>
|
|
<div class="flex items-center gap-4">
|
|
<span class="px-3 py-1 rounded bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
|
<i class="fas fa-check-circle mr-2"></i>{{ _('Connected') }}
|
|
</span>
|
|
<a href="{{ url_for('integrations.view_integration', integration_id=integration.id) }}" class="text-primary hover:underline">
|
|
{{ _('View Integration') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% elif integration %}
|
|
<div class="bg-card-light dark:bg-card-dark p-6 rounded-lg shadow mt-6">
|
|
<h3 class="text-lg font-semibold mb-4">{{ _('Next Steps') }}</h3>
|
|
<p class="text-sm text-text-muted-light dark:text-text-muted-dark mb-4">
|
|
{{ _('After saving credentials, connect the integration:') }}
|
|
</p>
|
|
<a href="{{ url_for('integrations.connect_integration', provider=provider) }}" class="bg-primary text-white px-6 py-2 rounded-lg hover:bg-primary/90 transition-colors inline-block">
|
|
<i class="fas fa-link mr-2"></i>{{ _('Connect Integration') }}
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
{% endblock %}
|
|
|