Add welcome page if no connections

This commit is contained in:
Raven Scott 2024-11-29 22:40:26 -05:00
parent e33023e250
commit 93c40af76a
2 changed files with 168 additions and 40 deletions

147
app.js
View File

@ -53,12 +53,29 @@ function waitForPeerResponse(expectedMessageFragment, timeout = 900000) {
// Initialize the app // Initialize the app
console.log('[INFO] Client app initialized'); console.log('[INFO] Client app initialized');
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const statusIndicator = document.getElementById('status-indicator'); console.log('[INFO] Initializing Client App');
if (statusIndicator) {
statusIndicator.remove(); const connectionTitle = document.getElementById('connection-title');
console.log('[INFO] Status indicator removed from DOM on load'); if (!connectionTitle) {
console.error('[ERROR] Connection title element is missing! Creating dynamically...');
const content = document.getElementById('content');
const titleElement = document.createElement('h1');
titleElement.id = 'connection-title';
titleElement.textContent = '󠀠';
titleElement.classList.add('hidden'); // Initially hidden
content.insertBefore(titleElement, content.firstChild);
} }
if (Object.keys(connections).length === 0) {
showWelcomePage();
} else {
hideWelcomePage();
}
assertVisibility(); // Ensure visibility is correct after initialization
}); });
// Show Status Indicator // Show Status Indicator
// Modify showStatusIndicator to recreate it dynamically // Modify showStatusIndicator to recreate it dynamically
function showStatusIndicator(message = 'Processing...') { function showStatusIndicator(message = 'Processing...') {
@ -169,10 +186,18 @@ addConnectionForm.addEventListener('submit', (e) => {
// Function to add a new connection // Function to add a new connection
function addConnection(topicHex) { function addConnection(topicHex) {
console.log(`[DEBUG] Adding connection with topic: ${topicHex}`);
if (Object.keys(connections).length === 0) {
console.log('[DEBUG] Hiding welcome page after first connection');
hideWelcomePage(); // Hide the welcome page when the first connection is added
}
const topic = b4a.from(topicHex, 'hex'); const topic = b4a.from(topicHex, 'hex');
const topicId = topicHex.substring(0, 12); const topicId = topicHex.substring(0, 12);
console.log(`[INFO] Adding connection with topic: ${topicHex}`); console.log(`[INFO] Adding connection with topic: ${topicHex}`);
assertVisibility(); // Ensure visibility reflects the added connection
const connectionItem = document.createElement('li'); const connectionItem = document.createElement('li');
connectionItem.className = 'list-group-item d-flex align-items-center justify-content-between'; connectionItem.className = 'list-group-item d-flex align-items-center justify-content-between';
@ -200,6 +225,8 @@ function addConnection(topicHex) {
connections[topicId] = { topic, peer: null, swarm: null }; connections[topicId] = { topic, peer: null, swarm: null };
console.log('[DEBUG] Updated connections object:', connections);
// Create a new swarm for this connection // Create a new swarm for this connection
const swarm = new Hyperswarm(); const swarm = new Hyperswarm();
connections[topicId].swarm = swarm; connections[topicId].swarm = swarm;
@ -209,7 +236,6 @@ function addConnection(topicHex) {
swarm.on('connection', (peer) => { swarm.on('connection', (peer) => {
console.log(`[INFO] Connected to peer for topic: ${topicHex}`); console.log(`[INFO] Connected to peer for topic: ${topicHex}`);
// Prevent duplicate connections
if (connections[topicId].peer) { if (connections[topicId].peer) {
console.warn(`[WARN] Duplicate connection detected for topic: ${topicId}. Closing.`); console.warn(`[WARN] Duplicate connection detected for topic: ${topicId}. Closing.`);
peer.destroy(); peer.destroy();
@ -235,23 +261,14 @@ function addConnection(topicHex) {
} }
}); });
// If this is the first connection, switch to it
if (!window.activePeer) { if (!window.activePeer) {
switchConnection(topicId); switchConnection(topicId);
} }
}); });
// Collapse the sidebar after adding a new connection
const sidebar = document.getElementById('sidebar');
const collapseSidebarBtn = document.getElementById('collapse-sidebar-btn');
if (!sidebar.classList.contains('collapsed')) {
sidebar.classList.add('collapsed');
collapseSidebarBtn.innerHTML = '>';
console.log('[INFO] Sidebar collapsed after adding new connection.');
}
} }
function disconnectConnection(topicId, connectionItem) { function disconnectConnection(topicId, connectionItem) {
const connection = connections[topicId]; const connection = connections[topicId];
if (!connection) { if (!connection) {
@ -259,22 +276,22 @@ function disconnectConnection(topicId, connectionItem) {
return; return;
} }
// Close and kill any open terminals associated with this connection // Close and clean up open terminals associated with this connection
if (window.openTerminals[topicId]) { if (window.openTerminals[topicId]) {
console.log(`[INFO] Closing terminals for topic: ${topicId}`); console.log(`[INFO] Closing terminals for topic: ${topicId}`);
window.openTerminals[topicId].forEach((containerId) => { window.openTerminals[topicId].forEach((containerId) => {
try { try {
cleanUpTerminal(containerId); // Use the terminal.js cleanup logic cleanUpTerminal(containerId); // Use the terminal.js cleanup logic
} catch (err) { } catch (err) {
console.error(`[ERROR] Failed to kill terminal for container ${containerId}: ${err.message}`); console.error(`[ERROR] Failed to clean up terminal for container ${containerId}: ${err.message}`);
} }
}); });
delete window.openTerminals[topicId]; delete window.openTerminals[topicId];
} }
// Hide the terminal modal if it is active // Hide the terminal modal if it's active
const terminalModal = document.getElementById('terminal-modal'); const terminalModal = document.getElementById('terminal-modal');
if (terminalModal.style.display === 'flex') { if (terminalModal && terminalModal.style.display === 'flex') {
console.log(`[INFO] Hiding terminal modal for disconnected topic: ${topicId}`); console.log(`[INFO] Hiding terminal modal for disconnected topic: ${topicId}`);
terminalModal.style.display = 'none'; terminalModal.style.display = 'none';
} }
@ -293,7 +310,9 @@ function disconnectConnection(topicId, connectionItem) {
delete connections[topicId]; delete connections[topicId];
// Remove the connection item from the list // Remove the connection item from the list
if (connectionItem) {
connectionList.removeChild(connectionItem); connectionList.removeChild(connectionItem);
}
console.log(`[INFO] Disconnected and removed connection: ${topicId}`); console.log(`[INFO] Disconnected and removed connection: ${topicId}`);
@ -305,12 +324,19 @@ function disconnectConnection(topicId, connectionItem) {
containerList.innerHTML = ''; // Clear the container list containerList.innerHTML = ''; // Clear the container list
} }
// Check if no connections remain, and show the welcome page
if (Object.keys(connections).length === 0) {
console.log('[DEBUG] All connections removed. Showing welcome page.');
showWelcomePage();
}
// Ensure the container list is cleared regardless of the active connection // Ensure the container list is cleared regardless of the active connection
resetContainerList(); resetContainerList();
// Refresh the connections view // Refresh the connections view
resetConnectionsView(); resetConnectionsView();
} }
// Function to reset the container list // Function to reset the container list
function resetContainerList() { function resetContainerList() {
containerList.innerHTML = ''; // Clear the existing list containerList.innerHTML = ''; // Clear the existing list
@ -361,24 +387,31 @@ function updateConnectionStatus(topicId, isConnected) {
// Switch between connections // Switch between connections
function switchConnection(topicId) { function switchConnection(topicId) {
const connection = connections[topicId]; const connection = connections[topicId];
if (!connection) { const connectionTitle = document.getElementById('connection-title');
console.error(`[ERROR] No connection found for topicId: ${topicId}`);
connectionTitle.textContent = 'Choose a Connection'; // Default message if (!connection || !connection.peer) {
return; console.error('[ERROR] No connection found or no active peer.');
}
// Update title if element exists
if (!connection.peer) { if (connectionTitle) {
console.error('[ERROR] No active peer for this connection.'); connectionTitle.textContent = '󠀠';
connectionTitle.textContent = 'Choose a Connection'; // Default message connectionTitle.classList.add('hidden');
}
showWelcomePage(); // Show welcome page
return; return;
} }
// Set active peer and update UI
window.activePeer = connection.peer; window.activePeer = connection.peer;
connectionTitle.textContent = `Connection: ${topicId}`;
dashboard.classList.remove('hidden');
console.log('[INFO] Sending "listContainers" command'); if (connectionTitle) {
sendCommand('listContainers'); connectionTitle.textContent = `Connection: ${topicId}`;
connectionTitle.classList.remove('hidden');
}
hideWelcomePage(); // Hide the welcome page
sendCommand('listContainers'); // Request container list
} }
// Attach switchConnection to the global window object // Attach switchConnection to the global window object
@ -674,6 +707,56 @@ duplicateContainerForm.addEventListener('submit', (e) => {
}); });
function showWelcomePage() {
const welcomePage = document.getElementById('welcome-page');
const dashboard = document.getElementById('dashboard');
const connectionTitle = document.getElementById('connection-title');
if (welcomePage) {
welcomePage.classList.remove('hidden');
}
if (dashboard) {
dashboard.classList.add('hidden');
}
if (connectionTitle) {
connectionTitle.textContent = '󠀠';
} else {
console.warn('[WARN] Connection title element not found!');
}
}
function hideWelcomePage() {
const welcomePage = document.getElementById('welcome-page');
const dashboard = document.getElementById('dashboard');
if (welcomePage) {
console.log('[DEBUG] Hiding welcome page');
welcomePage.classList.add('hidden'); // Hide the welcome page
} else {
console.error('[ERROR] Welcome page element not found!');
}
if (dashboard) {
console.log('[DEBUG] Showing dashboard');
dashboard.classList.remove('hidden'); // Show the dashboard
} else {
console.error('[ERROR] Dashboard element not found!');
}
}
function assertVisibility() {
const welcomePage = document.getElementById('welcome-page');
const dashboard = document.getElementById('dashboard');
if (Object.keys(connections).length === 0) {
console.assert(!welcomePage.classList.contains('hidden'), '[ASSERTION FAILED] Welcome page should be visible.');
console.assert(dashboard.classList.contains('hidden'), '[ASSERTION FAILED] Dashboard should be hidden.');
} else {
console.assert(welcomePage.classList.contains('hidden'), '[ASSERTION FAILED] Welcome page should be hidden.');
console.assert(!dashboard.classList.contains('hidden'), '[ASSERTION FAILED] Dashboard should be visible.');
}
}
// Attach startTerminal to the global window object // Attach startTerminal to the global window object
window.startTerminal = startTerminal; window.startTerminal = startTerminal;

View File

@ -22,6 +22,9 @@
color: white; color: white;
overflow: hidden; overflow: hidden;
} }
.hidden {
display: none !important;
}
#titlebar { #titlebar {
-webkit-app-region: drag; -webkit-app-region: drag;
@ -75,12 +78,14 @@
} }
#content { #content {
margin-left: 250px; display: flex;
flex: 1; flex-direction: column; /* Keep vertical stacking for child elements */
margin-left: 250px; /* Leave space for the sidebar */
flex: 1; /* Allow the content to grow */
padding: 30px; padding: 30px;
overflow-y: auto; overflow-y: auto; /* Allow scrolling if content overflows */
transition: margin-left 0.3s ease-in-out; position: relative;
} }
#sidebar.collapsed~#content { #sidebar.collapsed~#content {
margin-left: 50px; margin-left: 50px;
@ -188,6 +193,40 @@
color: #fff; color: #fff;
font-size: 1.25rem; font-size: 1.25rem;
} }
#welcome-page {
display: flex;
flex-direction: column; /* Stack child elements vertically */
justify-content: center; /* Center content vertically */
align-items: center; /* Center content horizontally */
text-align: center; /* Center-align text */
position: absolute; /* Overlay it over the content area */
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* Center it perfectly in the content */
max-width: 800px; /* Restrict the width of the welcome page */
width: 100%; /* Allow it to scale */
padding: 20px;
background-color: transparent; /* Match the theme */
}
#welcome-page.hidden {
display: none !important; /* Completely hide when not needed */
}
#dashboard {
display: flex; /* Use flex layout for content within the dashboard */
flex-direction: column; /* Stack elements vertically */
flex: 1; /* Ensure it uses all available space */
width: 100%; /* Take up the full width of the content area */
padding: 0; /* Remove extra padding */
overflow-y: auto; /* Allow vertical scrolling if needed */
position: relative; /* Prevent overlap with other elements */
}
#dashboard.hidden {
display: none !important; /* Hide the dashboard completely when not needed */
}
</style> </style>
</head> </head>
@ -210,7 +249,12 @@
</div> </div>
<div id="content"> <div id="content">
<h1 id="connection-title">Add a Connection</h1> <div id="welcome-page">
<h1>Welcome to Peartainer</h1>
<p class="mt-3">Easily manage your Docker containers across peer-to-peer connections.</p>
<p>To get started, add a connection using the form in the sidebar.</p>
<!-- <img src="https://via.placeholder.com/500x300" alt="Welcome Graphic" class="img-fluid mt-4"> -->
</div>
<div id="dashboard" class="hidden"> <div id="dashboard" class="hidden">
<h2>Containers</h2> <h2>Containers</h2>
<table class="table table-dark table-striped"> <table class="table table-dark table-striped">
@ -230,6 +274,7 @@
</div> </div>
</div> </div>
<!-- Duplicate Container Modal --> <!-- Duplicate Container Modal -->
<div class="modal fade" id="duplicateModal" tabindex="-1" aria-labelledby="duplicateModalLabel" aria-hidden="true"> <div class="modal fade" id="duplicateModal" tabindex="-1" aria-labelledby="duplicateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">