@@ -0,0 +1,118 @@
|
||||
/* retoor <retoor@molodetz.nl> */
|
||||
|
||||
.workspace-page {
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
padding: var(--space-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.workspace-title {
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.workspace-muted {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.workspace-state {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.workspace-meters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-md);
|
||||
margin: var(--space-sm) 0;
|
||||
}
|
||||
|
||||
.workspace-meter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.workspace-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-sm);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.workspace-tunnel-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 var(--space-sm) 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.workspace-tunnel {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.workspace-badge {
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-secondary);
|
||||
border-radius: var(--radius);
|
||||
padding: 0 var(--space-xs);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.workspace-badge-active {
|
||||
background: var(--success);
|
||||
color: var(--bg-card);
|
||||
}
|
||||
|
||||
.workspace-badge-failed {
|
||||
background: var(--danger);
|
||||
color: var(--bg-card);
|
||||
}
|
||||
|
||||
.workspace-badge-provisioning,
|
||||
.workspace-badge-pending {
|
||||
background: var(--warning);
|
||||
color: var(--bg-card);
|
||||
}
|
||||
|
||||
.workspace-error {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.workspace-tunnel-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.workspace-suspended {
|
||||
border-left: 3px solid var(--danger);
|
||||
}
|
||||
|
||||
.workspace-flag-critical {
|
||||
border-left: 3px solid var(--danger);
|
||||
}
|
||||
|
||||
.workspace-flag-warn {
|
||||
border-left: 3px solid var(--warning);
|
||||
}
|
||||
|
||||
.workspace-flag-info {
|
||||
border-left: 3px solid var(--text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.workspace-meters {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import { Http } from "./Http.js";
|
||||
import { Poller } from "./Poller.js";
|
||||
|
||||
export class WorkspaceManager {
|
||||
constructor(root) {
|
||||
this.root = root;
|
||||
this.slug = root.dataset.slug;
|
||||
this.poller = null;
|
||||
this.bind();
|
||||
this.subscribe();
|
||||
}
|
||||
|
||||
static mount() {
|
||||
const root = document.querySelector("[data-workspace-root]");
|
||||
return root ? new WorkspaceManager(root) : null;
|
||||
}
|
||||
|
||||
bind() {
|
||||
this.root.addEventListener("submit", (event) => {
|
||||
const form = event.target.closest("form");
|
||||
if (!form || form.dataset.confirm) return;
|
||||
event.preventDefault();
|
||||
this.send(form);
|
||||
});
|
||||
}
|
||||
|
||||
async send(form) {
|
||||
try {
|
||||
await Http.sendForm(form);
|
||||
await this.refresh();
|
||||
} catch (error) {
|
||||
window.app?.toast?.show(error.message || "Action failed", { type: "error" });
|
||||
}
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
const uid = this.root.dataset.workspaceUid;
|
||||
if (uid && window.app?.pubsub) {
|
||||
window.app.pubsub.subscribe(`workspace.${uid}.detail`, () => this.render());
|
||||
}
|
||||
this.poller = new Poller(() => this.refresh(), 20000);
|
||||
this.poller.start();
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
try {
|
||||
const data = await Http.getJson(`/projects/${this.slug}/workspace`);
|
||||
this.render(data);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
render(data) {
|
||||
if (!data || !data.workspace) return;
|
||||
const state = this.root.querySelector("[data-workspace-status]");
|
||||
if (state) state.textContent = data.workspace.status || "";
|
||||
}
|
||||
}
|
||||
|
||||
export default WorkspaceManager;
|
||||
Reference in New Issue
Block a user