Some checks are pending
build-and-push / image (push) Waiting to run
- Implemented demand pane for managing trend-driven design jobs. - Created diffusion pane for generating images via Stable Diffusion. - Added inbox pane for sweeping and routing artifacts through the CxAI inbox classifier. - Developed items pane for CRUD operations against /api/items. - Introduced lang pane for running language pipelines. - Established mac pane for macOS app distribution information. - Integrated slack pane for sending messages and displaying diagnostics. - Built system pane for process introspection and version information. - Launched tools pane for browsing and invoking MCP tools. - Set up websocket pane for connecting to the /ws/echo service.
80 lines
3.4 KiB
JavaScript
80 lines
3.4 KiB
JavaScript
// panes/slack.js — Slack sidecar.
|
|
import { registerPane } from '../app.js';
|
|
import { jget, jpost, escapeHtml } from '../lib/api.js';
|
|
import { fmtJSON, err } from '../lib/ui.js';
|
|
|
|
const TPL = `
|
|
<div class="pane-head">
|
|
<div><div class="title">Slack</div><div class="sub">Sidecar health and ad-hoc responses.</div></div>
|
|
<div class="grow"></div>
|
|
<button class="btn btn-secondary" id="slack-refresh">Refresh</button>
|
|
</div>
|
|
<div class="grid cols-2">
|
|
<div class="card">
|
|
<div class="card-title"><h2>Respond</h2></div>
|
|
<form id="slack-form" class="grid gap-3">
|
|
<label class="field"><span class="lbl">Message</span><textarea class="input" id="slack-text" rows="3" required></textarea></label>
|
|
<div class="grid cols-2 gap-3">
|
|
<label class="field"><span class="lbl">Channel</span><input class="input" id="slack-channel" placeholder="rest"/></label>
|
|
<label class="field"><span class="lbl">Thread ts</span><input class="input" id="slack-thread" placeholder="rest"/></label>
|
|
</div>
|
|
<button class="btn btn-primary" type="submit">Generate reply</button>
|
|
</form>
|
|
<h3 class="mt-3 mb-2">Reply</h3>
|
|
<pre id="slack-reply" class="muted">—</pre>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-title"><h2>Diagnostics</h2></div>
|
|
<h3 class="mb-2">healthz</h3><pre id="slack-health">…</pre>
|
|
<h3 class="mt-3 mb-2">info</h3><pre id="slack-info">…</pre>
|
|
<h3 class="mt-3 mb-2">memory</h3><pre id="slack-memory">…</pre>
|
|
<h3 class="mt-3 mb-2">tools</h3><div id="slack-tools">…</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
async function refresh(host) {
|
|
try {
|
|
const [h, info, mem, tools] = await Promise.all([
|
|
jget('/api/slack/healthz').catch(e => ({ error: e.message })),
|
|
jget('/api/slack/info').catch(e => ({ error: e.message })),
|
|
jget('/api/slack/memory').catch(e => ({ error: e.message })),
|
|
jget('/api/slack/tools').catch(e => ({ error: e.message })),
|
|
]);
|
|
host.querySelector('#slack-health').textContent = fmtJSON(h);
|
|
host.querySelector('#slack-info').textContent = fmtJSON(info);
|
|
host.querySelector('#slack-memory').textContent = fmtJSON(mem);
|
|
host.querySelector('#slack-tools').innerHTML = (tools.tools || []).map(t =>
|
|
`<div class="row"><div class="grow"><div class="ttl mono">${escapeHtml(t.name)}</div><div class="desc">${escapeHtml(t.description||'')}</div></div></div>`
|
|
).join('') || '<div class="muted" style="padding:12px">(none)</div>';
|
|
} catch (e) {
|
|
host.querySelector('#slack-health').textContent = e.message;
|
|
}
|
|
}
|
|
|
|
registerPane('slack', {
|
|
label: 'Slack',
|
|
init(host) {
|
|
host.innerHTML = TPL;
|
|
host.querySelector('#slack-refresh').addEventListener('click', () => refresh(host));
|
|
host.querySelector('#slack-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const body = {
|
|
text: host.querySelector('#slack-text').value,
|
|
channel: host.querySelector('#slack-channel').value || 'rest',
|
|
thread_ts: host.querySelector('#slack-thread').value || 'rest',
|
|
};
|
|
host.querySelector('#slack-reply').textContent = 'thinking…';
|
|
try {
|
|
const r = await jpost('/api/slack/respond', body);
|
|
host.querySelector('#slack-reply').textContent = r.reply || fmtJSON(r);
|
|
} catch (e) {
|
|
host.querySelector('#slack-reply').textContent = e.body?.detail || e.message;
|
|
err(e.message);
|
|
}
|
|
});
|
|
refresh(host);
|
|
},
|
|
refresh,
|
|
});
|