Five Lit custom elements following the go-scm UI pattern: - <core-process-panel> tabbed container (Daemons/Processes/Pipelines) - <core-process-daemons> daemon registry with health checks and stop - <core-process-list> managed processes with status badges - <core-process-output> live stdout/stderr WS stream viewer - <core-process-runner> pipeline execution results display Also adds provider.Renderable interface to ProcessProvider with Element() returning core-process-panel tag, extends WS channels with process-level events, and embeds the built UI bundle via go:embed. Co-Authored-By: Virgil <virgil@lethean.io>
1958 lines
56 KiB
JavaScript
1958 lines
56 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const V = globalThis, se = V.ShadowRoot && (V.ShadyCSS === void 0 || V.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, re = Symbol(), ne = /* @__PURE__ */ new WeakMap();
|
|
let $e = class {
|
|
constructor(e, t, i) {
|
|
if (this._$cssResult$ = !0, i !== re) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
|
|
this.cssText = e, this.t = t;
|
|
}
|
|
get styleSheet() {
|
|
let e = this.o;
|
|
const t = this.t;
|
|
if (se && e === void 0) {
|
|
const i = t !== void 0 && t.length === 1;
|
|
i && (e = ne.get(t)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), i && ne.set(t, e));
|
|
}
|
|
return e;
|
|
}
|
|
toString() {
|
|
return this.cssText;
|
|
}
|
|
};
|
|
const Ae = (s) => new $e(typeof s == "string" ? s : s + "", void 0, re), B = (s, ...e) => {
|
|
const t = s.length === 1 ? s[0] : e.reduce((i, r, n) => i + ((o) => {
|
|
if (o._$cssResult$ === !0) return o.cssText;
|
|
if (typeof o == "number") return o;
|
|
throw Error("Value passed to 'css' function must be a 'css' function result: " + o + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
|
|
})(r) + s[n + 1], s[0]);
|
|
return new $e(t, s, re);
|
|
}, ke = (s, e) => {
|
|
if (se) s.adoptedStyleSheets = e.map((t) => t instanceof CSSStyleSheet ? t : t.styleSheet);
|
|
else for (const t of e) {
|
|
const i = document.createElement("style"), r = V.litNonce;
|
|
r !== void 0 && i.setAttribute("nonce", r), i.textContent = t.cssText, s.appendChild(i);
|
|
}
|
|
}, ae = se ? (s) => s : (s) => s instanceof CSSStyleSheet ? ((e) => {
|
|
let t = "";
|
|
for (const i of e.cssRules) t += i.cssText;
|
|
return Ae(t);
|
|
})(s) : s;
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const { is: Se, defineProperty: Pe, getOwnPropertyDescriptor: Ce, getOwnPropertyNames: Ee, getOwnPropertySymbols: Ue, getPrototypeOf: Oe } = Object, A = globalThis, le = A.trustedTypes, ze = le ? le.emptyScript : "", X = A.reactiveElementPolyfillSupport, j = (s, e) => s, J = { toAttribute(s, e) {
|
|
switch (e) {
|
|
case Boolean:
|
|
s = s ? ze : null;
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
s = s == null ? s : JSON.stringify(s);
|
|
}
|
|
return s;
|
|
}, fromAttribute(s, e) {
|
|
let t = s;
|
|
switch (e) {
|
|
case Boolean:
|
|
t = s !== null;
|
|
break;
|
|
case Number:
|
|
t = s === null ? null : Number(s);
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
try {
|
|
t = JSON.parse(s);
|
|
} catch {
|
|
t = null;
|
|
}
|
|
}
|
|
return t;
|
|
} }, ie = (s, e) => !Se(s, e), ce = { attribute: !0, type: String, converter: J, reflect: !1, useDefault: !1, hasChanged: ie };
|
|
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), A.litPropertyMetadata ?? (A.litPropertyMetadata = /* @__PURE__ */ new WeakMap());
|
|
let D = class extends HTMLElement {
|
|
static addInitializer(e) {
|
|
this._$Ei(), (this.l ?? (this.l = [])).push(e);
|
|
}
|
|
static get observedAttributes() {
|
|
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
|
|
}
|
|
static createProperty(e, t = ce) {
|
|
if (t.state && (t.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(e) && ((t = Object.create(t)).wrapped = !0), this.elementProperties.set(e, t), !t.noAccessor) {
|
|
const i = Symbol(), r = this.getPropertyDescriptor(e, i, t);
|
|
r !== void 0 && Pe(this.prototype, e, r);
|
|
}
|
|
}
|
|
static getPropertyDescriptor(e, t, i) {
|
|
const { get: r, set: n } = Ce(this.prototype, e) ?? { get() {
|
|
return this[t];
|
|
}, set(o) {
|
|
this[t] = o;
|
|
} };
|
|
return { get: r, set(o) {
|
|
const l = r == null ? void 0 : r.call(this);
|
|
n == null || n.call(this, o), this.requestUpdate(e, l, i);
|
|
}, configurable: !0, enumerable: !0 };
|
|
}
|
|
static getPropertyOptions(e) {
|
|
return this.elementProperties.get(e) ?? ce;
|
|
}
|
|
static _$Ei() {
|
|
if (this.hasOwnProperty(j("elementProperties"))) return;
|
|
const e = Oe(this);
|
|
e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties);
|
|
}
|
|
static finalize() {
|
|
if (this.hasOwnProperty(j("finalized"))) return;
|
|
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(j("properties"))) {
|
|
const t = this.properties, i = [...Ee(t), ...Ue(t)];
|
|
for (const r of i) this.createProperty(r, t[r]);
|
|
}
|
|
const e = this[Symbol.metadata];
|
|
if (e !== null) {
|
|
const t = litPropertyMetadata.get(e);
|
|
if (t !== void 0) for (const [i, r] of t) this.elementProperties.set(i, r);
|
|
}
|
|
this._$Eh = /* @__PURE__ */ new Map();
|
|
for (const [t, i] of this.elementProperties) {
|
|
const r = this._$Eu(t, i);
|
|
r !== void 0 && this._$Eh.set(r, t);
|
|
}
|
|
this.elementStyles = this.finalizeStyles(this.styles);
|
|
}
|
|
static finalizeStyles(e) {
|
|
const t = [];
|
|
if (Array.isArray(e)) {
|
|
const i = new Set(e.flat(1 / 0).reverse());
|
|
for (const r of i) t.unshift(ae(r));
|
|
} else e !== void 0 && t.push(ae(e));
|
|
return t;
|
|
}
|
|
static _$Eu(e, t) {
|
|
const i = t.attribute;
|
|
return i === !1 ? void 0 : typeof i == "string" ? i : typeof e == "string" ? e.toLowerCase() : void 0;
|
|
}
|
|
constructor() {
|
|
super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev();
|
|
}
|
|
_$Ev() {
|
|
var e;
|
|
this._$ES = new Promise((t) => this.enableUpdating = t), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (e = this.constructor.l) == null || e.forEach((t) => t(this));
|
|
}
|
|
addController(e) {
|
|
var t;
|
|
(this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(e), this.renderRoot !== void 0 && this.isConnected && ((t = e.hostConnected) == null || t.call(e));
|
|
}
|
|
removeController(e) {
|
|
var t;
|
|
(t = this._$EO) == null || t.delete(e);
|
|
}
|
|
_$E_() {
|
|
const e = /* @__PURE__ */ new Map(), t = this.constructor.elementProperties;
|
|
for (const i of t.keys()) this.hasOwnProperty(i) && (e.set(i, this[i]), delete this[i]);
|
|
e.size > 0 && (this._$Ep = e);
|
|
}
|
|
createRenderRoot() {
|
|
const e = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
|
|
return ke(e, this.constructor.elementStyles), e;
|
|
}
|
|
connectedCallback() {
|
|
var e;
|
|
this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (e = this._$EO) == null || e.forEach((t) => {
|
|
var i;
|
|
return (i = t.hostConnected) == null ? void 0 : i.call(t);
|
|
});
|
|
}
|
|
enableUpdating(e) {
|
|
}
|
|
disconnectedCallback() {
|
|
var e;
|
|
(e = this._$EO) == null || e.forEach((t) => {
|
|
var i;
|
|
return (i = t.hostDisconnected) == null ? void 0 : i.call(t);
|
|
});
|
|
}
|
|
attributeChangedCallback(e, t, i) {
|
|
this._$AK(e, i);
|
|
}
|
|
_$ET(e, t) {
|
|
var n;
|
|
const i = this.constructor.elementProperties.get(e), r = this.constructor._$Eu(e, i);
|
|
if (r !== void 0 && i.reflect === !0) {
|
|
const o = (((n = i.converter) == null ? void 0 : n.toAttribute) !== void 0 ? i.converter : J).toAttribute(t, i.type);
|
|
this._$Em = e, o == null ? this.removeAttribute(r) : this.setAttribute(r, o), this._$Em = null;
|
|
}
|
|
}
|
|
_$AK(e, t) {
|
|
var n, o;
|
|
const i = this.constructor, r = i._$Eh.get(e);
|
|
if (r !== void 0 && this._$Em !== r) {
|
|
const l = i.getPropertyOptions(r), a = typeof l.converter == "function" ? { fromAttribute: l.converter } : ((n = l.converter) == null ? void 0 : n.fromAttribute) !== void 0 ? l.converter : J;
|
|
this._$Em = r;
|
|
const p = a.fromAttribute(t, l.type);
|
|
this[r] = p ?? ((o = this._$Ej) == null ? void 0 : o.get(r)) ?? p, this._$Em = null;
|
|
}
|
|
}
|
|
requestUpdate(e, t, i, r = !1, n) {
|
|
var o;
|
|
if (e !== void 0) {
|
|
const l = this.constructor;
|
|
if (r === !1 && (n = this[e]), i ?? (i = l.getPropertyOptions(e)), !((i.hasChanged ?? ie)(n, t) || i.useDefault && i.reflect && n === ((o = this._$Ej) == null ? void 0 : o.get(e)) && !this.hasAttribute(l._$Eu(e, i)))) return;
|
|
this.C(e, t, i);
|
|
}
|
|
this.isUpdatePending === !1 && (this._$ES = this._$EP());
|
|
}
|
|
C(e, t, { useDefault: i, reflect: r, wrapped: n }, o) {
|
|
i && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(e) && (this._$Ej.set(e, o ?? t ?? this[e]), n !== !0 || o !== void 0) || (this._$AL.has(e) || (this.hasUpdated || i || (t = void 0), this._$AL.set(e, t)), r === !0 && this._$Em !== e && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(e));
|
|
}
|
|
async _$EP() {
|
|
this.isUpdatePending = !0;
|
|
try {
|
|
await this._$ES;
|
|
} catch (t) {
|
|
Promise.reject(t);
|
|
}
|
|
const e = this.scheduleUpdate();
|
|
return e != null && await e, !this.isUpdatePending;
|
|
}
|
|
scheduleUpdate() {
|
|
return this.performUpdate();
|
|
}
|
|
performUpdate() {
|
|
var i;
|
|
if (!this.isUpdatePending) return;
|
|
if (!this.hasUpdated) {
|
|
if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) {
|
|
for (const [n, o] of this._$Ep) this[n] = o;
|
|
this._$Ep = void 0;
|
|
}
|
|
const r = this.constructor.elementProperties;
|
|
if (r.size > 0) for (const [n, o] of r) {
|
|
const { wrapped: l } = o, a = this[n];
|
|
l !== !0 || this._$AL.has(n) || a === void 0 || this.C(n, void 0, o, a);
|
|
}
|
|
}
|
|
let e = !1;
|
|
const t = this._$AL;
|
|
try {
|
|
e = this.shouldUpdate(t), e ? (this.willUpdate(t), (i = this._$EO) == null || i.forEach((r) => {
|
|
var n;
|
|
return (n = r.hostUpdate) == null ? void 0 : n.call(r);
|
|
}), this.update(t)) : this._$EM();
|
|
} catch (r) {
|
|
throw e = !1, this._$EM(), r;
|
|
}
|
|
e && this._$AE(t);
|
|
}
|
|
willUpdate(e) {
|
|
}
|
|
_$AE(e) {
|
|
var t;
|
|
(t = this._$EO) == null || t.forEach((i) => {
|
|
var r;
|
|
return (r = i.hostUpdated) == null ? void 0 : r.call(i);
|
|
}), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(e)), this.updated(e);
|
|
}
|
|
_$EM() {
|
|
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1;
|
|
}
|
|
get updateComplete() {
|
|
return this.getUpdateComplete();
|
|
}
|
|
getUpdateComplete() {
|
|
return this._$ES;
|
|
}
|
|
shouldUpdate(e) {
|
|
return !0;
|
|
}
|
|
update(e) {
|
|
this._$Eq && (this._$Eq = this._$Eq.forEach((t) => this._$ET(t, this[t]))), this._$EM();
|
|
}
|
|
updated(e) {
|
|
}
|
|
firstUpdated(e) {
|
|
}
|
|
};
|
|
D.elementStyles = [], D.shadowRootOptions = { mode: "open" }, D[j("elementProperties")] = /* @__PURE__ */ new Map(), D[j("finalized")] = /* @__PURE__ */ new Map(), X == null || X({ ReactiveElement: D }), (A.reactiveElementVersions ?? (A.reactiveElementVersions = [])).push("2.1.2");
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const N = globalThis, de = (s) => s, Z = N.trustedTypes, he = Z ? Z.createPolicy("lit-html", { createHTML: (s) => s }) : void 0, ye = "$lit$", x = `lit$${Math.random().toFixed(9).slice(2)}$`, ve = "?" + x, De = `<${ve}>`, E = document, I = () => E.createComment(""), L = (s) => s === null || typeof s != "object" && typeof s != "function", oe = Array.isArray, Te = (s) => oe(s) || typeof (s == null ? void 0 : s[Symbol.iterator]) == "function", Y = `[
|
|
\f\r]`, H = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, pe = /-->/g, ue = />/g, S = RegExp(`>|${Y}(?:([^\\s"'>=/]+)(${Y}*=${Y}*(?:[^
|
|
\f\r"'\`<>=]|("|')|))|$)`, "g"), me = /'/g, fe = /"/g, _e = /^(?:script|style|textarea|title)$/i, Me = (s) => (e, ...t) => ({ _$litType$: s, strings: e, values: t }), c = Me(1), T = Symbol.for("lit-noChange"), d = Symbol.for("lit-nothing"), ge = /* @__PURE__ */ new WeakMap(), P = E.createTreeWalker(E, 129);
|
|
function we(s, e) {
|
|
if (!oe(s) || !s.hasOwnProperty("raw")) throw Error("invalid template strings array");
|
|
return he !== void 0 ? he.createHTML(e) : e;
|
|
}
|
|
const Re = (s, e) => {
|
|
const t = s.length - 1, i = [];
|
|
let r, n = e === 2 ? "<svg>" : e === 3 ? "<math>" : "", o = H;
|
|
for (let l = 0; l < t; l++) {
|
|
const a = s[l];
|
|
let p, m, h = -1, b = 0;
|
|
for (; b < a.length && (o.lastIndex = b, m = o.exec(a), m !== null); ) b = o.lastIndex, o === H ? m[1] === "!--" ? o = pe : m[1] !== void 0 ? o = ue : m[2] !== void 0 ? (_e.test(m[2]) && (r = RegExp("</" + m[2], "g")), o = S) : m[3] !== void 0 && (o = S) : o === S ? m[0] === ">" ? (o = r ?? H, h = -1) : m[1] === void 0 ? h = -2 : (h = o.lastIndex - m[2].length, p = m[1], o = m[3] === void 0 ? S : m[3] === '"' ? fe : me) : o === fe || o === me ? o = S : o === pe || o === ue ? o = H : (o = S, r = void 0);
|
|
const w = o === S && s[l + 1].startsWith("/>") ? " " : "";
|
|
n += o === H ? a + De : h >= 0 ? (i.push(p), a.slice(0, h) + ye + a.slice(h) + x + w) : a + x + (h === -2 ? l : w);
|
|
}
|
|
return [we(s, n + (s[t] || "<?>") + (e === 2 ? "</svg>" : e === 3 ? "</math>" : "")), i];
|
|
};
|
|
class q {
|
|
constructor({ strings: e, _$litType$: t }, i) {
|
|
let r;
|
|
this.parts = [];
|
|
let n = 0, o = 0;
|
|
const l = e.length - 1, a = this.parts, [p, m] = Re(e, t);
|
|
if (this.el = q.createElement(p, i), P.currentNode = this.el.content, t === 2 || t === 3) {
|
|
const h = this.el.content.firstChild;
|
|
h.replaceWith(...h.childNodes);
|
|
}
|
|
for (; (r = P.nextNode()) !== null && a.length < l; ) {
|
|
if (r.nodeType === 1) {
|
|
if (r.hasAttributes()) for (const h of r.getAttributeNames()) if (h.endsWith(ye)) {
|
|
const b = m[o++], w = r.getAttribute(h).split(x), K = /([.?@])?(.*)/.exec(b);
|
|
a.push({ type: 1, index: n, name: K[2], strings: w, ctor: K[1] === "." ? je : K[1] === "?" ? Ne : K[1] === "@" ? Ie : G }), r.removeAttribute(h);
|
|
} else h.startsWith(x) && (a.push({ type: 6, index: n }), r.removeAttribute(h));
|
|
if (_e.test(r.tagName)) {
|
|
const h = r.textContent.split(x), b = h.length - 1;
|
|
if (b > 0) {
|
|
r.textContent = Z ? Z.emptyScript : "";
|
|
for (let w = 0; w < b; w++) r.append(h[w], I()), P.nextNode(), a.push({ type: 2, index: ++n });
|
|
r.append(h[b], I());
|
|
}
|
|
}
|
|
} else if (r.nodeType === 8) if (r.data === ve) a.push({ type: 2, index: n });
|
|
else {
|
|
let h = -1;
|
|
for (; (h = r.data.indexOf(x, h + 1)) !== -1; ) a.push({ type: 7, index: n }), h += x.length - 1;
|
|
}
|
|
n++;
|
|
}
|
|
}
|
|
static createElement(e, t) {
|
|
const i = E.createElement("template");
|
|
return i.innerHTML = e, i;
|
|
}
|
|
}
|
|
function M(s, e, t = s, i) {
|
|
var o, l;
|
|
if (e === T) return e;
|
|
let r = i !== void 0 ? (o = t._$Co) == null ? void 0 : o[i] : t._$Cl;
|
|
const n = L(e) ? void 0 : e._$litDirective$;
|
|
return (r == null ? void 0 : r.constructor) !== n && ((l = r == null ? void 0 : r._$AO) == null || l.call(r, !1), n === void 0 ? r = void 0 : (r = new n(s), r._$AT(s, t, i)), i !== void 0 ? (t._$Co ?? (t._$Co = []))[i] = r : t._$Cl = r), r !== void 0 && (e = M(s, r._$AS(s, e.values), r, i)), e;
|
|
}
|
|
class He {
|
|
constructor(e, t) {
|
|
this._$AV = [], this._$AN = void 0, this._$AD = e, this._$AM = t;
|
|
}
|
|
get parentNode() {
|
|
return this._$AM.parentNode;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
u(e) {
|
|
const { el: { content: t }, parts: i } = this._$AD, r = ((e == null ? void 0 : e.creationScope) ?? E).importNode(t, !0);
|
|
P.currentNode = r;
|
|
let n = P.nextNode(), o = 0, l = 0, a = i[0];
|
|
for (; a !== void 0; ) {
|
|
if (o === a.index) {
|
|
let p;
|
|
a.type === 2 ? p = new W(n, n.nextSibling, this, e) : a.type === 1 ? p = new a.ctor(n, a.name, a.strings, this, e) : a.type === 6 && (p = new Le(n, this, e)), this._$AV.push(p), a = i[++l];
|
|
}
|
|
o !== (a == null ? void 0 : a.index) && (n = P.nextNode(), o++);
|
|
}
|
|
return P.currentNode = E, r;
|
|
}
|
|
p(e) {
|
|
let t = 0;
|
|
for (const i of this._$AV) i !== void 0 && (i.strings !== void 0 ? (i._$AI(e, i, t), t += i.strings.length - 2) : i._$AI(e[t])), t++;
|
|
}
|
|
}
|
|
class W {
|
|
get _$AU() {
|
|
var e;
|
|
return ((e = this._$AM) == null ? void 0 : e._$AU) ?? this._$Cv;
|
|
}
|
|
constructor(e, t, i, r) {
|
|
this.type = 2, this._$AH = d, this._$AN = void 0, this._$AA = e, this._$AB = t, this._$AM = i, this.options = r, this._$Cv = (r == null ? void 0 : r.isConnected) ?? !0;
|
|
}
|
|
get parentNode() {
|
|
let e = this._$AA.parentNode;
|
|
const t = this._$AM;
|
|
return t !== void 0 && (e == null ? void 0 : e.nodeType) === 11 && (e = t.parentNode), e;
|
|
}
|
|
get startNode() {
|
|
return this._$AA;
|
|
}
|
|
get endNode() {
|
|
return this._$AB;
|
|
}
|
|
_$AI(e, t = this) {
|
|
e = M(this, e, t), L(e) ? e === d || e == null || e === "" ? (this._$AH !== d && this._$AR(), this._$AH = d) : e !== this._$AH && e !== T && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : Te(e) ? this.k(e) : this._(e);
|
|
}
|
|
O(e) {
|
|
return this._$AA.parentNode.insertBefore(e, this._$AB);
|
|
}
|
|
T(e) {
|
|
this._$AH !== e && (this._$AR(), this._$AH = this.O(e));
|
|
}
|
|
_(e) {
|
|
this._$AH !== d && L(this._$AH) ? this._$AA.nextSibling.data = e : this.T(E.createTextNode(e)), this._$AH = e;
|
|
}
|
|
$(e) {
|
|
var n;
|
|
const { values: t, _$litType$: i } = e, r = typeof i == "number" ? this._$AC(e) : (i.el === void 0 && (i.el = q.createElement(we(i.h, i.h[0]), this.options)), i);
|
|
if (((n = this._$AH) == null ? void 0 : n._$AD) === r) this._$AH.p(t);
|
|
else {
|
|
const o = new He(r, this), l = o.u(this.options);
|
|
o.p(t), this.T(l), this._$AH = o;
|
|
}
|
|
}
|
|
_$AC(e) {
|
|
let t = ge.get(e.strings);
|
|
return t === void 0 && ge.set(e.strings, t = new q(e)), t;
|
|
}
|
|
k(e) {
|
|
oe(this._$AH) || (this._$AH = [], this._$AR());
|
|
const t = this._$AH;
|
|
let i, r = 0;
|
|
for (const n of e) r === t.length ? t.push(i = new W(this.O(I()), this.O(I()), this, this.options)) : i = t[r], i._$AI(n), r++;
|
|
r < t.length && (this._$AR(i && i._$AB.nextSibling, r), t.length = r);
|
|
}
|
|
_$AR(e = this._$AA.nextSibling, t) {
|
|
var i;
|
|
for ((i = this._$AP) == null ? void 0 : i.call(this, !1, !0, t); e !== this._$AB; ) {
|
|
const r = de(e).nextSibling;
|
|
de(e).remove(), e = r;
|
|
}
|
|
}
|
|
setConnected(e) {
|
|
var t;
|
|
this._$AM === void 0 && (this._$Cv = e, (t = this._$AP) == null || t.call(this, e));
|
|
}
|
|
}
|
|
class G {
|
|
get tagName() {
|
|
return this.element.tagName;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
constructor(e, t, i, r, n) {
|
|
this.type = 1, this._$AH = d, this._$AN = void 0, this.element = e, this.name = t, this._$AM = r, this.options = n, i.length > 2 || i[0] !== "" || i[1] !== "" ? (this._$AH = Array(i.length - 1).fill(new String()), this.strings = i) : this._$AH = d;
|
|
}
|
|
_$AI(e, t = this, i, r) {
|
|
const n = this.strings;
|
|
let o = !1;
|
|
if (n === void 0) e = M(this, e, t, 0), o = !L(e) || e !== this._$AH && e !== T, o && (this._$AH = e);
|
|
else {
|
|
const l = e;
|
|
let a, p;
|
|
for (e = n[0], a = 0; a < n.length - 1; a++) p = M(this, l[i + a], t, a), p === T && (p = this._$AH[a]), o || (o = !L(p) || p !== this._$AH[a]), p === d ? e = d : e !== d && (e += (p ?? "") + n[a + 1]), this._$AH[a] = p;
|
|
}
|
|
o && !r && this.j(e);
|
|
}
|
|
j(e) {
|
|
e === d ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, e ?? "");
|
|
}
|
|
}
|
|
class je extends G {
|
|
constructor() {
|
|
super(...arguments), this.type = 3;
|
|
}
|
|
j(e) {
|
|
this.element[this.name] = e === d ? void 0 : e;
|
|
}
|
|
}
|
|
class Ne extends G {
|
|
constructor() {
|
|
super(...arguments), this.type = 4;
|
|
}
|
|
j(e) {
|
|
this.element.toggleAttribute(this.name, !!e && e !== d);
|
|
}
|
|
}
|
|
class Ie extends G {
|
|
constructor(e, t, i, r, n) {
|
|
super(e, t, i, r, n), this.type = 5;
|
|
}
|
|
_$AI(e, t = this) {
|
|
if ((e = M(this, e, t, 0) ?? d) === T) return;
|
|
const i = this._$AH, r = e === d && i !== d || e.capture !== i.capture || e.once !== i.once || e.passive !== i.passive, n = e !== d && (i === d || r);
|
|
r && this.element.removeEventListener(this.name, this, i), n && this.element.addEventListener(this.name, this, e), this._$AH = e;
|
|
}
|
|
handleEvent(e) {
|
|
var t;
|
|
typeof this._$AH == "function" ? this._$AH.call(((t = this.options) == null ? void 0 : t.host) ?? this.element, e) : this._$AH.handleEvent(e);
|
|
}
|
|
}
|
|
class Le {
|
|
constructor(e, t, i) {
|
|
this.element = e, this.type = 6, this._$AN = void 0, this._$AM = t, this.options = i;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
_$AI(e) {
|
|
M(this, e);
|
|
}
|
|
}
|
|
const ee = N.litHtmlPolyfillSupport;
|
|
ee == null || ee(q, W), (N.litHtmlVersions ?? (N.litHtmlVersions = [])).push("3.3.2");
|
|
const qe = (s, e, t) => {
|
|
const i = (t == null ? void 0 : t.renderBefore) ?? e;
|
|
let r = i._$litPart$;
|
|
if (r === void 0) {
|
|
const n = (t == null ? void 0 : t.renderBefore) ?? null;
|
|
i._$litPart$ = r = new W(e.insertBefore(I(), n), n, void 0, t ?? {});
|
|
}
|
|
return r._$AI(s), r;
|
|
};
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const C = globalThis;
|
|
class $ extends D {
|
|
constructor() {
|
|
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
|
|
}
|
|
createRenderRoot() {
|
|
var t;
|
|
const e = super.createRenderRoot();
|
|
return (t = this.renderOptions).renderBefore ?? (t.renderBefore = e.firstChild), e;
|
|
}
|
|
update(e) {
|
|
const t = this.render();
|
|
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = qe(t, this.renderRoot, this.renderOptions);
|
|
}
|
|
connectedCallback() {
|
|
var e;
|
|
super.connectedCallback(), (e = this._$Do) == null || e.setConnected(!0);
|
|
}
|
|
disconnectedCallback() {
|
|
var e;
|
|
super.disconnectedCallback(), (e = this._$Do) == null || e.setConnected(!1);
|
|
}
|
|
render() {
|
|
return T;
|
|
}
|
|
}
|
|
var be;
|
|
$._$litElement$ = !0, $.finalized = !0, (be = C.litElementHydrateSupport) == null || be.call(C, { LitElement: $ });
|
|
const te = C.litElementPolyfillSupport;
|
|
te == null || te({ LitElement: $ });
|
|
(C.litElementVersions ?? (C.litElementVersions = [])).push("4.2.2");
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const F = (s) => (e, t) => {
|
|
t !== void 0 ? t.addInitializer(() => {
|
|
customElements.define(s, e);
|
|
}) : customElements.define(s, e);
|
|
};
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const Be = { attribute: !0, type: String, converter: J, reflect: !1, hasChanged: ie }, We = (s = Be, e, t) => {
|
|
const { kind: i, metadata: r } = t;
|
|
let n = globalThis.litPropertyMetadata.get(r);
|
|
if (n === void 0 && globalThis.litPropertyMetadata.set(r, n = /* @__PURE__ */ new Map()), i === "setter" && ((s = Object.create(s)).wrapped = !0), n.set(t.name, s), i === "accessor") {
|
|
const { name: o } = t;
|
|
return { set(l) {
|
|
const a = e.get.call(this);
|
|
e.set.call(this, l), this.requestUpdate(o, a, s, !0, l);
|
|
}, init(l) {
|
|
return l !== void 0 && this.C(o, void 0, s, l), l;
|
|
} };
|
|
}
|
|
if (i === "setter") {
|
|
const { name: o } = t;
|
|
return function(l) {
|
|
const a = this[o];
|
|
e.call(this, l), this.requestUpdate(o, a, s, !0, l);
|
|
};
|
|
}
|
|
throw Error("Unsupported decorator location: " + i);
|
|
};
|
|
function f(s) {
|
|
return (e, t) => typeof t == "object" ? We(s, e, t) : ((i, r, n) => {
|
|
const o = r.hasOwnProperty(n);
|
|
return r.constructor.createProperty(n, i), o ? Object.getOwnPropertyDescriptor(r, n) : void 0;
|
|
})(s, e, t);
|
|
}
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
function u(s) {
|
|
return f({ ...s, state: !0, attribute: !1 });
|
|
}
|
|
function xe(s, e) {
|
|
const t = new WebSocket(s);
|
|
return t.onmessage = (i) => {
|
|
var r, n, o, l;
|
|
try {
|
|
const a = JSON.parse(i.data);
|
|
((n = (r = a.type) == null ? void 0 : r.startsWith) != null && n.call(r, "process.") || (l = (o = a.channel) == null ? void 0 : o.startsWith) != null && l.call(o, "process.")) && e(a);
|
|
} catch {
|
|
}
|
|
}, t;
|
|
}
|
|
class Fe {
|
|
constructor(e = "") {
|
|
this.baseUrl = e;
|
|
}
|
|
get base() {
|
|
return `${this.baseUrl}/api/process`;
|
|
}
|
|
async request(e, t) {
|
|
var n;
|
|
const r = await (await fetch(`${this.base}${e}`, t)).json();
|
|
if (!r.success)
|
|
throw new Error(((n = r.error) == null ? void 0 : n.message) ?? "Request failed");
|
|
return r.data;
|
|
}
|
|
/** List all alive daemons from the registry. */
|
|
listDaemons() {
|
|
return this.request("/daemons");
|
|
}
|
|
/** Get a single daemon entry by code and daemon name. */
|
|
getDaemon(e, t) {
|
|
return this.request(`/daemons/${e}/${t}`);
|
|
}
|
|
/** Stop a daemon (SIGTERM + unregister). */
|
|
stopDaemon(e, t) {
|
|
return this.request(`/daemons/${e}/${t}/stop`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
/** Check daemon health endpoint. */
|
|
healthCheck(e, t) {
|
|
return this.request(`/daemons/${e}/${t}/health`);
|
|
}
|
|
}
|
|
var Ke = Object.defineProperty, Ve = Object.getOwnPropertyDescriptor, k = (s, e, t, i) => {
|
|
for (var r = i > 1 ? void 0 : i ? Ve(e, t) : e, n = s.length - 1, o; n >= 0; n--)
|
|
(o = s[n]) && (r = (i ? o(e, t, r) : o(r)) || r);
|
|
return i && r && Ke(e, t, r), r;
|
|
};
|
|
let g = class extends $ {
|
|
constructor() {
|
|
super(...arguments), this.apiUrl = "", this.daemons = [], this.loading = !0, this.error = "", this.stopping = /* @__PURE__ */ new Set(), this.checking = /* @__PURE__ */ new Set(), this.healthResults = /* @__PURE__ */ new Map();
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.api = new Fe(this.apiUrl), this.loadDaemons();
|
|
}
|
|
async loadDaemons() {
|
|
this.loading = !0, this.error = "";
|
|
try {
|
|
this.daemons = await this.api.listDaemons();
|
|
} catch (s) {
|
|
this.error = s.message ?? "Failed to load daemons";
|
|
} finally {
|
|
this.loading = !1;
|
|
}
|
|
}
|
|
daemonKey(s) {
|
|
return `${s.code}/${s.daemon}`;
|
|
}
|
|
async handleStop(s) {
|
|
const e = this.daemonKey(s);
|
|
this.stopping = /* @__PURE__ */ new Set([...this.stopping, e]);
|
|
try {
|
|
await this.api.stopDaemon(s.code, s.daemon), this.dispatchEvent(
|
|
new CustomEvent("daemon-stopped", {
|
|
detail: { code: s.code, daemon: s.daemon },
|
|
bubbles: !0
|
|
})
|
|
), await this.loadDaemons();
|
|
} catch (t) {
|
|
this.error = t.message ?? "Failed to stop daemon";
|
|
} finally {
|
|
const t = new Set(this.stopping);
|
|
t.delete(e), this.stopping = t;
|
|
}
|
|
}
|
|
async handleHealthCheck(s) {
|
|
const e = this.daemonKey(s);
|
|
this.checking = /* @__PURE__ */ new Set([...this.checking, e]);
|
|
try {
|
|
const t = await this.api.healthCheck(s.code, s.daemon), i = new Map(this.healthResults);
|
|
i.set(e, t), this.healthResults = i;
|
|
} catch (t) {
|
|
this.error = t.message ?? "Health check failed";
|
|
} finally {
|
|
const t = new Set(this.checking);
|
|
t.delete(e), this.checking = t;
|
|
}
|
|
}
|
|
formatDate(s) {
|
|
try {
|
|
return new Date(s).toLocaleDateString("en-GB", {
|
|
day: "numeric",
|
|
month: "short",
|
|
year: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit"
|
|
});
|
|
} catch {
|
|
return s;
|
|
}
|
|
}
|
|
renderHealthBadge(s) {
|
|
const e = this.daemonKey(s);
|
|
if (this.checking.has(e))
|
|
return c`<span class="health-badge checking">Checking\u2026</span>`;
|
|
const t = this.healthResults.get(e);
|
|
return t ? c`<span class="health-badge ${t.healthy ? "healthy" : "unhealthy"}">
|
|
${t.healthy ? "Healthy" : "Unhealthy"}
|
|
</span>` : s.health ? c`<span class="health-badge unknown">Unchecked</span>` : c`<span class="health-badge unknown">No health endpoint</span>`;
|
|
}
|
|
render() {
|
|
return this.loading ? c`<div class="loading">Loading daemons\u2026</div>` : c`
|
|
${this.error ? c`<div class="error">${this.error}</div>` : d}
|
|
${this.daemons.length === 0 ? c`<div class="empty">No daemons registered.</div>` : c`
|
|
<div class="list">
|
|
${this.daemons.map((s) => {
|
|
const e = this.daemonKey(s);
|
|
return c`
|
|
<div class="item">
|
|
<div class="item-info">
|
|
<div class="item-name">
|
|
<span class="item-code">${s.code}</span>
|
|
<span>${s.daemon}</span>
|
|
${this.renderHealthBadge(s)}
|
|
</div>
|
|
<div class="item-meta">
|
|
<span class="pid-badge">PID ${s.pid}</span>
|
|
<span>Started ${this.formatDate(s.started)}</span>
|
|
${s.project ? c`<span>${s.project}</span>` : d}
|
|
${s.binary ? c`<span>${s.binary}</span>` : d}
|
|
</div>
|
|
</div>
|
|
<div class="item-actions">
|
|
${s.health ? c`
|
|
<button
|
|
class="health-btn"
|
|
?disabled=${this.checking.has(e)}
|
|
@click=${() => this.handleHealthCheck(s)}
|
|
>
|
|
${this.checking.has(e) ? "Checking…" : "Health"}
|
|
</button>
|
|
` : d}
|
|
<button
|
|
class="stop-btn"
|
|
?disabled=${this.stopping.has(e)}
|
|
@click=${() => this.handleStop(s)}
|
|
>
|
|
${this.stopping.has(e) ? "Stopping…" : "Stop"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
})}
|
|
</div>
|
|
`}
|
|
`;
|
|
}
|
|
};
|
|
g.styles = B`
|
|
:host {
|
|
display: block;
|
|
font-family: system-ui, -apple-system, sans-serif;
|
|
}
|
|
|
|
.list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.item {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
background: #fff;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
transition: box-shadow 0.15s;
|
|
}
|
|
|
|
.item:hover {
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.item-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.item-name {
|
|
font-weight: 600;
|
|
font-size: 0.9375rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.item-code {
|
|
font-family: monospace;
|
|
font-size: 0.8125rem;
|
|
colour: #6366f1;
|
|
}
|
|
|
|
.item-meta {
|
|
font-size: 0.75rem;
|
|
colour: #6b7280;
|
|
margin-top: 0.25rem;
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.pid-badge {
|
|
font-family: monospace;
|
|
background: #f3f4f6;
|
|
padding: 0.0625rem 0.375rem;
|
|
border-radius: 0.25rem;
|
|
font-size: 0.6875rem;
|
|
}
|
|
|
|
.health-badge {
|
|
font-size: 0.6875rem;
|
|
padding: 0.125rem 0.5rem;
|
|
border-radius: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.health-badge.healthy {
|
|
background: #dcfce7;
|
|
colour: #166534;
|
|
}
|
|
|
|
.health-badge.unhealthy {
|
|
background: #fef2f2;
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.health-badge.unknown {
|
|
background: #f3f4f6;
|
|
colour: #6b7280;
|
|
}
|
|
|
|
.health-badge.checking {
|
|
background: #fef3c7;
|
|
colour: #92400e;
|
|
}
|
|
|
|
.item-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
button {
|
|
padding: 0.375rem 0.75rem;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.8125rem;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
button.health-btn {
|
|
background: #fff;
|
|
colour: #6366f1;
|
|
border: 1px solid #6366f1;
|
|
}
|
|
|
|
button.health-btn:hover {
|
|
background: #eef2ff;
|
|
}
|
|
|
|
button.health-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
button.stop-btn {
|
|
background: #fff;
|
|
colour: #dc2626;
|
|
border: 1px solid #dc2626;
|
|
}
|
|
|
|
button.stop-btn:hover {
|
|
background: #fef2f2;
|
|
}
|
|
|
|
button.stop-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.empty {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #9ca3af;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.loading {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #6b7280;
|
|
}
|
|
|
|
.error {
|
|
colour: #dc2626;
|
|
padding: 0.75rem;
|
|
background: #fef2f2;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
`;
|
|
k([
|
|
f({ attribute: "api-url" })
|
|
], g.prototype, "apiUrl", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "daemons", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "loading", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "error", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "stopping", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "checking", 2);
|
|
k([
|
|
u()
|
|
], g.prototype, "healthResults", 2);
|
|
g = k([
|
|
F("core-process-daemons")
|
|
], g);
|
|
var Je = Object.defineProperty, Ze = Object.getOwnPropertyDescriptor, U = (s, e, t, i) => {
|
|
for (var r = i > 1 ? void 0 : i ? Ze(e, t) : e, n = s.length - 1, o; n >= 0; n--)
|
|
(o = s[n]) && (r = (i ? o(e, t, r) : o(r)) || r);
|
|
return i && r && Je(e, t, r), r;
|
|
};
|
|
let y = class extends $ {
|
|
constructor() {
|
|
super(...arguments), this.apiUrl = "", this.selectedId = "", this.processes = [], this.loading = !1, this.error = "", this.killing = /* @__PURE__ */ new Set();
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.loadProcesses();
|
|
}
|
|
async loadProcesses() {
|
|
this.loading = !1, this.processes = [];
|
|
}
|
|
handleSelect(s) {
|
|
this.dispatchEvent(
|
|
new CustomEvent("process-selected", {
|
|
detail: { id: s.id },
|
|
bubbles: !0,
|
|
composed: !0
|
|
})
|
|
);
|
|
}
|
|
formatUptime(s) {
|
|
try {
|
|
const e = Date.now() - new Date(s).getTime(), t = Math.floor(e / 1e3);
|
|
if (t < 60) return `${t}s`;
|
|
const i = Math.floor(t / 60);
|
|
return i < 60 ? `${i}m ${t % 60}s` : `${Math.floor(i / 60)}h ${i % 60}m`;
|
|
} catch {
|
|
return "unknown";
|
|
}
|
|
}
|
|
render() {
|
|
return this.loading ? c`<div class="loading">Loading processes\u2026</div>` : c`
|
|
${this.error ? c`<div class="error">${this.error}</div>` : d}
|
|
${this.processes.length === 0 ? c`
|
|
<div class="info-notice">
|
|
Process list endpoints are pending. Processes will appear here once
|
|
the REST API for managed processes is available.
|
|
</div>
|
|
<div class="empty">No managed processes.</div>
|
|
` : c`
|
|
<div class="list">
|
|
${this.processes.map(
|
|
(s) => {
|
|
var e;
|
|
return c`
|
|
<div
|
|
class="item ${this.selectedId === s.id ? "selected" : ""}"
|
|
@click=${() => this.handleSelect(s)}
|
|
>
|
|
<div class="item-info">
|
|
<div class="item-command">
|
|
<span>${s.command} ${((e = s.args) == null ? void 0 : e.join(" ")) ?? ""}</span>
|
|
<span class="status-badge ${s.status}">${s.status}</span>
|
|
</div>
|
|
<div class="item-meta">
|
|
<span class="pid-badge">PID ${s.pid}</span>
|
|
<span>${s.id}</span>
|
|
${s.dir ? c`<span>${s.dir}</span>` : d}
|
|
${s.status === "running" ? c`<span>Up ${this.formatUptime(s.startedAt)}</span>` : d}
|
|
${s.status === "exited" ? c`<span class="exit-code ${s.exitCode !== 0 ? "nonzero" : ""}">
|
|
exit ${s.exitCode}
|
|
</span>` : d}
|
|
</div>
|
|
</div>
|
|
${s.status === "running" ? c`
|
|
<div class="item-actions">
|
|
<button
|
|
class="kill-btn"
|
|
?disabled=${this.killing.has(s.id)}
|
|
@click=${(t) => {
|
|
t.stopPropagation();
|
|
}}
|
|
>
|
|
${this.killing.has(s.id) ? "Killing…" : "Kill"}
|
|
</button>
|
|
</div>
|
|
` : d}
|
|
</div>
|
|
`;
|
|
}
|
|
)}
|
|
</div>
|
|
`}
|
|
`;
|
|
}
|
|
};
|
|
y.styles = B`
|
|
:host {
|
|
display: block;
|
|
font-family: system-ui, -apple-system, sans-serif;
|
|
}
|
|
|
|
.list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.375rem;
|
|
}
|
|
|
|
.item {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
background: #fff;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
transition: box-shadow 0.15s, border-colour 0.15s;
|
|
}
|
|
|
|
.item:hover {
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.item.selected {
|
|
border-colour: #6366f1;
|
|
box-shadow: 0 0 0 1px #6366f1;
|
|
}
|
|
|
|
.item-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.item-command {
|
|
font-weight: 600;
|
|
font-size: 0.9375rem;
|
|
font-family: monospace;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.item-meta {
|
|
font-size: 0.75rem;
|
|
colour: #6b7280;
|
|
margin-top: 0.25rem;
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.status-badge {
|
|
font-size: 0.6875rem;
|
|
padding: 0.125rem 0.5rem;
|
|
border-radius: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-badge.running {
|
|
background: #dbeafe;
|
|
colour: #1e40af;
|
|
}
|
|
|
|
.status-badge.pending {
|
|
background: #fef3c7;
|
|
colour: #92400e;
|
|
}
|
|
|
|
.status-badge.exited {
|
|
background: #dcfce7;
|
|
colour: #166534;
|
|
}
|
|
|
|
.status-badge.failed {
|
|
background: #fef2f2;
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.status-badge.killed {
|
|
background: #fce7f3;
|
|
colour: #9d174d;
|
|
}
|
|
|
|
.exit-code {
|
|
font-family: monospace;
|
|
font-size: 0.6875rem;
|
|
background: #f3f4f6;
|
|
padding: 0.0625rem 0.375rem;
|
|
border-radius: 0.25rem;
|
|
}
|
|
|
|
.exit-code.nonzero {
|
|
background: #fef2f2;
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.pid-badge {
|
|
font-family: monospace;
|
|
background: #f3f4f6;
|
|
padding: 0.0625rem 0.375rem;
|
|
border-radius: 0.25rem;
|
|
font-size: 0.6875rem;
|
|
}
|
|
|
|
.item-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
button.kill-btn {
|
|
padding: 0.375rem 0.75rem;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.8125rem;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
background: #fff;
|
|
colour: #dc2626;
|
|
border: 1px solid #dc2626;
|
|
}
|
|
|
|
button.kill-btn:hover {
|
|
background: #fef2f2;
|
|
}
|
|
|
|
button.kill-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.empty {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #9ca3af;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.loading {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #6b7280;
|
|
}
|
|
|
|
.error {
|
|
colour: #dc2626;
|
|
padding: 0.75rem;
|
|
background: #fef2f2;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.info-notice {
|
|
padding: 0.75rem;
|
|
background: #eff6ff;
|
|
border: 1px solid #bfdbfe;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.8125rem;
|
|
colour: #1e40af;
|
|
margin-bottom: 1rem;
|
|
}
|
|
`;
|
|
U([
|
|
f({ attribute: "api-url" })
|
|
], y.prototype, "apiUrl", 2);
|
|
U([
|
|
f({ attribute: "selected-id" })
|
|
], y.prototype, "selectedId", 2);
|
|
U([
|
|
u()
|
|
], y.prototype, "processes", 2);
|
|
U([
|
|
u()
|
|
], y.prototype, "loading", 2);
|
|
U([
|
|
u()
|
|
], y.prototype, "error", 2);
|
|
U([
|
|
u()
|
|
], y.prototype, "killing", 2);
|
|
y = U([
|
|
F("core-process-list")
|
|
], y);
|
|
var Ge = Object.defineProperty, Qe = Object.getOwnPropertyDescriptor, O = (s, e, t, i) => {
|
|
for (var r = i > 1 ? void 0 : i ? Qe(e, t) : e, n = s.length - 1, o; n >= 0; n--)
|
|
(o = s[n]) && (r = (i ? o(e, t, r) : o(r)) || r);
|
|
return i && r && Ge(e, t, r), r;
|
|
};
|
|
let v = class extends $ {
|
|
constructor() {
|
|
super(...arguments), this.apiUrl = "", this.wsUrl = "", this.processId = "", this.lines = [], this.autoScroll = !0, this.connected = !1, this.ws = null;
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.wsUrl && this.processId && this.connect();
|
|
}
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback(), this.disconnect();
|
|
}
|
|
updated(s) {
|
|
(s.has("processId") || s.has("wsUrl")) && (this.disconnect(), this.lines = [], this.wsUrl && this.processId && this.connect()), this.autoScroll && this.scrollToBottom();
|
|
}
|
|
connect() {
|
|
this.ws = xe(this.wsUrl, (s) => {
|
|
const e = s.data;
|
|
if (!e) return;
|
|
(s.channel ?? s.type ?? "") === "process.output" && e.id === this.processId && (this.lines = [
|
|
...this.lines,
|
|
{
|
|
text: e.line ?? "",
|
|
stream: e.stream === "stderr" ? "stderr" : "stdout",
|
|
timestamp: Date.now()
|
|
}
|
|
]);
|
|
}), this.ws.onopen = () => {
|
|
this.connected = !0;
|
|
}, this.ws.onclose = () => {
|
|
this.connected = !1;
|
|
};
|
|
}
|
|
disconnect() {
|
|
this.ws && (this.ws.close(), this.ws = null), this.connected = !1;
|
|
}
|
|
handleClear() {
|
|
this.lines = [];
|
|
}
|
|
handleAutoScrollToggle() {
|
|
this.autoScroll = !this.autoScroll;
|
|
}
|
|
scrollToBottom() {
|
|
var e;
|
|
const s = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".output-body");
|
|
s && (s.scrollTop = s.scrollHeight);
|
|
}
|
|
render() {
|
|
return this.processId ? c`
|
|
<div class="output-header">
|
|
<span class="output-title">Output: ${this.processId}</span>
|
|
<div class="output-actions">
|
|
<label class="auto-scroll-toggle">
|
|
<input
|
|
type="checkbox"
|
|
?checked=${this.autoScroll}
|
|
@change=${this.handleAutoScrollToggle}
|
|
/>
|
|
Auto-scroll
|
|
</label>
|
|
<button class="clear-btn" @click=${this.handleClear}>Clear</button>
|
|
</div>
|
|
</div>
|
|
<div class="output-body">
|
|
${this.lines.length === 0 ? c`<div class="waiting">Waiting for output\u2026</div>` : this.lines.map(
|
|
(s) => c`
|
|
<div class="line ${s.stream}">
|
|
<span class="stream-tag">${s.stream}</span>${s.text}
|
|
</div>
|
|
`
|
|
)}
|
|
</div>
|
|
` : c`<div class="empty">Select a process to view its output.</div>`;
|
|
}
|
|
};
|
|
v.styles = B`
|
|
:host {
|
|
display: block;
|
|
font-family: system-ui, -apple-system, sans-serif;
|
|
margin-top: 0.75rem;
|
|
}
|
|
|
|
.output-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.5rem 0.75rem;
|
|
background: #1e1e1e;
|
|
border-radius: 0.5rem 0.5rem 0 0;
|
|
colour: #d4d4d4;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.output-title {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.output-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
button.clear-btn {
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 0.25rem;
|
|
font-size: 0.6875rem;
|
|
cursor: pointer;
|
|
background: #333;
|
|
colour: #d4d4d4;
|
|
border: 1px solid #555;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
button.clear-btn:hover {
|
|
background: #444;
|
|
}
|
|
|
|
.auto-scroll-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
font-size: 0.6875rem;
|
|
colour: #d4d4d4;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.auto-scroll-toggle input {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.output-body {
|
|
background: #1e1e1e;
|
|
border-radius: 0 0 0.5rem 0.5rem;
|
|
padding: 0.5rem 0.75rem;
|
|
max-height: 24rem;
|
|
overflow-y: auto;
|
|
font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
font-size: 0.8125rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.line {
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.line.stdout {
|
|
colour: #d4d4d4;
|
|
}
|
|
|
|
.line.stderr {
|
|
colour: #f87171;
|
|
}
|
|
|
|
.stream-tag {
|
|
display: inline-block;
|
|
width: 3rem;
|
|
font-size: 0.625rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
opacity: 0.5;
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
.empty {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #6b7280;
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.waiting {
|
|
colour: #9ca3af;
|
|
font-style: italic;
|
|
padding: 1rem;
|
|
text-align: center;
|
|
font-size: 0.8125rem;
|
|
}
|
|
`;
|
|
O([
|
|
f({ attribute: "api-url" })
|
|
], v.prototype, "apiUrl", 2);
|
|
O([
|
|
f({ attribute: "ws-url" })
|
|
], v.prototype, "wsUrl", 2);
|
|
O([
|
|
f({ attribute: "process-id" })
|
|
], v.prototype, "processId", 2);
|
|
O([
|
|
u()
|
|
], v.prototype, "lines", 2);
|
|
O([
|
|
u()
|
|
], v.prototype, "autoScroll", 2);
|
|
O([
|
|
u()
|
|
], v.prototype, "connected", 2);
|
|
v = O([
|
|
F("core-process-output")
|
|
], v);
|
|
var Xe = Object.defineProperty, Ye = Object.getOwnPropertyDescriptor, Q = (s, e, t, i) => {
|
|
for (var r = i > 1 ? void 0 : i ? Ye(e, t) : e, n = s.length - 1, o; n >= 0; n--)
|
|
(o = s[n]) && (r = (i ? o(e, t, r) : o(r)) || r);
|
|
return i && r && Xe(e, t, r), r;
|
|
};
|
|
let R = class extends $ {
|
|
constructor() {
|
|
super(...arguments), this.apiUrl = "", this.result = null, this.expandedOutputs = /* @__PURE__ */ new Set();
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.loadResults();
|
|
}
|
|
async loadResults() {
|
|
}
|
|
toggleOutput(s) {
|
|
const e = new Set(this.expandedOutputs);
|
|
e.has(s) ? e.delete(s) : e.add(s), this.expandedOutputs = e;
|
|
}
|
|
formatDuration(s) {
|
|
return s < 1e6 ? `${(s / 1e3).toFixed(0)}µs` : s < 1e9 ? `${(s / 1e6).toFixed(0)}ms` : `${(s / 1e9).toFixed(2)}s`;
|
|
}
|
|
resultStatus(s) {
|
|
return s.skipped ? "skipped" : s.passed ? "passed" : "failed";
|
|
}
|
|
render() {
|
|
if (!this.result)
|
|
return c`
|
|
<div class="info-notice">
|
|
Pipeline runner endpoints are pending. Pass pipeline results via the
|
|
<code>result</code> property, or results will appear here once the REST
|
|
API for pipeline execution is available.
|
|
</div>
|
|
<div class="empty">No pipeline results.</div>
|
|
`;
|
|
const { results: s, duration: e, passed: t, failed: i, skipped: r, success: n } = this.result;
|
|
return c`
|
|
<div class="summary">
|
|
<span class="overall-badge ${n ? "success" : "failure"}">
|
|
${n ? "Passed" : "Failed"}
|
|
</span>
|
|
<div class="summary-stat">
|
|
<span class="summary-value passed">${t}</span>
|
|
<span class="summary-label">Passed</span>
|
|
</div>
|
|
<div class="summary-stat">
|
|
<span class="summary-value failed">${i}</span>
|
|
<span class="summary-label">Failed</span>
|
|
</div>
|
|
<div class="summary-stat">
|
|
<span class="summary-value skipped">${r}</span>
|
|
<span class="summary-label">Skipped</span>
|
|
</div>
|
|
<span class="summary-duration">${this.formatDuration(e)}</span>
|
|
</div>
|
|
|
|
<div class="list">
|
|
${s.map(
|
|
(o) => c`
|
|
<div class="spec">
|
|
<div class="spec-header">
|
|
<div class="spec-name">
|
|
<span>${o.name}</span>
|
|
<span class="result-badge ${this.resultStatus(o)}">${this.resultStatus(o)}</span>
|
|
</div>
|
|
<span class="duration">${this.formatDuration(o.duration)}</span>
|
|
</div>
|
|
<div class="spec-meta">
|
|
${o.exitCode !== 0 && !o.skipped ? c`<span>exit ${o.exitCode}</span>` : d}
|
|
</div>
|
|
${o.error ? c`<div class="spec-error">${o.error}</div>` : d}
|
|
${o.output ? c`
|
|
<button class="toggle-output" @click=${() => this.toggleOutput(o.name)}>
|
|
${this.expandedOutputs.has(o.name) ? "Hide output" : "Show output"}
|
|
</button>
|
|
${this.expandedOutputs.has(o.name) ? c`<div class="spec-output">${o.output}</div>` : d}
|
|
` : d}
|
|
</div>
|
|
`
|
|
)}
|
|
</div>
|
|
`;
|
|
}
|
|
};
|
|
R.styles = B`
|
|
:host {
|
|
display: block;
|
|
font-family: system-ui, -apple-system, sans-serif;
|
|
}
|
|
|
|
.summary {
|
|
display: flex;
|
|
gap: 1rem;
|
|
padding: 0.75rem 1rem;
|
|
background: #fff;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.summary-stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.summary-value {
|
|
font-weight: 700;
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.summary-label {
|
|
font-size: 0.6875rem;
|
|
colour: #6b7280;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.025em;
|
|
}
|
|
|
|
.summary-value.passed {
|
|
colour: #166534;
|
|
}
|
|
|
|
.summary-value.failed {
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.summary-value.skipped {
|
|
colour: #92400e;
|
|
}
|
|
|
|
.summary-duration {
|
|
margin-left: auto;
|
|
font-size: 0.8125rem;
|
|
colour: #6b7280;
|
|
}
|
|
|
|
.overall-badge {
|
|
font-size: 0.75rem;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.overall-badge.success {
|
|
background: #dcfce7;
|
|
colour: #166534;
|
|
}
|
|
|
|
.overall-badge.failure {
|
|
background: #fef2f2;
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.375rem;
|
|
}
|
|
|
|
.spec {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
background: #fff;
|
|
transition: box-shadow 0.15s;
|
|
}
|
|
|
|
.spec:hover {
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.spec-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.spec-name {
|
|
font-weight: 600;
|
|
font-size: 0.9375rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.spec-meta {
|
|
font-size: 0.75rem;
|
|
colour: #6b7280;
|
|
margin-top: 0.25rem;
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.result-badge {
|
|
font-size: 0.6875rem;
|
|
padding: 0.125rem 0.5rem;
|
|
border-radius: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.result-badge.passed {
|
|
background: #dcfce7;
|
|
colour: #166534;
|
|
}
|
|
|
|
.result-badge.failed {
|
|
background: #fef2f2;
|
|
colour: #991b1b;
|
|
}
|
|
|
|
.result-badge.skipped {
|
|
background: #fef3c7;
|
|
colour: #92400e;
|
|
}
|
|
|
|
.duration {
|
|
font-family: monospace;
|
|
font-size: 0.75rem;
|
|
colour: #6b7280;
|
|
}
|
|
|
|
.deps {
|
|
font-size: 0.6875rem;
|
|
colour: #9ca3af;
|
|
}
|
|
|
|
.spec-output {
|
|
margin-top: 0.5rem;
|
|
padding: 0.5rem 0.75rem;
|
|
background: #1e1e1e;
|
|
border-radius: 0.375rem;
|
|
font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
font-size: 0.75rem;
|
|
line-height: 1.5;
|
|
colour: #d4d4d4;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
max-height: 12rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.spec-error {
|
|
margin-top: 0.375rem;
|
|
font-size: 0.75rem;
|
|
colour: #dc2626;
|
|
}
|
|
|
|
.toggle-output {
|
|
font-size: 0.6875rem;
|
|
colour: #6366f1;
|
|
cursor: pointer;
|
|
background: none;
|
|
border: none;
|
|
padding: 0;
|
|
margin-top: 0.375rem;
|
|
}
|
|
|
|
.toggle-output:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.empty {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
colour: #9ca3af;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.info-notice {
|
|
padding: 0.75rem;
|
|
background: #eff6ff;
|
|
border: 1px solid #bfdbfe;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.8125rem;
|
|
colour: #1e40af;
|
|
margin-bottom: 1rem;
|
|
}
|
|
`;
|
|
Q([
|
|
f({ attribute: "api-url" })
|
|
], R.prototype, "apiUrl", 2);
|
|
Q([
|
|
f({ type: Object })
|
|
], R.prototype, "result", 2);
|
|
Q([
|
|
u()
|
|
], R.prototype, "expandedOutputs", 2);
|
|
R = Q([
|
|
F("core-process-runner")
|
|
], R);
|
|
var et = Object.defineProperty, tt = Object.getOwnPropertyDescriptor, z = (s, e, t, i) => {
|
|
for (var r = i > 1 ? void 0 : i ? tt(e, t) : e, n = s.length - 1, o; n >= 0; n--)
|
|
(o = s[n]) && (r = (i ? o(e, t, r) : o(r)) || r);
|
|
return i && r && et(e, t, r), r;
|
|
};
|
|
let _ = class extends $ {
|
|
constructor() {
|
|
super(...arguments), this.apiUrl = "", this.wsUrl = "", this.activeTab = "daemons", this.wsConnected = !1, this.lastEvent = "", this.selectedProcessId = "", this.ws = null, this.tabs = [
|
|
{ id: "daemons", label: "Daemons" },
|
|
{ id: "processes", label: "Processes" },
|
|
{ id: "pipelines", label: "Pipelines" }
|
|
];
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.wsUrl && this.connectWs();
|
|
}
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback(), this.ws && (this.ws.close(), this.ws = null);
|
|
}
|
|
connectWs() {
|
|
this.ws = xe(this.wsUrl, (s) => {
|
|
this.lastEvent = s.channel ?? s.type ?? "", this.requestUpdate();
|
|
}), this.ws.onopen = () => {
|
|
this.wsConnected = !0;
|
|
}, this.ws.onclose = () => {
|
|
this.wsConnected = !1;
|
|
};
|
|
}
|
|
handleTabClick(s) {
|
|
this.activeTab = s;
|
|
}
|
|
handleRefresh() {
|
|
var e;
|
|
const s = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".content");
|
|
if (s) {
|
|
const t = s.firstElementChild;
|
|
t && "loadDaemons" in t ? t.loadDaemons() : t && "loadProcesses" in t ? t.loadProcesses() : t && "loadResults" in t && t.loadResults();
|
|
}
|
|
}
|
|
handleProcessSelected(s) {
|
|
this.selectedProcessId = s.detail.id;
|
|
}
|
|
renderContent() {
|
|
switch (this.activeTab) {
|
|
case "daemons":
|
|
return c`<core-process-daemons api-url=${this.apiUrl}></core-process-daemons>`;
|
|
case "processes":
|
|
return c`
|
|
<core-process-list
|
|
api-url=${this.apiUrl}
|
|
@process-selected=${this.handleProcessSelected}
|
|
></core-process-list>
|
|
${this.selectedProcessId ? c`<core-process-output
|
|
api-url=${this.apiUrl}
|
|
ws-url=${this.wsUrl}
|
|
process-id=${this.selectedProcessId}
|
|
></core-process-output>` : d}
|
|
`;
|
|
case "pipelines":
|
|
return c`<core-process-runner api-url=${this.apiUrl}></core-process-runner>`;
|
|
default:
|
|
return d;
|
|
}
|
|
}
|
|
render() {
|
|
const s = this.wsUrl ? this.wsConnected ? "connected" : "disconnected" : "idle";
|
|
return c`
|
|
<div class="header">
|
|
<span class="title">Process Manager</span>
|
|
<button class="refresh-btn" @click=${this.handleRefresh}>Refresh</button>
|
|
</div>
|
|
|
|
<div class="tabs">
|
|
${this.tabs.map(
|
|
(e) => c`
|
|
<button
|
|
class="tab ${this.activeTab === e.id ? "active" : ""}"
|
|
@click=${() => this.handleTabClick(e.id)}
|
|
>
|
|
${e.label}
|
|
</button>
|
|
`
|
|
)}
|
|
</div>
|
|
|
|
<div class="content">${this.renderContent()}</div>
|
|
|
|
<div class="footer">
|
|
<div class="ws-status">
|
|
<span class="ws-dot ${s}"></span>
|
|
<span>${s === "connected" ? "Connected" : s === "disconnected" ? "Disconnected" : "No WebSocket"}</span>
|
|
</div>
|
|
${this.lastEvent ? c`<span>Last: ${this.lastEvent}</span>` : d}
|
|
</div>
|
|
`;
|
|
}
|
|
};
|
|
_.styles = B`
|
|
:host {
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-family: system-ui, -apple-system, sans-serif;
|
|
height: 100%;
|
|
background: #fafafa;
|
|
}
|
|
|
|
/* H — Header */
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.75rem 1rem;
|
|
background: #fff;
|
|
border-bottom: 1px solid #e5e7eb;
|
|
}
|
|
|
|
.title {
|
|
font-weight: 700;
|
|
font-size: 1rem;
|
|
colour: #111827;
|
|
}
|
|
|
|
.refresh-btn {
|
|
padding: 0.375rem 0.75rem;
|
|
border: 1px solid #d1d5db;
|
|
border-radius: 0.375rem;
|
|
background: #fff;
|
|
font-size: 0.8125rem;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.refresh-btn:hover {
|
|
background: #f3f4f6;
|
|
}
|
|
|
|
/* H-L — Tabs */
|
|
.tabs {
|
|
display: flex;
|
|
gap: 0;
|
|
background: #fff;
|
|
border-bottom: 1px solid #e5e7eb;
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
.tab {
|
|
padding: 0.625rem 1rem;
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
colour: #6b7280;
|
|
cursor: pointer;
|
|
border-bottom: 2px solid transparent;
|
|
transition: all 0.15s;
|
|
background: none;
|
|
border-top: none;
|
|
border-left: none;
|
|
border-right: none;
|
|
}
|
|
|
|
.tab:hover {
|
|
colour: #374151;
|
|
}
|
|
|
|
.tab.active {
|
|
colour: #6366f1;
|
|
border-bottom-colour: #6366f1;
|
|
}
|
|
|
|
/* C — Content */
|
|
.content {
|
|
flex: 1;
|
|
padding: 1rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* F — Footer / Status bar */
|
|
.footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.5rem 1rem;
|
|
background: #fff;
|
|
border-top: 1px solid #e5e7eb;
|
|
font-size: 0.75rem;
|
|
colour: #9ca3af;
|
|
}
|
|
|
|
.ws-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
}
|
|
|
|
.ws-dot {
|
|
width: 0.5rem;
|
|
height: 0.5rem;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.ws-dot.connected {
|
|
background: #22c55e;
|
|
}
|
|
|
|
.ws-dot.disconnected {
|
|
background: #ef4444;
|
|
}
|
|
|
|
.ws-dot.idle {
|
|
background: #d1d5db;
|
|
}
|
|
`;
|
|
z([
|
|
f({ attribute: "api-url" })
|
|
], _.prototype, "apiUrl", 2);
|
|
z([
|
|
f({ attribute: "ws-url" })
|
|
], _.prototype, "wsUrl", 2);
|
|
z([
|
|
u()
|
|
], _.prototype, "activeTab", 2);
|
|
z([
|
|
u()
|
|
], _.prototype, "wsConnected", 2);
|
|
z([
|
|
u()
|
|
], _.prototype, "lastEvent", 2);
|
|
z([
|
|
u()
|
|
], _.prototype, "selectedProcessId", 2);
|
|
_ = z([
|
|
F("core-process-panel")
|
|
], _);
|
|
export {
|
|
Fe as ProcessApi,
|
|
g as ProcessDaemons,
|
|
y as ProcessList,
|
|
v as ProcessOutput,
|
|
_ as ProcessPanel,
|
|
R as ProcessRunner,
|
|
xe as connectProcessEvents
|
|
};
|