forked from snxraven/peardock
Add welcome page if no connections
This commit is contained in:
parent
e33023e250
commit
93c40af76a
147
app.js
147
app.js
@ -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,21 +261,12 @@ 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) {
|
||||||
@ -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;
|
||||||
|
|
||||||
|
55
index.html
55
index.html
@ -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,11 +78,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#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 {
|
||||||
@ -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">
|
||||||
|
Loading…
Reference in New Issue
Block a user