generated from coulomb/repo-seed
ihf-annotation-launcher.js: vanilla JS, no framework dependency. Scans DOM for data-widget-id elements, injects Annotate trigger, opens inline form, POSTs to /widgets/:widgetId/annotations. Works in React/Vue-rendered pages via MutationObserver. Feature-gated by IHP_ANNOTATION_LAUNCHER=true env var (Config.hs AnnotationLauncherEnabled, FrontController layout conditional). Docs: docs/annotation-launcher.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
2.2 KiB
Markdown
80 lines
2.2 KiB
Markdown
# IHF Annotation Launcher
|
|
|
|
`static/js/ihf-annotation-launcher.js` is a self-contained vanilla JS module
|
|
that injects an **Annotate** button adjacent to every element that carries a
|
|
`data-widget-id` attribute.
|
|
|
|
It works in IHP server-rendered pages **and** in React/Vue pages where IHP does
|
|
not own the DOM — the launcher relies solely on the presence of `data-widget-id`,
|
|
not on any framework-specific structure.
|
|
|
|
## Activation
|
|
|
|
Set the environment variable before starting the server:
|
|
|
|
```bash
|
|
IHP_ANNOTATION_LAUNCHER=true devenv up
|
|
```
|
|
|
|
This causes IHP to emit the following tag in every page's `<head>`:
|
|
|
|
```html
|
|
<script src="/js/ihf-annotation-launcher.js"></script>
|
|
```
|
|
|
|
When `IHP_ANNOTATION_LAUNCHER` is absent or not `"true"`, the script is not
|
|
loaded.
|
|
|
|
## Data attributes
|
|
|
|
| Attribute | Required | Description |
|
|
|--------------------|----------|--------------------------------------------------|
|
|
| `data-widget-id` | Yes | UUID of the widget (from the widget registry) |
|
|
| `data-hub-id` | No | UUID of the hub — read from element or nearest ancestor |
|
|
| `data-view-context`| No | Logical UI location (informational) |
|
|
|
|
## Usage in React
|
|
|
|
Because the launcher uses `MutationObserver`, it will pick up React-rendered
|
|
elements after mount:
|
|
|
|
```jsx
|
|
function MyWidget({ widgetId, hubId }) {
|
|
return (
|
|
<div data-widget-id={widgetId} data-hub-id={hubId}>
|
|
<button>Do something</button>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
No other integration is required. The launcher injects the Annotate button and
|
|
handles POST submission to `/widgets/:widgetId/annotations`.
|
|
|
|
## Programmatic re-scan
|
|
|
|
If your SPA does client-side navigation without full page reloads, call:
|
|
|
|
```js
|
|
window.IHFAnnotationLauncher.scan();
|
|
```
|
|
|
|
## Submission
|
|
|
|
The launcher POSTs `application/x-www-form-urlencoded` to:
|
|
|
|
```
|
|
POST /widgets/:widgetId/annotations
|
|
```
|
|
|
|
Fields submitted: `body`, `category`, `severity` (fixed `low`), CSRF token.
|
|
|
|
Responses:
|
|
- `200` or redirect → success (form closes with confirmation)
|
|
- Any non-OK response → inline error message
|
|
|
|
## CSRF
|
|
|
|
The launcher reads the CSRF token from `<meta name="csrf-token" content="...">`.
|
|
IHP emits this tag automatically in authenticated layouts.
|