Complete Track C roadmap: dashboard, job follow, actions, activity, roles
CI / test (push) Successful in 9m55s
CI / test (push) Successful in 9m55s
Ship the modern dashboard, job tray log follow, container overflow actions, stacks search, activity history, role-gated controls, invite form with copy token, first-connect checklist, and mark Track C done on the roadmap.
This commit is contained in:
+213
-125
@@ -45,6 +45,23 @@
|
||||
<span id="health-docker" class="health-docker">Docker —</span>
|
||||
<span id="health-role" class="health-role"></span>
|
||||
</div>
|
||||
<!-- Recent activity (job history) -->
|
||||
<div id="activity-tray" class="activity-tray">
|
||||
<button type="button" id="activity-tray-toggle" class="notification-tray-toggle" title="Recent activity" aria-label="Recent activity" aria-expanded="false">
|
||||
<i class="fas fa-list-check"></i>
|
||||
</button>
|
||||
<div id="activity-panel" class="activity-panel hidden" role="dialog" aria-label="Recent activity">
|
||||
<div class="activity-panel-header">
|
||||
<h5 class="mb-0">Recent activity</h5>
|
||||
<button type="button" class="notification-action-btn" id="activity-panel-close" title="Close" aria-label="Close">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="activity-panel-list" class="activity-panel-list">
|
||||
<div class="text-muted small p-3">No jobs yet</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Notification Tray - Global across all views -->
|
||||
<div id="notification-tray" class="notification-tray">
|
||||
<button id="notification-tray-toggle" class="notification-tray-toggle" aria-label="Notifications">
|
||||
@@ -222,122 +239,156 @@
|
||||
<i class="fas fa-plug me-2"></i>Add peer
|
||||
</button>
|
||||
</div>
|
||||
<!-- Dashboard View — fit-to-viewport, no outer scroll -->
|
||||
|
||||
<!-- First-connect checklist (shown once after successful connect) -->
|
||||
<div id="first-connect-checklist" class="first-connect-checklist hidden" role="dialog" aria-labelledby="first-connect-title">
|
||||
<div class="first-connect-card">
|
||||
<div class="first-connect-head">
|
||||
<h3 id="first-connect-title"><i class="fas fa-circle-check me-2 text-success"></i>You're connected</h3>
|
||||
<button type="button" class="btn-close btn-close-white" id="first-connect-dismiss" aria-label="Dismiss"></button>
|
||||
</div>
|
||||
<p class="text-muted small mb-3">A short tour of what to do next:</p>
|
||||
<ol class="first-connect-steps">
|
||||
<li><button type="button" class="first-connect-link" data-view="dashboard">Open the dashboard</button> for live host health</li>
|
||||
<li><button type="button" class="first-connect-link" data-view="containers">Browse containers</button> or <button type="button" class="first-connect-link" data-view="deploy">deploy a template</button></li>
|
||||
<li><button type="button" class="first-connect-link" data-view="settings">Settings</button> for density, auto-refresh, and template lists</li>
|
||||
<li>Press <kbd>Ctrl</kbd>+<kbd>K</kbd> anytime for the command palette</li>
|
||||
</ol>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="first-connect-got-it">Got it</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dashboard View — modern fit-to-viewport shell -->
|
||||
<div id="dashboard-view" class="view hidden">
|
||||
<div class="dashboard-layout">
|
||||
<div class="page-header dashboard-header">
|
||||
<div>
|
||||
<h2><i class="fas fa-gauge-high"></i>Dashboard</h2>
|
||||
<p class="page-subtitle">Host overview and quick actions</p>
|
||||
<div class="dashboard-layout dash">
|
||||
<header class="dash-header">
|
||||
<div class="dash-header-text">
|
||||
<p class="dash-kicker">Overview</p>
|
||||
<h2 class="dash-title">Dashboard</h2>
|
||||
<p class="dash-subtitle">Live engine health, storage, and activity on the active peer</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-header-actions">
|
||||
<button type="button" class="dash-icon-btn" onclick="window.loadDashboard && window.loadDashboard()" title="Refresh dashboard">
|
||||
<i class="fas fa-rotate"></i>
|
||||
</button>
|
||||
<button type="button" class="dash-chip-btn" onclick="window.navigateToView('deploy')">
|
||||
<i class="fas fa-rocket"></i><span>Deploy</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- System Overview Cards -->
|
||||
<div class="dashboard-stats-row">
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-icon" style="background: rgba(16, 185, 129, 0.2); color: var(--accent-success);">
|
||||
<i class="fas fa-box"></i>
|
||||
<!-- KPI strip -->
|
||||
<section class="dash-kpis" aria-label="Workload summary">
|
||||
<article class="dash-kpi dash-kpi--ok">
|
||||
<div class="dash-kpi-icon"><i class="fas fa-play"></i></div>
|
||||
<div class="dash-kpi-meta">
|
||||
<span class="dash-kpi-label">Running</span>
|
||||
<span class="dash-kpi-value" id="stat-running-containers">0</span>
|
||||
</div>
|
||||
<div class="stat-card-content">
|
||||
<div class="stat-card-value" id="stat-running-containers">0</div>
|
||||
<div class="stat-card-label">Running</div>
|
||||
<div class="dash-kpi-glow" aria-hidden="true"></div>
|
||||
</article>
|
||||
<article class="dash-kpi dash-kpi--stop">
|
||||
<div class="dash-kpi-icon"><i class="fas fa-stop"></i></div>
|
||||
<div class="dash-kpi-meta">
|
||||
<span class="dash-kpi-label">Stopped</span>
|
||||
<span class="dash-kpi-value" id="stat-stopped-containers">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-icon" style="background: rgba(239, 68, 68, 0.2); color: var(--accent-danger);">
|
||||
<i class="fas fa-stop-circle"></i>
|
||||
<div class="dash-kpi-glow" aria-hidden="true"></div>
|
||||
</article>
|
||||
<article class="dash-kpi dash-kpi--info">
|
||||
<div class="dash-kpi-icon"><i class="fas fa-layer-group"></i></div>
|
||||
<div class="dash-kpi-meta">
|
||||
<span class="dash-kpi-label">Images</span>
|
||||
<span class="dash-kpi-value" id="stat-total-images">0</span>
|
||||
</div>
|
||||
<div class="stat-card-content">
|
||||
<div class="stat-card-value" id="stat-stopped-containers">0</div>
|
||||
<div class="stat-card-label">Stopped</div>
|
||||
<div class="dash-kpi-glow" aria-hidden="true"></div>
|
||||
</article>
|
||||
<article class="dash-kpi dash-kpi--teal">
|
||||
<div class="dash-kpi-icon"><i class="fas fa-diagram-project"></i></div>
|
||||
<div class="dash-kpi-meta">
|
||||
<span class="dash-kpi-label">Networks</span>
|
||||
<span class="dash-kpi-value" id="stat-total-networks">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-icon" style="background: rgba(59, 130, 246, 0.2); color: var(--accent-info);">
|
||||
<i class="fas fa-images"></i>
|
||||
</div>
|
||||
<div class="stat-card-content">
|
||||
<div class="stat-card-value" id="stat-total-images">0</div>
|
||||
<div class="stat-card-label">Images</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-icon" style="background: rgba(20, 184, 166, 0.2); color: var(--accent-secondary);">
|
||||
<i class="fas fa-network-wired"></i>
|
||||
</div>
|
||||
<div class="stat-card-content">
|
||||
<div class="stat-card-value" id="stat-total-networks">0</div>
|
||||
<div class="stat-card-label">Networks</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-kpi-glow" aria-hidden="true"></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- Info panels fill remaining height -->
|
||||
<div class="dashboard-panels">
|
||||
<div class="info-card">
|
||||
<h5 class="info-card-title"><i class="fas fa-info-circle me-2"></i>Docker Information</h5>
|
||||
<div id="docker-info-content" class="info-card-body">
|
||||
<div class="skeleton skeleton-text"></div>
|
||||
<div class="skeleton skeleton-text mt-2"></div>
|
||||
<!-- Main panels -->
|
||||
<section class="dash-panels">
|
||||
<article class="dash-card">
|
||||
<div class="dash-card-head">
|
||||
<div class="dash-card-title"><i class="fas fa-gears"></i><span>Engine</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h5 class="info-card-title"><i class="fas fa-server me-2"></i>System Resources</h5>
|
||||
<div id="system-resources-content" class="info-card-body">
|
||||
<div class="skeleton skeleton-text"></div>
|
||||
<div class="skeleton skeleton-text mt-2"></div>
|
||||
<div id="docker-info-content" class="dash-card-body">
|
||||
<div class="dash-skeleton">
|
||||
<div class="dash-skel-line"></div>
|
||||
<div class="dash-skel-line"></div>
|
||||
<div class="dash-skel-line short"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="d-flex justify-content-between align-items-center gap-2 info-card-heading">
|
||||
<h5 class="info-card-title mb-0 text-truncate"><i class="fas fa-hdd me-2"></i>Disk Usage</h5>
|
||||
<button class="btn btn-sm btn-outline-secondary flex-shrink-0" type="button" onclick="window.refreshSystemDf && window.refreshSystemDf()" title="Refresh system df">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</article>
|
||||
|
||||
<article class="dash-card">
|
||||
<div class="dash-card-head">
|
||||
<div class="dash-card-title"><i class="fas fa-microchip"></i><span>Host</span></div>
|
||||
</div>
|
||||
<div id="system-resources-content" class="dash-card-body">
|
||||
<div class="dash-skeleton">
|
||||
<div class="dash-skel-line"></div>
|
||||
<div class="dash-skel-line"></div>
|
||||
<div class="dash-skel-line short"></div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="dash-card">
|
||||
<div class="dash-card-head">
|
||||
<div class="dash-card-title"><i class="fas fa-hard-drive"></i><span>Disk</span></div>
|
||||
<button type="button" class="dash-icon-btn dash-icon-btn--sm" onclick="window.refreshSystemDf && window.refreshSystemDf()" title="Refresh disk usage">
|
||||
<i class="fas fa-rotate"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="system-df-content" class="info-card-body">
|
||||
<div class="text-muted small">Connect to load Docker disk usage…</div>
|
||||
<div id="system-df-content" class="dash-card-body">
|
||||
<div class="dash-empty">Connect a peer to load disk usage</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="d-flex justify-content-between align-items-center gap-2 info-card-heading">
|
||||
<h5 class="info-card-title mb-0 text-truncate"><i class="fas fa-stream me-2"></i>Live Events</h5>
|
||||
<button class="btn btn-sm btn-outline-secondary flex-shrink-0" type="button" onclick="window.clearEventTimeline && window.clearEventTimeline()" title="Clear">
|
||||
</article>
|
||||
|
||||
<article class="dash-card dash-card--events">
|
||||
<div class="dash-card-head">
|
||||
<div class="dash-card-title"><i class="fas fa-bolt"></i><span>Live events</span></div>
|
||||
<button type="button" class="dash-icon-btn dash-icon-btn--sm" onclick="window.clearEventTimeline && window.clearEventTimeline()" title="Clear events">
|
||||
<i class="fas fa-eraser"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="docker-events-timeline" class="info-card-body events-timeline">
|
||||
<div class="text-muted small">Docker events will appear here…</div>
|
||||
<div id="docker-events-timeline" class="dash-card-body events-timeline dash-events">
|
||||
<div class="dash-empty">Docker events will stream here…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="info-card dashboard-actions">
|
||||
<h5 class="info-card-title"><i class="fas fa-bolt me-2"></i>Quick Actions</h5>
|
||||
<div class="info-card-body">
|
||||
<div class="d-flex gap-2 flex-wrap dashboard-action-btns">
|
||||
<button class="btn btn-sm btn-primary" onclick="window.navigateToView('containers')">
|
||||
<i class="fas fa-box me-1"></i>Containers
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="window.navigateToView('images')">
|
||||
<i class="fas fa-images me-1"></i>Images
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="window.navigateToView('networks')">
|
||||
<i class="fas fa-network-wired me-1"></i>Networks
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="window.navigateToView('volumes')">
|
||||
<i class="fas fa-database me-1"></i>Volumes
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-warning" type="button" onclick="window.pruneResource && window.pruneResource('containers')" title="Prune stopped containers">
|
||||
<i class="fas fa-broom me-1"></i>Prune Containers
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-warning" type="button" onclick="window.pruneResource && window.pruneResource('images')" title="Prune unused images">
|
||||
<i class="fas fa-broom me-1"></i>Prune Images
|
||||
</button>
|
||||
</div>
|
||||
<!-- Quick actions dock -->
|
||||
<footer class="dash-actions">
|
||||
<div class="dash-actions-label"><i class="fas fa-bolt"></i> Quick actions</div>
|
||||
<div class="dash-actions-row">
|
||||
<button type="button" class="dash-action" onclick="window.navigateToView('containers')">
|
||||
<i class="fas fa-cube"></i><span>Containers</span>
|
||||
</button>
|
||||
<button type="button" class="dash-action" onclick="window.navigateToView('images')">
|
||||
<i class="fas fa-layer-group"></i><span>Images</span>
|
||||
</button>
|
||||
<button type="button" class="dash-action" onclick="window.navigateToView('networks')">
|
||||
<i class="fas fa-diagram-project"></i><span>Networks</span>
|
||||
</button>
|
||||
<button type="button" class="dash-action" onclick="window.navigateToView('volumes')">
|
||||
<i class="fas fa-hard-drive"></i><span>Volumes</span>
|
||||
</button>
|
||||
<button type="button" class="dash-action dash-action--warn" data-min-role="admin" onclick="window.pruneResource && window.pruneResource('containers')" title="Prune stopped containers">
|
||||
<i class="fas fa-broom"></i><span>Prune containers</span>
|
||||
</button>
|
||||
<button type="button" class="dash-action dash-action--warn" data-min-role="admin" onclick="window.pruneResource && window.pruneResource('images')" title="Prune unused images">
|
||||
<i class="fas fa-broom"></i><span>Prune images</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -931,7 +982,7 @@
|
||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#buildImageModal">
|
||||
<i class="fas fa-hammer me-2"></i>Build Image
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" type="button" onclick="window.pruneResource && window.pruneResource('images')">
|
||||
<button class="btn btn-outline-warning" type="button" data-min-role="admin" onclick="window.pruneResource && window.pruneResource('images')">
|
||||
<i class="fas fa-broom me-2"></i>Prune
|
||||
</button>
|
||||
</div>
|
||||
@@ -1007,7 +1058,7 @@
|
||||
<button class="btn btn-primary" type="button" id="networks-create-btn" data-action="create-network">
|
||||
<i class="fas fa-plus me-2"></i>Create Network
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" type="button" onclick="window.pruneResource && window.pruneResource('networks')">
|
||||
<button class="btn btn-outline-warning" type="button" data-min-role="admin" onclick="window.pruneResource && window.pruneResource('networks')">
|
||||
<i class="fas fa-broom me-2"></i>Prune
|
||||
</button>
|
||||
</div>
|
||||
@@ -1276,10 +1327,13 @@
|
||||
<h2><i class="fas fa-boxes-stacked"></i>Stacks</h2>
|
||||
<p class="page-subtitle">Compose stacks on the remote host</p>
|
||||
</div>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#deploy-stack-modal">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#deploy-stack-modal" data-min-role="operator">
|
||||
<i class="fas fa-plus me-2"></i>Deploy Stack
|
||||
</button>
|
||||
</div>
|
||||
<div class="view-toolbar mb-3">
|
||||
<input type="search" id="stack-search" class="form-control form-control-sm bg-dark text-white list-search-input" placeholder="Search stacks…" spellcheck="false" autocomplete="off">
|
||||
</div>
|
||||
<div id="stacks-list" class="table-responsive">
|
||||
<table class="table table-dark table-hover">
|
||||
<thead>
|
||||
@@ -1349,7 +1403,7 @@ services:
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createVolumeModal">
|
||||
<i class="fas fa-plus me-2"></i>Create Volume
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" type="button" onclick="window.pruneResource && window.pruneResource('volumes')">
|
||||
<button class="btn btn-outline-warning" type="button" data-min-role="admin" onclick="window.pruneResource && window.pruneResource('volumes')">
|
||||
<i class="fas fa-broom me-2"></i>Prune
|
||||
</button>
|
||||
</div>
|
||||
@@ -1404,7 +1458,7 @@ services:
|
||||
<div class="card bg-dark border-secondary">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="fas fa-users me-2"></i>Peers</span>
|
||||
<button class="btn btn-sm btn-primary" id="access-invite-btn" type="button">
|
||||
<button class="btn btn-sm btn-primary" id="access-invite-btn" type="button" data-bs-toggle="modal" data-bs-target="#invitePeerModal" data-min-role="admin">
|
||||
<i class="fas fa-ticket me-1"></i>Create invite
|
||||
</button>
|
||||
</div>
|
||||
@@ -3346,35 +3400,69 @@ services:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Network Modal -->
|
||||
<div class="modal fade" id="createNetworkModal" tabindex="-1" aria-labelledby="createNetworkModalLabel" aria-hidden="true">
|
||||
<!-- Invite peer modal -->
|
||||
<div class="modal fade" id="invitePeerModal" tabindex="-1" aria-labelledby="invitePeerModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content bg-dark text-white">
|
||||
<div class="modal-header border-secondary">
|
||||
<h5 class="modal-title" id="invitePeerModalLabel"><i class="fas fa-ticket me-2"></i>Create invite</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form id="invite-peer-form">
|
||||
<div class="modal-body">
|
||||
<p class="small text-muted">Generate a one-time (or multi-use) invite token for a new client key.</p>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="invite-role">Role</label>
|
||||
<select id="invite-role" class="form-select bg-dark text-white">
|
||||
<option value="viewer">viewer</option>
|
||||
<option value="operator" selected>operator</option>
|
||||
<option value="admin">admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label" for="invite-ttl">TTL (hours)</label>
|
||||
<input type="number" id="invite-ttl" class="form-control bg-dark text-white" min="1" max="720" value="72">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label" for="invite-max-uses">Max uses</label>
|
||||
<input type="number" id="invite-max-uses" class="form-control bg-dark text-white" min="1" max="100" value="1">
|
||||
</div>
|
||||
</div>
|
||||
<div id="invite-token-result" class="invite-token-result hidden">
|
||||
<label class="form-label">Invite token</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" id="invite-token-value" class="form-control bg-dark text-white font-monospace" readonly>
|
||||
<button type="button" class="btn btn-outline-primary" id="invite-token-copy"><i class="fas fa-copy"></i></button>
|
||||
</div>
|
||||
<p class="small text-muted mt-2 mb-0">Copy this now — it will not be shown in full after you leave this dialog.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary" id="invite-peer-submit">
|
||||
<i class="fas fa-ticket me-1"></i>Create invite
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Legacy create-network modal removed — use smart create (#createNetworkSmartModal) -->
|
||||
<div class="modal fade d-none" id="createNetworkModal" tabindex="-1" aria-hidden="true" data-legacy="removed">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark text-white">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="createNetworkModalLabel"><i class="fas fa-plus me-2"></i>Create Network</h5>
|
||||
<h5 class="modal-title">Create Network</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="create-network-form">
|
||||
<div class="mb-3">
|
||||
<label for="network-name" class="form-label">Network Name</label>
|
||||
<input type="text" id="network-name" class="form-control bg-dark text-white" placeholder="my-network" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="network-driver" class="form-label">Driver</label>
|
||||
<select id="network-driver" class="form-select bg-dark text-white">
|
||||
<option value="bridge">Bridge</option>
|
||||
<option value="overlay">Overlay</option>
|
||||
<option value="macvlan">Macvlan</option>
|
||||
<option value="host">Host</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="network-subnet" class="form-label">Subnet (Optional)</label>
|
||||
<input type="text" id="network-subnet" class="form-control bg-dark text-white" placeholder="172.20.0.0/16">
|
||||
<small class="text-muted">CIDR notation (e.g., 172.20.0.0/16)</small>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-muted small mb-0">This form was replaced by the smart Create network dialog.</p>
|
||||
<form id="create-network-form" class="d-none">
|
||||
<input type="text" id="network-name">
|
||||
<select id="network-driver"><option value="bridge">bridge</option></select>
|
||||
<input type="text" id="network-subnet">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
|
||||
Reference in New Issue
Block a user