mirror of
https://github.com/ChrispyBacon-dev/DockFlare.git
synced 2026-04-28 03:39:32 +00:00
Merge pull request #337 from nguyenhuy158/fix/mobile-ui-optimization
Optimize UI for mobile devices testing in unstable
This commit is contained in:
commit
fb440e8aa1
7 changed files with 136 additions and 97 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1593,8 +1593,8 @@ function renderIdPTable(idps) {
|
|||
};
|
||||
|
||||
let tableHTML = `
|
||||
<table class="table table-zebra table-sm policy-table w-full">
|
||||
<colgroup>
|
||||
<table class="table table-zebra table-sm policy-table w-full table-responsive">
|
||||
<colgroup class="hidden md:table-column-group">
|
||||
<col class="col-primary">
|
||||
<col class="col-secondary">
|
||||
<col class="col-tertiary">
|
||||
|
|
@ -1621,18 +1621,18 @@ function renderIdPTable(idps) {
|
|||
|
||||
tableHTML += `
|
||||
<tr>
|
||||
<td class="p-3">
|
||||
<td class="p-3" data-label="${t('js.table.provider')}">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="inline-flex items-center justify-center">${icon}</span>
|
||||
<div class="font-medium">${idpData.name}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-3 text-xs opacity-70">
|
||||
<td class="p-3 text-xs opacity-70" data-label="${t('js.table.cloudflare_id')}">
|
||||
${idpData.cloudflare_id ? `<span class="tooltip" data-tip="${idpData.cloudflare_id}"><code>${idpData.cloudflare_id.slice(0, 8)}...</code></span>` : '-'}
|
||||
</td>
|
||||
<td class="p-3 text-sm opacity-80">${idpData.type}</td>
|
||||
<td class="p-3">${statusBadge}</td>
|
||||
<td class="p-3 text-right">
|
||||
<td class="p-3 text-sm opacity-80" data-label="${t('js.table.connector')}">${idpData.type}</td>
|
||||
<td class="p-3" data-label="${t('js.table.status')}">${statusBadge}</td>
|
||||
<td class="p-3 text-right" data-label="${t('js.table.actions')}">
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2 mt-4 sm:mt-0">
|
||||
<button id="sync-cloudflare-btn" class="btn btn-sm btn-secondary">
|
||||
<div class="flex flex-col sm:flex-row gap-2 mt-4 sm:mt-0 w-full sm:w-auto">
|
||||
<button id="sync-cloudflare-btn" class="btn btn-sm btn-secondary w-full sm:w-auto">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2"><path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /></svg>
|
||||
{{ t('policies.sync_from_cloudflare') }}
|
||||
</button>
|
||||
<button id="create-access-group-btn" class="btn btn-sm btn-primary">
|
||||
<button id="create-access-group-btn" class="btn btn-sm btn-primary w-full sm:w-auto">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /></svg>
|
||||
{{ t('policies.create_new_group') }}
|
||||
</button>
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
|
||||
{% if access_groups and access_groups.items() %}
|
||||
<div class="overflow-x-auto table-container">
|
||||
<table class="table table-zebra policy-table w-full" id="access-groups-table">
|
||||
<colgroup>
|
||||
<table class="table table-zebra policy-table w-full table-responsive" id="access-groups-table">
|
||||
<colgroup class="hidden md:table-column-group">
|
||||
<col class="col-primary">
|
||||
<col class="col-secondary">
|
||||
<col class="col-tertiary">
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
{% set policy_type_label = 'system' %}
|
||||
{% endif %}
|
||||
<tr data-policy-type="{{ policy_type_label }}" data-group-id="{{ group_id }}">
|
||||
<td class="px-4 py-3 cell-top">
|
||||
<td class="px-4 py-3 cell-top" data-label="{{ t('policies.display_name') }}">
|
||||
<div class="font-medium flex items-center gap-2">
|
||||
{{ details.display_name }}
|
||||
</div>
|
||||
|
|
@ -84,15 +84,15 @@
|
|||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 cell-top"><code class="badge badge-sm badge-outline">{{ group_id }}</code></td>
|
||||
<td class="px-4 py-3 text-xs opacity-80 cell-top">
|
||||
<td class="px-4 py-3 cell-top" data-label="{{ t('policies.group_id_label') }}"><code class="badge badge-sm badge-outline">{{ group_id }}</code></td>
|
||||
<td class="px-4 py-3 text-xs opacity-80 cell-top" data-label="{{ t('policies.policy_summary') }}">
|
||||
{% if details.policies %}
|
||||
{{ t('policies.rules_defined', count=details.policies | length) }}
|
||||
{% else %}
|
||||
<span class="italic opacity-60">{{ t('policies.no_rules') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<td class="px-4 py-3" data-label="{{ t('policies.policy_type') }}">
|
||||
{% if details.external_policy %}
|
||||
<span class="badge badge-sm badge-secondary df-badge">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" /></svg>
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right align-top">
|
||||
<td class="px-4 py-3 text-right align-top" data-label="{{ t('common.actions') }}">
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
|
@ -404,28 +404,30 @@
|
|||
--policy-col-actions: 12%;
|
||||
}
|
||||
|
||||
.policy-table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
@media (min-width: 769px) {
|
||||
.policy-table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.policy-table col.col-primary {
|
||||
width: var(--policy-col-primary);
|
||||
}
|
||||
.policy-table col.col-primary {
|
||||
width: var(--policy-col-primary);
|
||||
}
|
||||
|
||||
.policy-table col.col-secondary {
|
||||
width: var(--policy-col-secondary);
|
||||
}
|
||||
.policy-table col.col-secondary {
|
||||
width: var(--policy-col-secondary);
|
||||
}
|
||||
|
||||
.policy-table col.col-tertiary {
|
||||
width: var(--policy-col-tertiary);
|
||||
}
|
||||
.policy-table col.col-tertiary {
|
||||
width: var(--policy-col-tertiary);
|
||||
}
|
||||
|
||||
.policy-table col.col-status {
|
||||
width: var(--policy-col-status);
|
||||
}
|
||||
.policy-table col.col-status {
|
||||
width: var(--policy-col-status);
|
||||
}
|
||||
|
||||
.policy-table col.col-actions {
|
||||
width: var(--policy-col-actions);
|
||||
.policy-table col.col-actions {
|
||||
width: var(--policy-col-actions);
|
||||
}
|
||||
}
|
||||
|
||||
.policy-table th,
|
||||
|
|
@ -911,8 +913,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
let html = '<div class="overflow-x-auto table-container"><table class="table table-zebra policy-table w-full">';
|
||||
html += '<colgroup>';
|
||||
let html = '<div class="overflow-x-auto table-container"><table class="table table-zebra policy-table w-full table-responsive">';
|
||||
html += '<colgroup class="hidden md:table-column-group">';
|
||||
html += '<col class="col-primary">';
|
||||
html += '<col class="col-secondary">';
|
||||
html += '<col class="col-tertiary">';
|
||||
|
|
@ -929,14 +931,14 @@
|
|||
|
||||
zonePolicies.forEach(zone => {
|
||||
html += '<tr>';
|
||||
html += `<td class="px-4 py-3 font-medium">${zone.zone_name}</td>`;
|
||||
html += `<td class="px-4 py-3 font-medium" data-label="{{ t('policies.zone_name') }}">${zone.zone_name}</td>`;
|
||||
if (zone.zone_id) {
|
||||
html += `<td class="px-4 py-3 text-xs opacity-70"><span class=\"tooltip\" data-tip=\"${zone.zone_id}\"><code>${zone.zone_id.slice(0, 8)}...</code></span></td>`;
|
||||
html += `<td class="px-4 py-3 text-xs opacity-70" data-label="{{ t('policies.zone_id') }}"><span class=\"tooltip\" data-tip=\"${zone.zone_id}\"><code>${zone.zone_id.slice(0, 8)}...</code></span></td>`;
|
||||
} else {
|
||||
html += '<td class="px-4 py-3 text-xs opacity-70">-</td>';
|
||||
html += '<td class="px-4 py-3 text-xs opacity-70" data-label="{{ t('policies.zone_id') }}">-</td>';
|
||||
}
|
||||
html += `<td class="px-4 py-3"><code class="text-sm">*.${zone.zone_name}</code></td>`;
|
||||
html += '<td class="px-4 py-3">';
|
||||
html += `<td class="px-4 py-3" data-label="{{ t('policies.wildcard_hostname') }}"><code class="text-sm">*.${zone.zone_name}</code></td>`;
|
||||
html += '<td class="px-4 py-3" data-label="{{ t('common.status') }}">';
|
||||
|
||||
if (zone.has_default_policy) {
|
||||
html += '<span class="badge badge-sm badge-success df-badge">';
|
||||
|
|
@ -946,7 +948,7 @@
|
|||
html += '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>{{ t('policies.not_protected') }}</span>';
|
||||
}
|
||||
|
||||
html += '</td><td class="px-4 py-3 text-right">';
|
||||
html += '</td><td class="px-4 py-3 text-right" data-label="{{ t('common.actions') }}">';
|
||||
|
||||
if (!zone.has_default_policy) {
|
||||
html += `<div class="dropdown dropdown-end">
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between border-b border-base-300 pb-3 mb-6">
|
||||
<h1 class="card-title text-2xl sm:text-3xl">{{ t('agents.agents_management') }}</h1>
|
||||
<div class="flex items-center gap-2 mt-4 sm:mt-0">
|
||||
<button id="btn-force-reconcile" class="btn btn-ghost btn-sm">{{ t('agents.force_reconciliation') }}</button>
|
||||
<button id="btn-generate-key" class="btn btn-primary btn-sm">
|
||||
<div class="flex flex-col sm:flex-row items-center gap-2 mt-4 sm:mt-0 w-full sm:w-auto">
|
||||
<button id="btn-force-reconcile" class="btn btn-ghost btn-sm w-full sm:w-auto">{{ t('agents.force_reconciliation') }}</button>
|
||||
<button id="btn-generate-key" class="btn btn-primary btn-sm w-full sm:w-auto">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v-2.25L15.188 8.43c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z" /></svg>
|
||||
{{ t('agents.generate_new_api_key') }}
|
||||
</button>
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
</div>
|
||||
|
||||
<div class="overflow-x-auto min-w-0 agents-table-container">
|
||||
<table class="table table-zebra w-full">
|
||||
<colgroup>
|
||||
<table class="table table-zebra w-full table-responsive">
|
||||
<colgroup class="hidden md:table-column-group">
|
||||
<col style="width:10%">
|
||||
<col style="width:13%">
|
||||
<col style="width:6%">
|
||||
|
|
@ -81,8 +81,8 @@
|
|||
<div class="card-body">
|
||||
<h2 class="card-title text-xl border-b border-base-300 pb-3 mb-6">{{ t('agents.active_api_keys') }}</h2>
|
||||
<div class="overflow-x-auto active-keys-table-container">
|
||||
<table class="table table-zebra table-sm w-full api-keys-table">
|
||||
<colgroup>
|
||||
<table class="table table-zebra table-sm w-full api-keys-table table-responsive">
|
||||
<colgroup class="hidden md:table-column-group">
|
||||
<col class="col-key">
|
||||
<col class="col-owner">
|
||||
<col class="col-created">
|
||||
|
|
@ -127,8 +127,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="overflow-x-auto revoked-keys-table-container">
|
||||
<table class="table table-zebra table-sm w-full api-keys-table">
|
||||
<colgroup>
|
||||
<table class="table table-zebra table-sm w-full api-keys-table table-responsive">
|
||||
<colgroup class="hidden md:table-column-group">
|
||||
<col class="col-key">
|
||||
<col class="col-owner">
|
||||
<col class="col-created">
|
||||
|
|
@ -700,27 +700,27 @@
|
|||
}
|
||||
|
||||
tr.innerHTML = `
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.agent_id')}">
|
||||
<span class="font-mono text-xs text-base-content/50 cursor-help" title="${agentId}">${agentId.substring(0, 8)}…</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.display_name')}">
|
||||
<span class="text-sm font-medium">${agent.display_name || na}</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.version')}">
|
||||
<span class="text-sm text-base-content/60">${agent.version || na}</span>
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<td class="px-4 py-3" data-label="${t('agents.status')}">
|
||||
<div class="flex flex-wrap gap-1">${statusHtml}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-center">${ledStripHtml}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 text-center" data-label="${t('agents.heart_beat')}">${ledStripHtml}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.assigned_tunnel')}">
|
||||
<span class="text-sm">${agent.assigned_tunnel_name || na}</span>
|
||||
</td>
|
||||
<td class="px-4 py-3">${migrationHtml}${migrationStatus && (migrationStatus.has_conflicts || migrationStatus.has_orphaned) ? `<button class="btn btn-xs btn-info ml-2 btn-migration-assistant" data-agent-id="${agentId}" title="Open Migration Assistant">Resolve</button>` : ''}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">${cloudflaredVersion}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">${originIp}</td>
|
||||
<td class="px-4 py-3">${getTunnelStatusBadge(agent.tunnel_status)}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
<td class="px-4 py-3" data-label="${t('agents.migration')}">${migrationHtml}${migrationStatus && (migrationStatus.has_conflicts || migrationStatus.has_orphaned) ? `<button class="btn btn-xs btn-info ml-2 btn-migration-assistant" data-agent-id="${agentId}" title="Open Migration Assistant">Resolve</button>` : ''}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.cloudflared_version')}">${cloudflaredVersion}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.origin_ip')}">${originIp}</td>
|
||||
<td class="px-4 py-3" data-label="${t('agents.tunnel_status')}">${getTunnelStatusBadge(agent.tunnel_status)}</td>
|
||||
<td class="px-4 py-3 text-center" data-label="${t('common.actions')}">
|
||||
<button class="btn btn-ghost btn-sm agent-action-trigger"
|
||||
data-agent-id="${agentId}"
|
||||
data-enrolled="${agent.status === 'enrolled'}"
|
||||
|
|
@ -781,14 +781,14 @@
|
|||
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td class="px-4 py-3 whitespace-nowrap font-mono break-all">${keyId.substring(0, 8)}...</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">${owner}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">${createdAt}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap font-mono break-all" data-label="${t('agents.key_partial')}">${keyId.substring(0, 8)}...</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.owner')}">${owner}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.created_at')}">${createdAt}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('common.status')}">
|
||||
<span class="badge badge-success badge-sm">Active</span>
|
||||
<br><small class="text-xs opacity-60">${lastUsed}</small>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td class="px-4 py-3 text-right" data-label="${t('common.actions')}">
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
|
|
@ -857,22 +857,22 @@
|
|||
const tr = document.createElement('tr');
|
||||
tr.className = 'opacity-60 italic';
|
||||
tr.innerHTML = `
|
||||
<td class="px-4 py-3 font-mono break-all text-sm">
|
||||
<td class="px-4 py-3 font-mono break-all text-sm" data-label="${t('agents.full_api_key')}">
|
||||
<div class="bg-base-200 p-2 rounded border-2 border-dashed">
|
||||
<span class="text-xs opacity-75">Full Key:</span><br>
|
||||
<code class="text-xs">${keyId}</code>
|
||||
<button class="btn btn-xs btn-ghost ml-2 btn-copy-revoked-key" data-key="${keyId}">Copy</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap line-through">${owner}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap line-through" data-label="${t('agents.owner')}">${owner}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.revoked_at')}">
|
||||
<span class="badge badge-error badge-sm">Revoked</span>
|
||||
<br><small class="text-xs">${revokedAt}</small>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td class="px-4 py-3 whitespace-nowrap" data-label="${t('agents.auto_delete')}">
|
||||
${autoDeleteInfo}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td class="px-4 py-3 text-right" data-label="${t('common.actions')}">
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
|
|
|
|||
|
|
@ -30,6 +30,43 @@
|
|||
#log-output::-webkit-scrollbar-thumb:hover { background-color: rgba(156, 163, 175, 0.7); }
|
||||
html[data-theme="dark"] #log-output::-webkit-scrollbar-thumb { background-color: rgba(107, 114, 128, 0.5); }
|
||||
html[data-theme="dark"] #log-output::-webkit-scrollbar-thumb:hover { background-color: rgba(107, 114, 128, 0.7); }
|
||||
|
||||
/* Mobile Responsive Table Support */
|
||||
@media (max-width: 768px) {
|
||||
.table-responsive thead { display: none; }
|
||||
.table-responsive tr {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid hsl(var(--bc) / 0.1);
|
||||
border-radius: var(--rounded-box, 1rem);
|
||||
background-color: hsl(var(--b1));
|
||||
padding: 0.5rem;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.table-responsive td {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
text-align: right;
|
||||
padding: 0.5rem 1rem !important;
|
||||
border: none !important;
|
||||
position: relative;
|
||||
min-height: 2.5rem;
|
||||
}
|
||||
.table-responsive td::before {
|
||||
content: attr(data-label);
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.65rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.table-responsive td:last-child { border-bottom: 0; }
|
||||
|
||||
/* Specific overrides for status badges and links */
|
||||
.table-responsive td > * { max-width: 60%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@
|
|||
</p>
|
||||
{% if all_account_tunnels is defined and all_account_tunnels %}
|
||||
<div class="overflow-x-auto -mx-6 sm:-mx-8">
|
||||
<table class="table table-sm w-full">
|
||||
<thead>
|
||||
<table class="table table-sm w-full table-responsive">
|
||||
<thead class="hidden md:table-header-group">
|
||||
<tr>
|
||||
<th class="w-12">+/-</th>
|
||||
<th>{{ t('settings.tunnel_name') }}</th>
|
||||
|
|
@ -179,21 +179,21 @@
|
|||
<tbody>
|
||||
{% for tunnel in all_account_tunnels %}
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<td class="text-center" data-label="Expand">
|
||||
<button type="button" class="btn btn-xs btn-ghost btn-circle tunnel-dns-toggle"
|
||||
data-tunnel-id="{{ tunnel.id | e }}" aria-expanded="false" aria-controls="dns-records-{{ tunnel.id | e }}" title="{{ t('settings.toggle_dns_records') }}">
|
||||
<svg class="w-4 h-4 expand-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
<svg class="w-4 h-4 collapse-icon hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 12H6"></path></svg>
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-sm font-medium">{{ tunnel.name | e }}</td>
|
||||
<td><code class="text-xs opacity-80">{{ tunnel.id | e }}</code></td>
|
||||
<td>
|
||||
<td class="text-sm font-medium" data-label="{{ t('settings.tunnel_name') }}">{{ tunnel.name | e }}</td>
|
||||
<td data-label="{{ t('settings.tunnel_id') }}"><code class="text-xs opacity-80">{{ tunnel.id | e }}</code></td>
|
||||
<td data-label="{{ t('common.status') }}">
|
||||
{% set status_color = 'badge-success' if tunnel.status | lower == 'healthy' else ('badge-warning' if tunnel.status | lower == 'degraded' else ('badge-error' if tunnel.status | lower == 'down' else 'badge-ghost')) %}
|
||||
<span class="badge {{ status_color }} badge-sm">{{ tunnel.status | capitalize | e }}</span>
|
||||
</td>
|
||||
<td class="text-xs opacity-70">{% if tunnel.created_at %}{{ tunnel.created_at.split('T')[0] | e }}{% else %}N/A{% endif %}</td>
|
||||
<td class="text-xs">
|
||||
<td class="text-xs opacity-70" data-label="{{ t('settings.created_at') }}">{% if tunnel.created_at %}{{ tunnel.created_at.split('T')[0] | e }}{% else %}N/A{% endif %}</td>
|
||||
<td class="text-xs" data-label="{{ t('common.actions') }}">
|
||||
<button type="button" class="btn btn-xs btn-error delete-tunnel-btn"
|
||||
data-tunnel-id="{{ tunnel.id | e }}"
|
||||
data-tunnel-name="{{ tunnel.name | e }}">
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="12" cy="12" r="10" class="opacity-30"/><path d="M12 8h.01" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 12h1v4h1" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</button>
|
||||
</h2>
|
||||
<button class="btn btn-sm btn-primary ml-auto" onclick="document.getElementById('add_manual_rule_modal').showModal()">
|
||||
<button class="btn btn-sm btn-primary w-full sm:w-auto mt-4 sm:mt-0" onclick="document.getElementById('add_manual_rule_modal').showModal()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-1"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /></svg>
|
||||
{{ t('status.add_manual_rule') }}
|
||||
</button>
|
||||
|
|
@ -151,7 +151,7 @@
|
|||
</div>
|
||||
|
||||
<div class="overflow-x-auto pb-24">
|
||||
<table class="table table-zebra table-sm w-full">
|
||||
<table class="table table-zebra table-sm w-full table-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="p-3 w-auto">{{ t('common.status') }}</th>
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
<tbody>
|
||||
{% for hostname, details in rules.items()|sort %}
|
||||
<tr data-rule-key="{{ hostname }}" data-rule-status="{{ details.status }}" data-rule-source="{{ details.source }}">
|
||||
<td class="p-3 whitespace-nowrap" data-role="status-cell">
|
||||
<td class="p-3 whitespace-nowrap" data-role="status-cell" data-label="{{ t('common.status') }}">
|
||||
{% if details.source == 'manual' %}
|
||||
<span class="badge badge-info badge-sm status-badge">{{ t('status.manual_rules') }}</span>
|
||||
{% else %}
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap align-top" data-role="tunnel-name" data-tunnel-name="{{ details.tunnel_name or '' }}">
|
||||
<td class="p-3 whitespace-nowrap align-top" data-role="tunnel-name" data-tunnel-name="{{ details.tunnel_name or '' }}" data-label="{{ t('status.tunnel_name') }}">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm opacity-90">{{ details.tunnel_name or 'N/A' }}</span>
|
||||
<span class="text-xs opacity-60 mt-1">Zone: {{ details.zone_name or 'Unknown' }}</span>
|
||||
|
|
@ -188,16 +188,16 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap">
|
||||
<td class="p-3 whitespace-nowrap" data-label="{{ t('status.hostname') }}">
|
||||
{% set display_hostname = details.hostname if details.hostname else hostname.split('|')[0] %}
|
||||
{% set display_path = details.path if details.path else (hostname.split('|')[1] if '|' in hostname else None) %}
|
||||
<a href="https://{{ display_hostname }}{% if display_path %}{{ display_path }}{% endif %}" target="_blank" rel="noopener noreferrer" title="{{ t('status.open_url', hostname=display_hostname, path=display_path if display_path else '') }}" class="link link-hover link-primary text-sm">
|
||||
{{ display_hostname }}
|
||||
</a>
|
||||
{% if display_hostname and display_hostname.startswith('*.') %}
|
||||
<span class="badge badge-info badge-xs ml-2">wildcard</span>
|
||||
{% endif %}
|
||||
<div class="text-xs mt-1">
|
||||
</a>
|
||||
{% if display_hostname and display_hostname.startswith('*.') %}
|
||||
<span class="badge badge-info badge-xs ml-2">wildcard</span>
|
||||
{% endif %}
|
||||
<div class="text-xs mt-1">
|
||||
{% if details.no_tls_verify %}
|
||||
<span class="badge badge-warning badge-xs" title="{{ t('status.tls_verification_disabled') }}">{{ t('status.no_tls_verify') }}</span>
|
||||
{% endif %}
|
||||
|
|
@ -217,16 +217,16 @@
|
|||
<span class="badge badge-info badge-xs ml-1" title="{{ t('status.match_sni_to_host_description') }}">{{ t('status.match_sni_to_host') }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap">
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap" data-label="{{ t('status.path') }}">
|
||||
{% if display_path and display_path.strip() %}
|
||||
<code class="text-xs opacity-70">{{ display_path }}</code>
|
||||
{% else %}
|
||||
<span class="text-xs opacity-50 italic">(root)</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap"><code class="text-xs opacity-80">{{ details.service }}</code></td>
|
||||
<td class="p-3 whitespace-nowrap text-sm opacity-80" id="access-policy-display-{{ details.source if details.source else 'docker' }}-{{ hostname | replace('.', '-') }}">
|
||||
<td class="p-3 whitespace-nowrap" data-label="{{ t('status.service_target') }}"><code class="text-xs opacity-80">{{ details.service }}</code></td>
|
||||
<td class="p-3 whitespace-nowrap text-sm opacity-80" id="access-policy-display-{{ details.source if details.source else 'docker' }}-{{ hostname | replace('.', '-') }}" data-label="{{ t('status.access_policy') }}">
|
||||
{% if details.access_policy_type == 'group' %}
|
||||
{% if details.access_group_id is iterable and details.access_group_id is not string %}
|
||||
{% for group_id in details.access_group_id %}
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
<span class="badge badge-error badge-xs ml-2 animate-pulse" title="{{ t('status.docker_rule_overridden') }}">{{ t('status.rule_ui_override') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="p-3 whitespace-nowrap text-sm opacity-70" data-role="expires-cell">
|
||||
<td class="p-3 whitespace-nowrap text-sm opacity-70" data-role="expires-cell" data-label="{{ t('status.expires_in') }}">
|
||||
{% if details.status=='pending_deletion' and details.delete_at %}
|
||||
<div data-delete-at="{{ details.delete_at.isoformat() }}">
|
||||
<span class="absolute-time-display"></span>
|
||||
|
|
@ -262,7 +262,7 @@
|
|||
<span class="text-xs opacity-60">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="p-3">
|
||||
<td class="p-3" data-label="{{ t('common.actions') }}">
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue