Merge claude/2
This commit is contained in:
commit
51069ae05a
@ -231,7 +231,8 @@
|
||||
Rich container detail panel — limits, image, healthcheck,
|
||||
networks, mounts. Rendered inside .task-details above the
|
||||
log container so it's discoverable from the existing "Logs"
|
||||
expand action.
|
||||
expand action. Gated behind the global Advanced UI mode so
|
||||
a Beginner doesn't see a wall of technical detail.
|
||||
============================================================ */
|
||||
.service-rich {
|
||||
display: flex;
|
||||
@ -239,6 +240,72 @@
|
||||
gap: 14px;
|
||||
margin: 8px 0 14px;
|
||||
}
|
||||
body:not(.lp-ui--advanced) .service-rich { display: none; }
|
||||
|
||||
/* ============================================================
|
||||
Beginner / Advanced toggle in the Services tab title row.
|
||||
Project-wide visual; same component will be reused wherever
|
||||
else surfaces grow an Advanced-only section.
|
||||
============================================================ */
|
||||
.services-title {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
.services-title-main { flex: 1; min-width: 0; }
|
||||
|
||||
.lp-ui-advanced-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.lp-ui-advanced-toggle input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.lp-ui-advanced-toggle-track {
|
||||
position: relative;
|
||||
width: 34px;
|
||||
height: 18px;
|
||||
background: rgba(var(--text-rgb), 0.18);
|
||||
border-radius: 999px;
|
||||
transition: background .15s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.lp-ui-advanced-toggle-thumb {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: var(--text-primary);
|
||||
border-radius: 50%;
|
||||
transition: transform .15s ease, background .15s ease;
|
||||
}
|
||||
.lp-ui-advanced-toggle input:checked + .lp-ui-advanced-toggle-track {
|
||||
background: var(--accent);
|
||||
}
|
||||
.lp-ui-advanced-toggle input:checked + .lp-ui-advanced-toggle-track .lp-ui-advanced-toggle-thumb {
|
||||
transform: translateX(16px);
|
||||
background: var(--text-on-accent, #0a1426);
|
||||
}
|
||||
.lp-ui-advanced-toggle-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: rgba(var(--text-rgb), 0.7);
|
||||
transition: color .15s ease;
|
||||
}
|
||||
.lp-ui-advanced-toggle:hover .lp-ui-advanced-toggle-label { color: var(--text-primary); }
|
||||
.lp-ui-advanced-toggle input:focus-visible + .lp-ui-advanced-toggle-track {
|
||||
outline: 2px solid rgba(var(--accent-rgb), 0.6);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.service-rich-grid {
|
||||
display: grid;
|
||||
|
||||
@ -1,3 +1,44 @@
|
||||
// Global "UI mode" — Beginner vs Advanced. First foothold of a
|
||||
// project-wide pattern: any surface that wants to render extra-technical
|
||||
// detail (mounts, limits, internals, raw IDs, …) gates it on
|
||||
// body.lp-ui--advanced. Default is OFF (Beginner) so a newcomer isn't
|
||||
// overwhelmed; flipping the toggle reveals everything site-wide.
|
||||
//
|
||||
// The flag persists per-browser via localStorage. The install will later
|
||||
// seed the initial value from CFG_INSTALL_LEVEL (Beginner | Advanced)
|
||||
// chosen on the very first setup screen — once that lands, the body
|
||||
// class is set server-side at template render time so there's no FOUC.
|
||||
// Until then, the user picks it from any surface that exposes a toggle
|
||||
// (currently the Services tab).
|
||||
(function setupLpUi() {
|
||||
if (window.LpUi && window.LpUi.advanced) return;
|
||||
const KEY = 'lp.ui.advanced';
|
||||
const advanced = {
|
||||
get() {
|
||||
try { return localStorage.getItem(KEY) === '1'; } catch { return false; }
|
||||
},
|
||||
set(on) {
|
||||
const v = !!on;
|
||||
try { localStorage.setItem(KEY, v ? '1' : '0'); } catch { /* private mode */ }
|
||||
document.body && document.body.classList.toggle('lp-ui--advanced', v);
|
||||
window.dispatchEvent(new CustomEvent('lp-ui-advanced-changed', { detail: { advanced: v } }));
|
||||
},
|
||||
apply() {
|
||||
if (!document.body) return;
|
||||
document.body.classList.toggle('lp-ui--advanced', this.get());
|
||||
},
|
||||
};
|
||||
window.LpUi = { ...(window.LpUi || {}), advanced };
|
||||
// Apply as early as possible — once the body exists, we drop the class
|
||||
// in so any already-rendered surface (e.g. another tab re-mounted with
|
||||
// .service-rich present) reflects the saved mode immediately.
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => advanced.apply(), { once: true });
|
||||
} else {
|
||||
advanced.apply();
|
||||
}
|
||||
})();
|
||||
|
||||
// Services tab on the app detail page.
|
||||
//
|
||||
// Each row renders a single docker compose service with:
|
||||
@ -87,10 +128,23 @@ class ServicesManager {
|
||||
|
||||
_titleBlock(appName) {
|
||||
const display = (appName || '').replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
||||
const adv = window.LpUi?.advanced?.get() ? 'checked' : '';
|
||||
// The toggle is the visible surface for the global "Advanced UI" mode
|
||||
// ([[window.LpUi.advanced]]). Flipping it here unhides the rich
|
||||
// container detail (limits, mounts, networks, healthcheck) across
|
||||
// every service row. The body class drives the CSS show/hide, so
|
||||
// other surfaces that opt into the same mode get it for free.
|
||||
return `
|
||||
<div class="services-title">
|
||||
<h3>⚡ Services</h3>
|
||||
<p>Inspect, restart and tail logs for the docker compose services that make up ${escapeHtml(display)}</p>
|
||||
<div class="services-title-main">
|
||||
<h3>⚡ Services</h3>
|
||||
<p>Inspect, restart and tail logs for the docker compose services that make up ${escapeHtml(display)}</p>
|
||||
</div>
|
||||
<label class="lp-ui-advanced-toggle" title="Reveal container internals (limits, mounts, networks, healthcheck)">
|
||||
<input type="checkbox" data-action="toggle-advanced" ${adv}>
|
||||
<span class="lp-ui-advanced-toggle-track"><span class="lp-ui-advanced-toggle-thumb"></span></span>
|
||||
<span class="lp-ui-advanced-toggle-label">Advanced</span>
|
||||
</label>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@ -449,7 +503,6 @@ class ServicesManager {
|
||||
<div class="meta-item"><strong>State:</strong> ${escapeHtml(state)}</div>
|
||||
<div class="meta-item"><strong>Status:</strong> ${escapeHtml(svc.statusText)}</div>
|
||||
</div>
|
||||
${this._renderRichDetail(info)}
|
||||
<div class="task-logs" style="position: relative;">
|
||||
<div class="log-container terminal-style service-log-output" data-stream="off" style="height: 200px; overflow-y: auto; border: 1px solid #444; border-radius: 4px; padding: 10px; background-color: #1a1a1a;"></div>
|
||||
<div class="service-log-overlay" style="position: absolute; inset: 0; display: none; flex-direction: column; align-items: center; justify-content: center; gap: 10px; background: rgba(20, 20, 24, 0.85); backdrop-filter: blur(2px); border-radius: 4px;">
|
||||
@ -460,6 +513,7 @@ class ServicesManager {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
${this._renderRichDetail(info)}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@ -487,6 +541,13 @@ class ServicesManager {
|
||||
this._resumeLogs(item, serviceName);
|
||||
}
|
||||
});
|
||||
// Advanced toggle lives in the title, not on a row — bind change here
|
||||
// so it works regardless of which service rows are present.
|
||||
root.addEventListener('change', (ev) => {
|
||||
const cb = ev.target.closest('[data-action="toggle-advanced"]');
|
||||
if (!cb || !window.LpUi?.advanced) return;
|
||||
window.LpUi.advanced.set(cb.checked);
|
||||
});
|
||||
}
|
||||
|
||||
async _restartService(serviceName, btn) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user