mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-04-28 00:11:34 -05:00
0c310736c1
Remove both system-wide and per-user UI feature enable/disable settings in favor of the centralized ModuleRegistry system for module management. Changes: - Remove ui_allow_* columns from Settings model and database (migration 093) - Remove ui_show_* preference assignments from user settings route - Remove UI Customization section from user settings template - Remove UI Features section from admin settings template - Update admin modules template to use ModuleRegistry instead of settings flags - Remove settings_flag and user_flag attributes from ModuleDefinition - Update ModuleRegistry.is_enabled() to only check dependencies and default_enabled - Update dashboard template to use is_module_enabled() helper - Update admin route docstring to reflect module management changes Module visibility is now controlled exclusively via the admin module management interface (/admin/modules), eliminating the need for separate system-wide and per-user UI preference systems.
372 lines
24 KiB
HTML
372 lines
24 KiB
HTML
{% extends "base.html" %}
|
|
{% from "components/ui.html" import page_header, breadcrumb_nav, button, filter_badge %}
|
|
|
|
{% block content %}
|
|
{% set breadcrumbs = [
|
|
{'text': 'Admin', 'url': url_for('admin.admin_dashboard')},
|
|
{'text': 'System Settings'}
|
|
] %}
|
|
|
|
{{ page_header(
|
|
icon_class='fas fa-sliders-h',
|
|
title_text='System Settings',
|
|
subtitle_text='Configure system-wide application settings',
|
|
breadcrumbs=breadcrumbs,
|
|
actions_html=None
|
|
) }}
|
|
|
|
<!-- Main Settings Form -->
|
|
<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() }}">
|
|
|
|
<div class="space-y-8">
|
|
<!-- General Settings -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">General</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="timezone" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Timezone</label>
|
|
<select name="timezone" id="timezone" class="form-input" required>
|
|
{% for tz in timezones %}
|
|
<option value="{{ tz }}" {% if settings.timezone == tz %}selected{% endif %}>{{ tz }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<p class="mt-1 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
This becomes the default timezone for users who choose “System Default”.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<label for="currency" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Currency</label>
|
|
<input type="text" name="currency" id="currency" value="{{ settings.currency }}" required class="form-input">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timer Settings -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">Timers</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="rounding_minutes" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Rounding (Minutes)</label>
|
|
<input type="number" name="rounding_minutes" id="rounding_minutes" value="{{ settings.rounding_minutes }}" required class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="idle_timeout_minutes" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Idle Timeout (Minutes)</label>
|
|
<input type="number" name="idle_timeout_minutes" id="idle_timeout_minutes" value="{{ settings.idle_timeout_minutes }}" required class="form-input">
|
|
</div>
|
|
<div class="md:col-span-2 flex items-center">
|
|
<input type="checkbox" name="single_active_timer" id="single_active_timer" {% if settings.single_active_timer %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="single_active_timer" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">Allow only one active timer per user</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User Management -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('User Management') }}</h2>
|
|
<div class="space-y-4">
|
|
<div class="flex items-center">
|
|
<input type="checkbox" name="allow_self_register" id="allow_self_register" {% if settings.allow_self_register %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="allow_self_register" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">Allow self-registration (users can create accounts by entering any username on login page)</label>
|
|
</div>
|
|
<p class="text-xs text-text-muted-light dark:text-text-muted-dark ml-6">
|
|
Note: Admin users are configured via the ADMIN_USERNAMES environment variable, not in this UI.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Company Branding -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Company Branding') }}</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="company_name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ _('Company Name') }}</label>
|
|
<input type="text" name="company_name" id="company_name" value="{{ settings.company_name }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="company_email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Company Email</label>
|
|
<input type="email" name="company_email" id="company_email" value="{{ settings.company_email }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="company_phone" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Company Phone</label>
|
|
<input type="text" name="company_phone" id="company_phone" value="{{ settings.company_phone }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="company_website" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Company Website</label>
|
|
<input type="text" name="company_website" id="company_website" value="{{ settings.company_website }}" class="form-input">
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label for="company_address" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Company Address</label>
|
|
<textarea name="company_address" id="company_address" rows="3" class="form-input">{{ settings.company_address }}</textarea>
|
|
</div>
|
|
<div>
|
|
<label for="company_tax_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tax ID (optional)</label>
|
|
<input type="text" name="company_tax_id" id="company_tax_id" value="{{ settings.company_tax_id }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="company_bank_info" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Bank Information (optional)</label>
|
|
<textarea name="company_bank_info" id="company_bank_info" rows="3" class="form-input">{{ settings.company_bank_info }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Invoice Defaults -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Invoice Defaults') }}</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="invoice_prefix" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Invoice Prefix</label>
|
|
<input type="text" name="invoice_prefix" id="invoice_prefix" value="{{ settings.invoice_prefix }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="invoice_start_number" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Invoice Start Number</label>
|
|
<input type="number" name="invoice_start_number" id="invoice_start_number" value="{{ settings.invoice_start_number }}" class="form-input">
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label for="invoice_terms" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Default Payment Terms</label>
|
|
<textarea name="invoice_terms" id="invoice_terms" rows="3" class="form-input">{{ settings.invoice_terms }}</textarea>
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label for="invoice_notes" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Default Invoice Notes</label>
|
|
<textarea name="invoice_notes" id="invoice_notes" rows="3" class="form-input">{{ settings.invoice_notes }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Backup Settings -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Backup Settings') }}</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="backup_retention_days" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Backup Retention (Days)</label>
|
|
<input type="number" name="backup_retention_days" id="backup_retention_days" value="{{ settings.backup_retention_days }}" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="backup_time" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Backup Time (HH:MM)</label>
|
|
<input type="text" name="backup_time" id="backup_time" value="{{ settings.backup_time }}" placeholder="02:00" class="form-input">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Settings -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Export Settings') }}</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="export_delimiter" class="block text-sm font-medium text-gray-700 dark:text-gray-300">CSV Export Delimiter</label>
|
|
<select name="export_delimiter" id="export_delimiter" class="form-input">
|
|
<option value="," {% if settings.export_delimiter == ',' %}selected{% endif %}>Comma (,)</option>
|
|
<option value=";" {% if settings.export_delimiter == ';' %}selected{% endif %}>Semicolon (;)</option>
|
|
<option value="\t" {% if settings.export_delimiter == '\t' %}selected{% endif %}>Tab</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Kiosk Mode Settings -->
|
|
<div class="border-b border-border-light dark:border-border-dark pb-6">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Kiosk Mode') }}</h2>
|
|
<div class="space-y-4">
|
|
<div class="flex items-center">
|
|
<input type="checkbox" name="kiosk_mode_enabled" id="kiosk_mode_enabled" {% if kiosk_settings.kiosk_mode_enabled %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="kiosk_mode_enabled" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">
|
|
{{ _('Enable Kiosk Mode') }}
|
|
</label>
|
|
</div>
|
|
<p class="ml-6 text-xs text-text-muted-light dark:text-text-muted-dark">
|
|
{{ _('Kiosk mode provides a simplified interface for warehouse operations with barcode scanning and time tracking. Access at') }} <code class="text-xs bg-gray-100 dark:bg-gray-800 px-1 py-0.5 rounded">/kiosk/login</code>
|
|
</p>
|
|
{% if kiosk_settings.kiosk_mode_enabled %}
|
|
<div class="ml-6 grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
|
|
<div>
|
|
<label for="kiosk_auto_logout_minutes" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ _('Auto-Logout Timeout (Minutes)') }}</label>
|
|
<input type="number" name="kiosk_auto_logout_minutes" id="kiosk_auto_logout_minutes" value="{{ kiosk_settings.kiosk_auto_logout_minutes }}" min="1" max="60" class="form-input">
|
|
</div>
|
|
<div>
|
|
<label for="kiosk_default_movement_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ _('Default Movement Type') }}</label>
|
|
<select name="kiosk_default_movement_type" id="kiosk_default_movement_type" class="form-input">
|
|
<option value="adjustment" {% if kiosk_settings.kiosk_default_movement_type == 'adjustment' %}selected{% endif %}>{{ _('Adjustment') }}</option>
|
|
<option value="transfer" {% if kiosk_settings.kiosk_default_movement_type == 'transfer' %}selected{% endif %}>{{ _('Transfer') }}</option>
|
|
<option value="sale" {% if kiosk_settings.kiosk_default_movement_type == 'sale' %}selected{% endif %}>{{ _('Sale') }}</option>
|
|
<option value="purchase" {% if kiosk_settings.kiosk_default_movement_type == 'purchase' %}selected{% endif %}>{{ _('Purchase') }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<input type="checkbox" name="kiosk_allow_camera_scanning" id="kiosk_allow_camera_scanning" {% if kiosk_settings.kiosk_allow_camera_scanning %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="kiosk_allow_camera_scanning" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">
|
|
{{ _('Allow Camera-Based Barcode Scanning') }}
|
|
</label>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<input type="checkbox" name="kiosk_require_reason_for_adjustments" id="kiosk_require_reason_for_adjustments" {% if kiosk_settings.kiosk_require_reason_for_adjustments %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="kiosk_require_reason_for_adjustments" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">
|
|
{{ _('Require Reason for Stock Adjustments') }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Analytics Settings -->
|
|
<div>
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Privacy & Analytics') }}</h2>
|
|
<div class="space-y-4">
|
|
<div class="flex items-center">
|
|
<input type="checkbox" name="allow_analytics" id="allow_analytics" {% if settings.allow_analytics %}checked{% endif %} class="h-4 w-4 rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<label for="allow_analytics" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">Enable anonymous usage analytics</label>
|
|
</div>
|
|
<div class="ml-6 text-xs text-text-muted-light dark:text-text-muted-dark space-y-1">
|
|
<p>Help improve TimeTracker by sharing anonymous usage data:</p>
|
|
<ul class="list-disc ml-4 space-y-0.5">
|
|
<li>Platform and version information</li>
|
|
<li>Feature usage patterns (no personal data)</li>
|
|
<li>Performance and error metrics</li>
|
|
</ul>
|
|
<p class="mt-2"><strong>Privacy:</strong> All data is anonymized. No personal information, time entries, or client data is ever collected.</p>
|
|
<p>This is the same setting as the telemetry preference shown during initial setup.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 pt-6 flex justify-end">
|
|
<button type="submit" class="bg-primary text-white px-4 py-2 rounded-lg">{{ _('Save Settings') }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Company Logo Upload - Separate Section -->
|
|
<div class="bg-card-light dark:bg-card-dark p-6 rounded-lg shadow">
|
|
<h2 class="text-lg font-semibold mb-4">{{ _('Company Logo') }}</h2>
|
|
|
|
<!-- Current Logo Display -->
|
|
{% if settings.has_logo() %}
|
|
<div class="mb-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg border-2 border-green-500 dark:border-green-600">
|
|
<div class="flex items-start justify-between mb-3">
|
|
<div>
|
|
<h3 class="text-sm font-semibold text-green-700 dark:text-green-400 mb-1">✓ Current Company Logo</h3>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">This logo appears on invoices, PDFs, and other documents</p>
|
|
</div>
|
|
<form id="removeLogoForm" method="POST" action="{{ url_for('admin.remove_logo') }}" class="inline">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<button type="button" class="text-sm text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300 font-medium" onclick="confirmRemoveLogo()">
|
|
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
</svg>
|
|
Remove Logo
|
|
</button>
|
|
</form>
|
|
</div>
|
|
<div class="flex items-center justify-center bg-white dark:bg-gray-900 p-6 rounded border border-gray-200 dark:border-gray-700">
|
|
<img src="{{ settings.get_logo_url() }}?v={{ range(1, 10000) | random }}" alt="{{ _('Company Logo') }}" class="max-h-32 max-w-full object-contain" onerror="this.onerror=null; this.parentElement.innerHTML='<p class=\'text-red-600 text-sm\'>Error loading logo</p>';">
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="mb-4 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg border-2 border-dashed border-gray-300 dark:border-gray-600">
|
|
<div class="text-center py-4">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
</svg>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">No company logo uploaded yet</p>
|
|
<p class="text-xs text-gray-500 dark:text-gray-500 mt-1">Upload a logo to appear on invoices, PDFs, and documents</p>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Upload Form -->
|
|
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
|
|
<h3 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-3">{{ _('Upload New Logo') }}</h3>
|
|
<form method="POST" action="{{ url_for('admin.upload_logo') }}" enctype="multipart/form-data" id="logoUploadForm">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<input type="file" name="logo" id="logoFileInput" accept="image/png,image/jpeg,image/jpg,image/gif,image/svg+xml,image/webp" required
|
|
class="block w-full text-sm text-gray-900 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
onchange="previewLogoBeforeUpload(this)">
|
|
</div>
|
|
|
|
<!-- Preview of selected file before upload -->
|
|
<div id="logoPreview" class="hidden bg-white dark:bg-gray-900 p-4 rounded border border-gray-200 dark:border-gray-700">
|
|
<p class="text-xs text-gray-600 dark:text-gray-400 mb-2">Preview:</p>
|
|
<div class="flex items-center justify-center">
|
|
<img id="logoPreviewImage" src="" alt="{{ _('Logo Preview') }}" class="max-h-24 max-w-full object-contain">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium transition-colors">
|
|
<svg class="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
|
</svg>
|
|
Upload Logo
|
|
</button>
|
|
<button type="button" onclick="document.getElementById('logoFileInput').value = ''; document.getElementById('logoPreview').classList.add('hidden');"
|
|
class="text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 px-4 py-2 text-sm">
|
|
Clear
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div class="mt-3 text-xs text-gray-600 dark:text-gray-400 space-y-1">
|
|
<p><strong>Allowed formats:</strong> PNG, JPG, GIF, SVG, WEBP (max 5MB)</p>
|
|
<p><strong>Recommended:</strong> Square or landscape logo, at least 200x200 pixels</p>
|
|
<p><strong>Where it appears:</strong> PDF invoices, email templates, and exported documents</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
</style>
|
|
<script>
|
|
function previewLogoBeforeUpload(input) {
|
|
const preview = document.getElementById('logoPreview');
|
|
const previewImage = document.getElementById('logoPreviewImage');
|
|
|
|
if (input.files && input.files[0]) {
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = function(e) {
|
|
previewImage.src = e.target.result;
|
|
preview.classList.remove('hidden');
|
|
};
|
|
|
|
reader.readAsDataURL(input.files[0]);
|
|
} else {
|
|
preview.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
async function confirmRemoveLogo() {
|
|
const confirmed = await showConfirm(
|
|
'{{ _("Are you sure you want to remove the company logo?") }}',
|
|
{
|
|
title: '{{ _("Remove Logo") }}',
|
|
confirmText: '{{ _("Remove") }}',
|
|
cancelText: '{{ _("Cancel") }}',
|
|
variant: 'danger'
|
|
}
|
|
);
|
|
if (confirmed) {
|
|
document.getElementById('removeLogoForm').submit();
|
|
}
|
|
}
|
|
|
|
}, 10);
|
|
}
|
|
|
|
// Initialize: keep collapsed by default
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const content = document.getElementById('integrationCredentialsContent');
|
|
const toggleIcon = document.getElementById('integrationCredentialsToggleIcon');
|
|
if (content && toggleIcon) {
|
|
// Ensure it starts collapsed
|
|
content.classList.add('integration-credentials-collapsed');
|
|
toggleIcon.classList.remove('fa-chevron-up');
|
|
toggleIcon.classList.add('fa-chevron-down');
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|