Add UI for removed Docker hosts re-enrollment
Adds a "Removed Docker Hosts" section to Settings -> Agents that displays hosts blocked from re-enrolling and provides an "Allow re-enroll" button. The backend API already existed; this adds the missing frontend component. Related to #773
This commit is contained in:
parent
3e2715d3f5
commit
f9bd09a2b4
1 changed files with 66 additions and 1 deletions
|
|
@ -6,7 +6,7 @@ import { MonitoringAPI } from '@/api/monitoring';
|
|||
import { SecurityAPI } from '@/api/security';
|
||||
import { notificationStore } from '@/stores/notifications';
|
||||
import type { SecurityStatus } from '@/types/config';
|
||||
import type { HostLookupResponse } from '@/types/api';
|
||||
import type { HostLookupResponse, RemovedDockerHost } from '@/types/api';
|
||||
import type { APITokenRecord } from '@/api/security';
|
||||
import { HOST_AGENT_SCOPE, DOCKER_REPORT_SCOPE } from '@/constants/apiScopes';
|
||||
import { copyToClipboard } from '@/utils/clipboard';
|
||||
|
|
@ -302,6 +302,12 @@ export const UnifiedAgents: Component = () => {
|
|||
const legacyAgents = createMemo(() => allHosts().filter(h => h.isLegacy));
|
||||
const hasLegacyAgents = createMemo(() => legacyAgents().length > 0);
|
||||
|
||||
const removedDockerHosts = createMemo(() => {
|
||||
const removed = state.removedDockerHosts || [];
|
||||
return removed.sort((a, b) => b.removedAt - a.removedAt);
|
||||
});
|
||||
const hasRemovedDockerHosts = createMemo(() => removedDockerHosts().length > 0);
|
||||
|
||||
const getUpgradeCommand = (_hostname: string) => {
|
||||
const token = resolvedToken();
|
||||
return `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${token}`;
|
||||
|
|
@ -323,6 +329,16 @@ export const UnifiedAgents: Component = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleAllowReenroll = async (hostId: string, hostname?: string) => {
|
||||
try {
|
||||
await MonitoringAPI.allowDockerHostReenroll(hostId);
|
||||
notificationStore.success(`Re-enrollment allowed for ${hostname || hostId}. Restart the agent to reconnect.`);
|
||||
} catch (err) {
|
||||
logger.error('Failed to allow re-enrollment', err);
|
||||
notificationStore.error('Failed to allow re-enrollment');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="space-y-6">
|
||||
<Card padding="lg" class="space-y-5">
|
||||
|
|
@ -711,6 +727,55 @@ export const UnifiedAgents: Component = () => {
|
|||
</table>
|
||||
</Card>
|
||||
</Card>
|
||||
|
||||
<Show when={hasRemovedDockerHosts()}>
|
||||
<Card padding="lg" class="space-y-4">
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">Removed Docker Hosts</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Docker hosts that were removed and are blocked from re-enrolling. Allow re-enrollment to let them report again.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card padding="none" tone="glass" class="overflow-hidden rounded-lg">
|
||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400">Hostname</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400">Host ID</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400">Removed</th>
|
||||
<th scope="col" class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-900">
|
||||
<For each={removedDockerHosts()}>
|
||||
{(host) => (
|
||||
<tr>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{host.displayName || host.hostname || 'Unknown'}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-sm text-gray-500 dark:text-gray-400 font-mono text-xs">
|
||||
{host.id.slice(0, 8)}...
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
||||
{formatRelativeTime(host.removedAt)}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-right text-sm font-medium">
|
||||
<button
|
||||
onClick={() => handleAllowReenroll(host.id, host.hostname)}
|
||||
class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
Allow re-enroll
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
</Card>
|
||||
</Card>
|
||||
</Show>
|
||||
</div >
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue