move instance management and firewall help into modal windows
This commit is contained in:
parent
76565477e7
commit
77c1c3114f
3 changed files with 185 additions and 64 deletions
|
|
@ -15,10 +15,30 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const createUserForm = document.getElementById('create-user-form');
|
const createUserForm = document.getElementById('create-user-form');
|
||||||
const changePasswordForm = document.getElementById('change-password-form');
|
const changePasswordForm = document.getElementById('change-password-form');
|
||||||
const profileSuccess = document.getElementById('profile-success');
|
const profileSuccess = document.getElementById('profile-success');
|
||||||
|
const helpBtn = document.getElementById('help-btn');
|
||||||
|
const helpModal = document.getElementById('help-modal');
|
||||||
|
const addInstanceModal = document.getElementById('add-instance-modal');
|
||||||
|
const showAddBtn = document.getElementById('show-add-btn');
|
||||||
|
|
||||||
let config = { firewall_host_ip: null };
|
let config = { firewall_host_ip: null };
|
||||||
let currentUser = null;
|
let currentUser = null;
|
||||||
|
|
||||||
|
const openModal = (modal) => modal.classList.add('active');
|
||||||
|
const closeModal = (modal) => modal.classList.remove('active');
|
||||||
|
|
||||||
|
document.querySelectorAll('.btn-close').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
closeModal(btn.closest('.modal'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('click', (e) => {
|
||||||
|
if (e.target.classList.contains('modal')) closeModal(e.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
helpBtn.addEventListener('click', () => openModal(helpModal));
|
||||||
|
showAddBtn.addEventListener('click', () => openModal(addInstanceModal));
|
||||||
|
|
||||||
const showLogin = () => {
|
const showLogin = () => {
|
||||||
loginOverlay.style.display = 'flex';
|
loginOverlay.style.display = 'flex';
|
||||||
logoutBtn.style.display = 'none';
|
logoutBtn.style.display = 'none';
|
||||||
|
|
@ -158,6 +178,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
addForm.reset();
|
addForm.reset();
|
||||||
document.getElementById('port').value = "4646";
|
document.getElementById('port').value = "4646";
|
||||||
|
closeModal(addInstanceModal);
|
||||||
fetchInstances();
|
fetchInstances();
|
||||||
} else if (res.status === 401) {
|
} else if (res.status === 401) {
|
||||||
showLogin();
|
showLogin();
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,22 @@
|
||||||
</svg>
|
</svg>
|
||||||
<h1>XIVLauncher Remote OTP</h1>
|
<h1>XIVLauncher Remote OTP</h1>
|
||||||
</div>
|
</div>
|
||||||
<button id="logout-btn" class="btn btn-icon btn-logout" title="Logout" style="display: none;">
|
<div class="header-actions">
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<button id="help-btn" class="btn btn-icon" title="Firewall Help">
|
||||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<polyline points="16 17 21 12 16 7"></polyline>
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
|
||||||
</svg>
|
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||||
</button>
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button id="logout-btn" class="btn btn-icon btn-logout" title="Logout" style="display: none;">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||||
|
<polyline points="16 17 21 12 16 7"></polyline>
|
||||||
|
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav id="main-nav" class="main-nav" style="display: none;">
|
<nav id="main-nav" class="main-nav" style="display: none;">
|
||||||
|
|
@ -35,66 +44,25 @@
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div id="instances-section" class="tab-content active">
|
<div id="instances-section" class="tab-content active">
|
||||||
<div class="card add-instance-card">
|
<div class="card instances-card">
|
||||||
<h2>Add Instance</h2>
|
<div class="instances-header">
|
||||||
<form id="add-form">
|
<h2>Managed Instances</h2>
|
||||||
<div class="form-group">
|
<div class="actions">
|
||||||
<label for="name">Name</label>
|
<button class="btn btn-primary btn-sm" id="show-add-btn">
|
||||||
<input type="text" id="name" placeholder="e.g. Steam Deck" required>
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||||
</div>
|
Add
|
||||||
<div class="form-row">
|
</button>
|
||||||
<div class="form-group">
|
<button class="btn btn-icon" id="refresh-btn" title="Refresh">
|
||||||
<label for="ip">IP Address</label>
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<input type="text" id="ip" placeholder="192.168.1.100" required>
|
<polyline points="23 4 23 10 17 10"></polyline>
|
||||||
</div>
|
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
|
||||||
<div class="form-group">
|
</svg>
|
||||||
<label for="port">Port</label>
|
</button>
|
||||||
<input type="number" id="port" value="4646" required>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div id="instances-list" class="instances-list">
|
||||||
<label for="secret">OTP Secret</label>
|
<!-- Instances injected via JS -->
|
||||||
<input type="password" id="secret" placeholder="Base32 Secret or otpauth:// URL" required>
|
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Add Instance</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card firewall-helper-card">
|
|
||||||
<h2>Firewall Helper</h2>
|
|
||||||
<p class="helper-text">Run these commands on the machine running XIVLauncher to allow incoming connections on the specified port.</p>
|
|
||||||
<div class="code-block">
|
|
||||||
<span class="code-label">UFW</span>
|
|
||||||
<div class="code-wrapper">
|
|
||||||
<code id="ufw-cmd">sudo ufw allow from localhost to any port 4646 proto tcp</code>
|
|
||||||
<button class="btn-copy" onclick="copyToClipboard('ufw-cmd')" title="Copy to clipboard">
|
|
||||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="code-block">
|
|
||||||
<span class="code-label">iptables</span>
|
|
||||||
<div class="code-wrapper">
|
|
||||||
<code id="iptables-cmd">sudo iptables -I INPUT -p tcp -s localhost --dport 4646 -j ACCEPT</code>
|
|
||||||
<button class="btn-copy" onclick="copyToClipboard('iptables-cmd')" title="Copy to clipboard">
|
|
||||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card instances-card">
|
|
||||||
<div class="instances-header">
|
|
||||||
<h2>Managed Instances</h2>
|
|
||||||
<button class="btn btn-icon" id="refresh-btn" title="Refresh">
|
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<polyline points="23 4 23 10 17 10"></polyline>
|
|
||||||
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="instances-list" class="instances-list">
|
|
||||||
<!-- Instances injected via JS -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -136,6 +104,65 @@
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modals -->
|
||||||
|
<div id="add-instance-modal" class="modal">
|
||||||
|
<div class="modal-content card">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Add Instance</h2>
|
||||||
|
<button class="btn-close">×</button>
|
||||||
|
</div>
|
||||||
|
<form id="add-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input type="text" id="name" placeholder="e.g. Steam Deck" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ip">IP Address</label>
|
||||||
|
<input type="text" id="ip" placeholder="192.168.1.100" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="port">Port</label>
|
||||||
|
<input type="number" id="port" value="4646" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="secret">OTP Secret</label>
|
||||||
|
<input type="password" id="secret" placeholder="Base32 Secret or otpauth:// URL" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Add Instance</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="help-modal" class="modal">
|
||||||
|
<div class="modal-content card">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Firewall Help</h2>
|
||||||
|
<button class="btn-close">×</button>
|
||||||
|
</div>
|
||||||
|
<p class="helper-text">Run these commands on the machine running XIVLauncher to allow incoming connections on the specified port.</p>
|
||||||
|
<div class="code-block">
|
||||||
|
<span class="code-label">UFW</span>
|
||||||
|
<div class="code-wrapper">
|
||||||
|
<code id="ufw-cmd">sudo ufw allow from localhost to any port 4646 proto tcp</code>
|
||||||
|
<button class="btn-copy" onclick="copyToClipboard('ufw-cmd')" title="Copy to clipboard">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="code-block">
|
||||||
|
<span class="code-label">iptables</span>
|
||||||
|
<div class="code-wrapper">
|
||||||
|
<code id="iptables-cmd">sudo iptables -I INPUT -p tcp -s localhost --dport 4646 -j ACCEPT</code>
|
||||||
|
<button class="btn-copy" onclick="copyToClipboard('iptables-cmd')" title="Copy to clipboard">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="login-overlay" class="login-overlay">
|
<div id="login-overlay" class="login-overlay">
|
||||||
<div class="login-card">
|
<div class="login-card">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
|
|
|
||||||
|
|
@ -419,3 +419,76 @@ input:focus {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modals */
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
z-index: 2000;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-close {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-close:hover {
|
||||||
|
color: var(--text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instances-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instances-header .actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue