generated from coulomb/repo-seed
feat(P6/T05): cross-framework annotation launcher JS widget
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>
This commit is contained in:
79
docs/annotation-launcher.md
Normal file
79
docs/annotation-launcher.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user