Files
kandev/apps/backend/cmd/plugin-fixture/fixture-package/ui/bundle.js
T
José Almeida 9c16d337a2 feat(web): add global app status surface (#1869)
* feat(web): add app status bar

* feat(web): add app status bar visibility toggle

* feat(web): persist status bar item order

* fix(web): refine app status bar behavior

* fix(web): polish app status bar presentation

* test(web): split plugin slot coverage groups

* fix(web): address status surface review feedback

* fix(web): stabilize status bar overlay tests
2026-07-23 12:28:54 +01:00

97 lines
3.0 KiB
JavaScript

/**
* Native JS UI bundle for the kandev-plugin-e2e fixture plugin
* (docs/plans/plugins/PLUGIN-API.md). A self-contained ES module — no
* imports, no bundled React — that calls `window.registerKandevPlugin(id,
* plugin)` at evaluation time and, on `initialize(registry, host)`,
* registers a nav item, a top-level route, a `task-sidebar` slot component,
* a `main-top-bar` slot component, and a `task.created` WS handler. Uses
* only host.React/host.jsx.
*
* The task-created counter lives in module scope (not component state) with
* a tiny listener set, so it survives across route navigations (the page
* component unmounts/remounts as the user navigates away and back).
*/
(function () {
var moduleCount = 0;
var listeners = new Set();
function emit() {
listeners.forEach(function (fn) {
fn(moduleCount);
});
}
function incrementCount() {
moduleCount += 1;
emit();
}
function useCounter(React) {
var state = React.useState(moduleCount);
var count = state[0];
var setCount = state[1];
React.useEffect(function () {
setCount(moduleCount);
listeners.add(setCount);
return function () {
listeners.delete(setCount);
};
}, []);
return count;
}
window.registerKandevPlugin("kandev-plugin-e2e", {
initialize: function (registry, host) {
var React = host.React;
var jsx = host.jsx;
function PluginPage() {
var count = useCounter(React);
return jsx(
"div",
{ id: "hello-plugin-page-root" },
jsx("h1", { id: "hello-plugin-page" }, "Hello E2E"),
jsx("span", { id: "hello-task-counter" }, String(count)),
);
}
function SidebarSlot() {
return jsx("div", { id: "hello-sidebar" }, "Hello E2E sidebar");
}
function MainTopBarSlot(props) {
var slotProps = props.slotProps || {};
return jsx("span", { id: "hello-main-top-bar" }, "Hello " + slotProps.currentPage);
}
function StatusSlot(props) {
var slotProps = props.slotProps || {};
var id = slotProps.placement === "left" ? "hello-status-left" : "hello-status-right";
return jsx(
"span",
{ id: id },
"Hello status " +
String(slotProps.presentation || "unknown") +
" " +
String(slotProps.activeTaskId || "no-task"),
);
}
registry.registerNavItem({
id: "e2e-hello",
label: "Hello E2E",
path: "/plugins/e2e-hello",
section: "main",
});
registry.registerRoute("/plugins/e2e-hello", PluginPage);
registry.registerComponent("task-sidebar", SidebarSlot);
registry.registerComponent("main-top-bar", MainTopBarSlot);
registry.registerComponent("app-status-bar-left", StatusSlot);
registry.registerComponent("app-status-bar-right", StatusSlot);
registry.registerWsHandler("task.created", function () {
incrementCount();
});
},
});
})();