Add restart to actions
This commit is contained in:
parent
964c6c60f3
commit
4f13281873
105
app.js
105
app.js
@ -105,27 +105,31 @@ function hideStatusIndicator() {
|
||||
// Show Alert
|
||||
function showAlert(type, message) {
|
||||
const alertContainer = document.getElementById('alert-container');
|
||||
|
||||
// Create alert element
|
||||
const alert = document.createElement('div');
|
||||
alert.className = `alert alert-${type} alert-dismissible fade show`;
|
||||
alert.role = 'alert';
|
||||
alert.className = `alert ${type}`;
|
||||
alert.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
<span>${message}</span>
|
||||
<button class="close-btn" aria-label="Close">×</button>
|
||||
`;
|
||||
|
||||
// Add close button functionality
|
||||
const closeButton = alert.querySelector('.close-btn');
|
||||
closeButton.addEventListener('click', () => {
|
||||
alert.remove(); // Remove alert on close
|
||||
});
|
||||
|
||||
// Append alert to container
|
||||
alertContainer.appendChild(alert);
|
||||
|
||||
// Automatically hide the status indicator for errors or success
|
||||
if (type === 'danger' || type === 'success') {
|
||||
hideStatusIndicator();
|
||||
}
|
||||
|
||||
// Automatically remove the alert after 5 seconds
|
||||
// Automatically remove alert after 5 seconds
|
||||
setTimeout(() => {
|
||||
alert.classList.remove('show');
|
||||
setTimeout(() => alert.remove(), 300); // Bootstrap's fade-out transition duration
|
||||
alert.remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
|
||||
// Collapse Sidebar Functionality
|
||||
const collapseSidebarBtn = document.getElementById('collapse-sidebar-btn');
|
||||
collapseSidebarBtn.addEventListener('click', () => {
|
||||
@ -454,30 +458,33 @@ function renderContainers(containers) {
|
||||
const row = document.createElement('tr');
|
||||
row.dataset.containerId = containerId; // Store container ID for reference
|
||||
row.innerHTML = `
|
||||
<td>${name}</td>
|
||||
<td>${image}</td>
|
||||
<td>${container.State}</td>
|
||||
<td class="cpu">0</td>
|
||||
<td class="memory">0</td>
|
||||
<td class="ip-address">${ipAddress}</td>
|
||||
<td>
|
||||
<button class="btn btn-success btn-sm action-start" ${container.State === 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button class="btn btn-warning btn-sm action-stop" ${container.State !== 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-stop"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm action-remove">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm action-terminal" ${container.State !== 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-terminal"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm action-duplicate">
|
||||
<i class="fas fa-clone"></i>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
<td>${name}</td>
|
||||
<td>${image}</td>
|
||||
<td>${container.State}</td>
|
||||
<td class="cpu">0</td>
|
||||
<td class="memory">0</td>
|
||||
<td class="ip-address">${ipAddress}</td>
|
||||
<td>
|
||||
<button class="btn btn-success btn-sm action-start" ${container.State === 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button class="btn btn-warning btn-sm action-stop" ${container.State !== 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-stop"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm action-remove">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm action-terminal" ${container.State !== 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-terminal"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm action-duplicate">
|
||||
<i class="fas fa-clone"></i>
|
||||
</button>
|
||||
<button class="btn btn-info btn-sm action-restart" ${container.State !== 'running' ? 'disabled' : ''}>
|
||||
<i class="fas fa-redo"></i>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
containerList.appendChild(row);
|
||||
|
||||
// Add event listeners for action buttons
|
||||
@ -494,6 +501,7 @@ function addActionListeners(row, container) {
|
||||
const stopBtn = row.querySelector('.action-stop');
|
||||
const removeBtn = row.querySelector('.action-remove');
|
||||
const terminalBtn = row.querySelector('.action-terminal');
|
||||
const restartBtn = row.querySelector('.action-restart');
|
||||
|
||||
// Start Button
|
||||
startBtn.addEventListener('click', async () => {
|
||||
@ -541,6 +549,31 @@ function addActionListeners(row, container) {
|
||||
hideStatusIndicator();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Restart Button
|
||||
restartBtn.addEventListener('click', async () => {
|
||||
showStatusIndicator(`Restarting container "${container.Names[0]}"...`);
|
||||
sendCommand('restartContainer', { id: container.Id });
|
||||
|
||||
const expectedMessageFragment = `Container ${container.Id} restarted`;
|
||||
|
||||
try {
|
||||
const response = await waitForPeerResponse(expectedMessageFragment);
|
||||
console.log('[DEBUG] Restart container response:', response);
|
||||
|
||||
showAlert('success', response.message);
|
||||
|
||||
// Refresh the container list to update states
|
||||
sendCommand('listContainers');
|
||||
} catch (error) {
|
||||
console.error('[ERROR] Failed to restart container:', error.message);
|
||||
showAlert('danger', error.message || 'Failed to restart container.');
|
||||
} finally {
|
||||
console.log('[DEBUG] Hiding status indicator in restartBtn finally block');
|
||||
hideStatusIndicator();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Remove Button
|
||||
|
68
index.html
68
index.html
@ -226,6 +226,74 @@
|
||||
|
||||
#dashboard.hidden {
|
||||
display: none !important; /* Hide the dashboard completely when not needed */
|
||||
}
|
||||
#alert-container {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 1055; /* Ensure it overlays other elements */
|
||||
display: flex;
|
||||
flex-direction: column-reverse; /* Stack alerts upwards */
|
||||
gap: 10px; /* Add space between alerts */
|
||||
}
|
||||
|
||||
.alert {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
max-width: 80%; /* Ensure the alert doesn't stretch too wide */
|
||||
padding: 12px 20px; /* Adjust padding for a more balanced look */
|
||||
background-color: #2b2b2b; /* Slightly lighter background for better contrast */
|
||||
color: #e0e0e0; /* Softer white text for readability */
|
||||
border-radius: 6px; /* Round corners for a modern look */
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5); /* Add subtle shadow for depth */
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px; /* Adjust font size for readability */
|
||||
animation: fadeIn 0.3s ease-out, fadeOut 4.5s ease-in forwards;
|
||||
white-space: nowrap; /* Prevent text wrapping */
|
||||
overflow: hidden; /* Hide overflow for long text */
|
||||
text-overflow: ellipsis; /* Add ellipsis for overflowed text */
|
||||
}
|
||||
|
||||
.alert.success {
|
||||
border-left: 6px solid #28a745; /* Green border for success */
|
||||
}
|
||||
|
||||
.alert.danger {
|
||||
border-left: 6px solid #dc3545; /* Red border for danger */
|
||||
}
|
||||
|
||||
.alert .close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #e0e0e0; /* Use the same text color for consistency */
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
margin-left: 15px; /* Space between text and close button */
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
90% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
@ -60,12 +60,12 @@ swarm.on('connection', (peer) => {
|
||||
console.log('[INFO] Handling \'listContainers\' command');
|
||||
try {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
|
||||
|
||||
const detailedContainers = await Promise.all(
|
||||
containers.map(async (container) => {
|
||||
try {
|
||||
const details = await docker.getContainer(container.Id).inspect();
|
||||
|
||||
|
||||
// Safely access the IP address
|
||||
let ipAddress = 'No IP Assigned';
|
||||
if (details.NetworkSettings && details.NetworkSettings.Networks) {
|
||||
@ -74,7 +74,7 @@ swarm.on('connection', (peer) => {
|
||||
ipAddress = networks[0].IPAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return { ...container, ipAddress }; // Add IP address to container data
|
||||
} catch (error) {
|
||||
console.error(`[ERROR] Failed to inspect container ${container.Id}: ${error.message}`);
|
||||
@ -82,14 +82,14 @@ swarm.on('connection', (peer) => {
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
response = { type: 'containers', data: detailedContainers };
|
||||
} catch (error) {
|
||||
console.error(`[ERROR] Failed to list containers: ${error.message}`);
|
||||
response = { error: 'Failed to list containers' };
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'inspectContainer':
|
||||
console.log(`[INFO] Handling 'inspectContainer' command for container: ${parsedData.args.id}`);
|
||||
const container = docker.getContainer(parsedData.args.id);
|
||||
@ -118,6 +118,12 @@ swarm.on('connection', (peer) => {
|
||||
response = { success: true, message: `Container ${parsedData.args.id} stopped` };
|
||||
break;
|
||||
|
||||
case 'restartContainer':
|
||||
console.log(`[INFO] Handling 'restartContainer' command for container: ${parsedData.args.id}`);
|
||||
await docker.getContainer(parsedData.args.id).restart();
|
||||
response = { success: true, message: `Container ${parsedData.args.id} restarted` };
|
||||
break;
|
||||
|
||||
case 'removeContainer':
|
||||
console.log(`[INFO] Handling 'removeContainer' command for container: ${parsedData.args.id}`);
|
||||
await docker.getContainer(parsedData.args.id).remove({ force: true });
|
||||
|
Loading…
Reference in New Issue
Block a user