@evermore.work/plugin-sdk 2026.509.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1215 -0
- package/dist/bundlers.d.ts +57 -0
- package/dist/bundlers.d.ts.map +1 -0
- package/dist/bundlers.js +106 -0
- package/dist/bundlers.js.map +1 -0
- package/dist/define-plugin.d.ts +266 -0
- package/dist/define-plugin.d.ts.map +1 -0
- package/dist/define-plugin.js +85 -0
- package/dist/define-plugin.js.map +1 -0
- package/dist/dev-cli.d.ts +3 -0
- package/dist/dev-cli.d.ts.map +1 -0
- package/dist/dev-cli.js +49 -0
- package/dist/dev-cli.js.map +1 -0
- package/dist/dev-server.d.ts +34 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/dev-server.js +194 -0
- package/dist/dev-server.js.map +1 -0
- package/dist/host-client-factory.d.ts +272 -0
- package/dist/host-client-factory.d.ts.map +1 -0
- package/dist/host-client-factory.js +481 -0
- package/dist/host-client-factory.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +1285 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +306 -0
- package/dist/protocol.js.map +1 -0
- package/dist/testing.d.ts +166 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1766 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +1330 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/components.d.ts +511 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +135 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/hooks.d.ts +155 -0
- package/dist/ui/hooks.d.ts.map +1 -0
- package/dist/ui/hooks.js +195 -0
- package/dist/ui/hooks.js.map +1 -0
- package/dist/ui/index.d.ts +54 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +51 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/runtime.d.ts +3 -0
- package/dist/ui/runtime.d.ts.map +1 -0
- package/dist/ui/runtime.js +30 -0
- package/dist/ui/runtime.js.map +1 -0
- package/dist/ui/types.d.ts +388 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +17 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/worker-rpc-host.d.ts +127 -0
- package/dist/worker-rpc-host.d.ts.map +1 -0
- package/dist/worker-rpc-host.js +1279 -0
- package/dist/worker-rpc-host.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared UI component declarations for plugin frontends.
|
|
3
|
+
*
|
|
4
|
+
* These components are exported from `@evermore.work/plugin-sdk/ui` and are
|
|
5
|
+
* provided by the host at runtime. They match the host's design tokens and
|
|
6
|
+
* visual language, reducing the boilerplate needed to build consistent plugin UIs.
|
|
7
|
+
*
|
|
8
|
+
* **Plugins are not required to use these components.** They exist to reduce
|
|
9
|
+
* boilerplate and keep visual consistency. A plugin may render entirely custom
|
|
10
|
+
* UI using any React component library.
|
|
11
|
+
*
|
|
12
|
+
* Component implementations are provided by the host — plugin bundles contain
|
|
13
|
+
* only the type declarations; the runtime implementations are injected via the
|
|
14
|
+
* host module registry.
|
|
15
|
+
*
|
|
16
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components In `@evermore.work/plugin-sdk/ui`
|
|
17
|
+
*/
|
|
18
|
+
import { renderSdkUiComponent } from "./runtime.js";
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Component declarations (provided by host at runtime)
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// These are declared as ambient values so plugin TypeScript code can import
|
|
23
|
+
// and use them with full type-checking. The host's module registry provides
|
|
24
|
+
// the concrete React component implementations at bundle load time.
|
|
25
|
+
/**
|
|
26
|
+
* Displays a single metric with an optional trend indicator and sparkline.
|
|
27
|
+
*
|
|
28
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
29
|
+
*/
|
|
30
|
+
function createSdkUiComponent(name) {
|
|
31
|
+
return function EvermoreSdkUiComponent(props) {
|
|
32
|
+
return renderSdkUiComponent(name, props);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export const MetricCard = createSdkUiComponent("MetricCard");
|
|
36
|
+
/**
|
|
37
|
+
* Displays an inline status badge (ok / warning / error / info / pending).
|
|
38
|
+
*
|
|
39
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
40
|
+
*/
|
|
41
|
+
export const StatusBadge = createSdkUiComponent("StatusBadge");
|
|
42
|
+
/**
|
|
43
|
+
* Sortable, paginated data table.
|
|
44
|
+
*
|
|
45
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
46
|
+
*/
|
|
47
|
+
export const DataTable = createSdkUiComponent("DataTable");
|
|
48
|
+
/**
|
|
49
|
+
* Line or bar chart for time-series data.
|
|
50
|
+
*
|
|
51
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
52
|
+
*/
|
|
53
|
+
export const TimeseriesChart = createSdkUiComponent("TimeseriesChart");
|
|
54
|
+
/**
|
|
55
|
+
* Renders Markdown text as HTML.
|
|
56
|
+
*
|
|
57
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
58
|
+
*/
|
|
59
|
+
export const MarkdownBlock = createSdkUiComponent("MarkdownBlock");
|
|
60
|
+
/**
|
|
61
|
+
* Renders Evermore's shared Markdown editor.
|
|
62
|
+
*
|
|
63
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
64
|
+
*/
|
|
65
|
+
export const MarkdownEditor = createSdkUiComponent("MarkdownEditor");
|
|
66
|
+
/**
|
|
67
|
+
* Renders a definition-list of label/value pairs.
|
|
68
|
+
*
|
|
69
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
70
|
+
*/
|
|
71
|
+
export const KeyValueList = createSdkUiComponent("KeyValueList");
|
|
72
|
+
/**
|
|
73
|
+
* Row of action buttons wired to the plugin bridge's `performAction` handlers.
|
|
74
|
+
*
|
|
75
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
76
|
+
*/
|
|
77
|
+
export const ActionBar = createSdkUiComponent("ActionBar");
|
|
78
|
+
/**
|
|
79
|
+
* Scrollable, timestamped log output viewer.
|
|
80
|
+
*
|
|
81
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
82
|
+
*/
|
|
83
|
+
export const LogView = createSdkUiComponent("LogView");
|
|
84
|
+
/**
|
|
85
|
+
* Collapsible JSON tree for debugging or raw data inspection.
|
|
86
|
+
*
|
|
87
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
88
|
+
*/
|
|
89
|
+
export const JsonTree = createSdkUiComponent("JsonTree");
|
|
90
|
+
/**
|
|
91
|
+
* Loading indicator.
|
|
92
|
+
*
|
|
93
|
+
* @see PLUGIN_SPEC.md §19.6 — Shared Components
|
|
94
|
+
*/
|
|
95
|
+
export const Spinner = createSdkUiComponent("Spinner");
|
|
96
|
+
/**
|
|
97
|
+
* React error boundary that prevents plugin rendering errors from crashing
|
|
98
|
+
* the host page.
|
|
99
|
+
*
|
|
100
|
+
* @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
|
|
101
|
+
*/
|
|
102
|
+
export const ErrorBoundary = createSdkUiComponent("ErrorBoundary");
|
|
103
|
+
/**
|
|
104
|
+
* Renders the host file tree component with a stable plugin-safe prop surface.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* import { FileTree, type FileTreeNode } from "@evermore.work/plugin-sdk/ui";
|
|
109
|
+
*
|
|
110
|
+
* const nodes: FileTreeNode[] = [
|
|
111
|
+
* { name: "README.md", path: "README.md", kind: "file", children: [] },
|
|
112
|
+
* ];
|
|
113
|
+
*
|
|
114
|
+
* <FileTree nodes={nodes} onSelectFile={(path) => console.log(path)} />;
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export const FileTree = createSdkUiComponent("FileTree");
|
|
118
|
+
/**
|
|
119
|
+
* Renders Evermore's native issue list component for company-scoped plugin
|
|
120
|
+
* pages that need a standard board issue view.
|
|
121
|
+
*/
|
|
122
|
+
export const IssuesList = createSdkUiComponent("IssuesList");
|
|
123
|
+
/**
|
|
124
|
+
* Renders the same host assignee picker used by the new issue pane.
|
|
125
|
+
*/
|
|
126
|
+
export const AssigneePicker = createSdkUiComponent("AssigneePicker");
|
|
127
|
+
/**
|
|
128
|
+
* Renders the same host project picker used by the new issue pane.
|
|
129
|
+
*/
|
|
130
|
+
export const ProjectPicker = createSdkUiComponent("ProjectPicker");
|
|
131
|
+
/**
|
|
132
|
+
* Renders Evermore's native managed routines list for plugin settings pages.
|
|
133
|
+
*/
|
|
134
|
+
export const ManagedRoutinesList = createSdkUiComponent("ManagedRoutinesList");
|
|
135
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/ui/components.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAmbpD,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,4EAA4E;AAC5E,4EAA4E;AAC5E,oEAAoE;AAEpE;;;;GAIG;AACH,SAAS,oBAAoB,CAAS,IAAY;IAChD,OAAO,SAAS,sBAAsB,CAAC,KAAa;QAClD,OAAO,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAoB,CAAC;IAC9D,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,oBAAoB,CAAkB,YAAY,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAmB,aAAa,CAAC,CAAC;AAEjF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,oBAAoB,CAAiB,WAAW,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,CAAuB,iBAAiB,CAAC,CAAC;AAE7F;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAqB,eAAe,CAAC,CAAC;AAEvF;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAsB,gBAAgB,CAAC,CAAC;AAE1F;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAoB,cAAc,CAAC,CAAC;AAEpF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,oBAAoB,CAAiB,WAAW,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAe,SAAS,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAgB,UAAU,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAe,SAAS,CAAC,CAAC;AAErE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAqB,eAAe,CAAC,CAAC;AAEvF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAgB,UAAU,CAAC,CAAC;AAExE;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,oBAAoB,CAAkB,YAAY,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAsB,gBAAgB,CAAC,CAAC;AAE1F;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAqB,eAAe,CAAC,CAAC;AAEvF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAAoB,CAA2B,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { PluginDataResult, PluginActionFn, HostLocation, HostNavigation, PluginHostContext, PluginStreamResult, PluginToastFn } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fetch data from the plugin worker's registered `getData` handler.
|
|
4
|
+
*
|
|
5
|
+
* Calls `ctx.data.register(key, handler)` in the worker and returns the
|
|
6
|
+
* result as reactive state. Re-fetches when `params` changes.
|
|
7
|
+
*
|
|
8
|
+
* @template T The expected shape of the returned data
|
|
9
|
+
* @param key - The data key matching the handler registered with `ctx.data.register()`
|
|
10
|
+
* @param params - Optional parameters forwarded to the handler
|
|
11
|
+
* @returns `PluginDataResult<T>` with `data`, `loading`, `error`, and `refresh`
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* function SyncWidget({ context }: PluginWidgetProps) {
|
|
16
|
+
* const { data, loading, error } = usePluginData<SyncHealth>("sync-health", {
|
|
17
|
+
* companyId: context.companyId,
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* if (loading) return <div>Loading…</div>;
|
|
21
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
22
|
+
* return <div>Synced Issues: {data!.syncedCount}</div>;
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @see PLUGIN_SPEC.md §13.8 — `getData`
|
|
27
|
+
* @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
|
|
28
|
+
*/
|
|
29
|
+
export declare function usePluginData<T = unknown>(key: string, params?: Record<string, unknown>): PluginDataResult<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Get a callable function that invokes the plugin worker's registered
|
|
32
|
+
* `performAction` handler.
|
|
33
|
+
*
|
|
34
|
+
* The returned function is async and throws a `PluginBridgeError` on failure.
|
|
35
|
+
*
|
|
36
|
+
* @param key - The action key matching the handler registered with `ctx.actions.register()`
|
|
37
|
+
* @returns An async function that sends the action to the worker and resolves with the result
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* function ResyncButton({ context }: PluginWidgetProps) {
|
|
42
|
+
* const resync = usePluginAction("resync");
|
|
43
|
+
* const [error, setError] = useState<string | null>(null);
|
|
44
|
+
*
|
|
45
|
+
* async function handleClick() {
|
|
46
|
+
* try {
|
|
47
|
+
* await resync({ companyId: context.companyId });
|
|
48
|
+
* } catch (err) {
|
|
49
|
+
* setError((err as PluginBridgeError).message);
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* return <button onClick={handleClick}>Resync Now</button>;
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see PLUGIN_SPEC.md §13.9 — `performAction`
|
|
58
|
+
* @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
|
|
59
|
+
*/
|
|
60
|
+
export declare function usePluginAction(key: string): PluginActionFn;
|
|
61
|
+
/**
|
|
62
|
+
* Read the current host context (active company, project, entity, user).
|
|
63
|
+
*
|
|
64
|
+
* Use this to know which context the plugin component is being rendered in
|
|
65
|
+
* so you can scope data requests and actions accordingly.
|
|
66
|
+
*
|
|
67
|
+
* @returns The current `PluginHostContext`
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```tsx
|
|
71
|
+
* function IssueTab() {
|
|
72
|
+
* const { companyId, entityId } = useHostContext();
|
|
73
|
+
* const { data } = usePluginData("linear-link", { issueId: entityId });
|
|
74
|
+
* return <div>{data?.linearIssueUrl}</div>;
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @see PLUGIN_SPEC.md §19 — UI Extension Model
|
|
79
|
+
*/
|
|
80
|
+
export declare function useHostContext(): PluginHostContext;
|
|
81
|
+
/**
|
|
82
|
+
* Navigate within the Evermore host without forcing a full document reload.
|
|
83
|
+
*
|
|
84
|
+
* Use `linkProps()` for links so browser-native behavior still works:
|
|
85
|
+
* modifier-click, middle-click, copy-link, and open-in-new-tab all use the
|
|
86
|
+
* returned real `href`.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* function WikiSidebarLink() {
|
|
91
|
+
* const hostNavigation = useHostNavigation();
|
|
92
|
+
* return <a {...hostNavigation.linkProps("/wiki")}>Wiki</a>;
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function useHostNavigation(): HostNavigation;
|
|
97
|
+
/**
|
|
98
|
+
* Observe the current host router location.
|
|
99
|
+
*
|
|
100
|
+
* Returns a snapshot of the active `pathname`, `search`, and `hash`. The
|
|
101
|
+
* component re-renders when any of these change (e.g. after the host router
|
|
102
|
+
* pushes a new entry, or after the browser back/forward gestures). Use this
|
|
103
|
+
* for URL-driven plugin UI such as a takeover sidebar with section-aware
|
|
104
|
+
* active state.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* function WikiSection() {
|
|
109
|
+
* const { pathname } = useHostLocation();
|
|
110
|
+
* const section = pathname.split("/").filter(Boolean).at(-1) ?? "wiki";
|
|
111
|
+
* return <div>Active section: {section}</div>;
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function useHostLocation(): HostLocation;
|
|
116
|
+
/**
|
|
117
|
+
* Subscribe to a real-time event stream pushed from the plugin worker.
|
|
118
|
+
*
|
|
119
|
+
* Opens an SSE connection to `GET /api/plugins/:pluginId/bridge/stream/:channel`
|
|
120
|
+
* and accumulates events as they arrive. The worker pushes events using
|
|
121
|
+
* `ctx.streams.emit(channel, event)`.
|
|
122
|
+
*
|
|
123
|
+
* @template T The expected shape of each streamed event
|
|
124
|
+
* @param channel - The stream channel name (must match what the worker uses in `ctx.streams.emit`)
|
|
125
|
+
* @param options - Optional configuration for the stream
|
|
126
|
+
* @returns `PluginStreamResult<T>` with `events`, `lastEvent`, connection status, and `close()`
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```tsx
|
|
130
|
+
* function ChatMessages() {
|
|
131
|
+
* const { events, connected, close } = usePluginStream<ChatToken>("chat-stream");
|
|
132
|
+
*
|
|
133
|
+
* return (
|
|
134
|
+
* <div>
|
|
135
|
+
* {events.map((e, i) => <span key={i}>{e.text}</span>)}
|
|
136
|
+
* {connected && <span className="pulse" />}
|
|
137
|
+
* <button onClick={close}>Stop</button>
|
|
138
|
+
* </div>
|
|
139
|
+
* );
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @see PLUGIN_SPEC.md §19.8 — Real-Time Streaming
|
|
144
|
+
*/
|
|
145
|
+
export declare function usePluginStream<T = unknown>(channel: string, options?: {
|
|
146
|
+
companyId?: string;
|
|
147
|
+
}): PluginStreamResult<T>;
|
|
148
|
+
/**
|
|
149
|
+
* Trigger a host toast notification from plugin UI.
|
|
150
|
+
*
|
|
151
|
+
* This lets plugin pages and widgets surface user-facing feedback through the
|
|
152
|
+
* same toast system as the host app without reaching into host internals.
|
|
153
|
+
*/
|
|
154
|
+
export declare function usePluginToast(): PluginToastFn;
|
|
155
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/ui/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACd,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EACvC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,gBAAgB,CAAC,CAAC,CAAC,CAKrB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAG3D;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAGlD;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAGlD;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAG9C;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,CAAC,CAAC,GAAG,OAAO,EACzC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B,kBAAkB,CAAC,CAAC,CAAC,CAKvB;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAG9C"}
|
package/dist/ui/hooks.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { getSdkUiRuntimeValue } from "./runtime.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// usePluginData
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Fetch data from the plugin worker's registered `getData` handler.
|
|
7
|
+
*
|
|
8
|
+
* Calls `ctx.data.register(key, handler)` in the worker and returns the
|
|
9
|
+
* result as reactive state. Re-fetches when `params` changes.
|
|
10
|
+
*
|
|
11
|
+
* @template T The expected shape of the returned data
|
|
12
|
+
* @param key - The data key matching the handler registered with `ctx.data.register()`
|
|
13
|
+
* @param params - Optional parameters forwarded to the handler
|
|
14
|
+
* @returns `PluginDataResult<T>` with `data`, `loading`, `error`, and `refresh`
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* function SyncWidget({ context }: PluginWidgetProps) {
|
|
19
|
+
* const { data, loading, error } = usePluginData<SyncHealth>("sync-health", {
|
|
20
|
+
* companyId: context.companyId,
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* if (loading) return <div>Loading…</div>;
|
|
24
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
25
|
+
* return <div>Synced Issues: {data!.syncedCount}</div>;
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @see PLUGIN_SPEC.md §13.8 — `getData`
|
|
30
|
+
* @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
|
|
31
|
+
*/
|
|
32
|
+
export function usePluginData(key, params) {
|
|
33
|
+
const impl = getSdkUiRuntimeValue("usePluginData");
|
|
34
|
+
return impl(key, params);
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// usePluginAction
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Get a callable function that invokes the plugin worker's registered
|
|
41
|
+
* `performAction` handler.
|
|
42
|
+
*
|
|
43
|
+
* The returned function is async and throws a `PluginBridgeError` on failure.
|
|
44
|
+
*
|
|
45
|
+
* @param key - The action key matching the handler registered with `ctx.actions.register()`
|
|
46
|
+
* @returns An async function that sends the action to the worker and resolves with the result
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* function ResyncButton({ context }: PluginWidgetProps) {
|
|
51
|
+
* const resync = usePluginAction("resync");
|
|
52
|
+
* const [error, setError] = useState<string | null>(null);
|
|
53
|
+
*
|
|
54
|
+
* async function handleClick() {
|
|
55
|
+
* try {
|
|
56
|
+
* await resync({ companyId: context.companyId });
|
|
57
|
+
* } catch (err) {
|
|
58
|
+
* setError((err as PluginBridgeError).message);
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* return <button onClick={handleClick}>Resync Now</button>;
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @see PLUGIN_SPEC.md §13.9 — `performAction`
|
|
67
|
+
* @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
|
|
68
|
+
*/
|
|
69
|
+
export function usePluginAction(key) {
|
|
70
|
+
const impl = getSdkUiRuntimeValue("usePluginAction");
|
|
71
|
+
return impl(key);
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// useHostContext
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
/**
|
|
77
|
+
* Read the current host context (active company, project, entity, user).
|
|
78
|
+
*
|
|
79
|
+
* Use this to know which context the plugin component is being rendered in
|
|
80
|
+
* so you can scope data requests and actions accordingly.
|
|
81
|
+
*
|
|
82
|
+
* @returns The current `PluginHostContext`
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* function IssueTab() {
|
|
87
|
+
* const { companyId, entityId } = useHostContext();
|
|
88
|
+
* const { data } = usePluginData("linear-link", { issueId: entityId });
|
|
89
|
+
* return <div>{data?.linearIssueUrl}</div>;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see PLUGIN_SPEC.md §19 — UI Extension Model
|
|
94
|
+
*/
|
|
95
|
+
export function useHostContext() {
|
|
96
|
+
const impl = getSdkUiRuntimeValue("useHostContext");
|
|
97
|
+
return impl();
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// useHostNavigation
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Navigate within the Evermore host without forcing a full document reload.
|
|
104
|
+
*
|
|
105
|
+
* Use `linkProps()` for links so browser-native behavior still works:
|
|
106
|
+
* modifier-click, middle-click, copy-link, and open-in-new-tab all use the
|
|
107
|
+
* returned real `href`.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```tsx
|
|
111
|
+
* function WikiSidebarLink() {
|
|
112
|
+
* const hostNavigation = useHostNavigation();
|
|
113
|
+
* return <a {...hostNavigation.linkProps("/wiki")}>Wiki</a>;
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function useHostNavigation() {
|
|
118
|
+
const impl = getSdkUiRuntimeValue("useHostNavigation");
|
|
119
|
+
return impl();
|
|
120
|
+
}
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// useHostLocation
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
/**
|
|
125
|
+
* Observe the current host router location.
|
|
126
|
+
*
|
|
127
|
+
* Returns a snapshot of the active `pathname`, `search`, and `hash`. The
|
|
128
|
+
* component re-renders when any of these change (e.g. after the host router
|
|
129
|
+
* pushes a new entry, or after the browser back/forward gestures). Use this
|
|
130
|
+
* for URL-driven plugin UI such as a takeover sidebar with section-aware
|
|
131
|
+
* active state.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* function WikiSection() {
|
|
136
|
+
* const { pathname } = useHostLocation();
|
|
137
|
+
* const section = pathname.split("/").filter(Boolean).at(-1) ?? "wiki";
|
|
138
|
+
* return <div>Active section: {section}</div>;
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function useHostLocation() {
|
|
143
|
+
const impl = getSdkUiRuntimeValue("useHostLocation");
|
|
144
|
+
return impl();
|
|
145
|
+
}
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// usePluginStream
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
/**
|
|
150
|
+
* Subscribe to a real-time event stream pushed from the plugin worker.
|
|
151
|
+
*
|
|
152
|
+
* Opens an SSE connection to `GET /api/plugins/:pluginId/bridge/stream/:channel`
|
|
153
|
+
* and accumulates events as they arrive. The worker pushes events using
|
|
154
|
+
* `ctx.streams.emit(channel, event)`.
|
|
155
|
+
*
|
|
156
|
+
* @template T The expected shape of each streamed event
|
|
157
|
+
* @param channel - The stream channel name (must match what the worker uses in `ctx.streams.emit`)
|
|
158
|
+
* @param options - Optional configuration for the stream
|
|
159
|
+
* @returns `PluginStreamResult<T>` with `events`, `lastEvent`, connection status, and `close()`
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```tsx
|
|
163
|
+
* function ChatMessages() {
|
|
164
|
+
* const { events, connected, close } = usePluginStream<ChatToken>("chat-stream");
|
|
165
|
+
*
|
|
166
|
+
* return (
|
|
167
|
+
* <div>
|
|
168
|
+
* {events.map((e, i) => <span key={i}>{e.text}</span>)}
|
|
169
|
+
* {connected && <span className="pulse" />}
|
|
170
|
+
* <button onClick={close}>Stop</button>
|
|
171
|
+
* </div>
|
|
172
|
+
* );
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*
|
|
176
|
+
* @see PLUGIN_SPEC.md §19.8 — Real-Time Streaming
|
|
177
|
+
*/
|
|
178
|
+
export function usePluginStream(channel, options) {
|
|
179
|
+
const impl = getSdkUiRuntimeValue("usePluginStream");
|
|
180
|
+
return impl(channel, options);
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// usePluginToast
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Trigger a host toast notification from plugin UI.
|
|
187
|
+
*
|
|
188
|
+
* This lets plugin pages and widgets surface user-facing feedback through the
|
|
189
|
+
* same toast system as the host app without reaching into host internals.
|
|
190
|
+
*/
|
|
191
|
+
export function usePluginToast() {
|
|
192
|
+
const impl = getSdkUiRuntimeValue("usePluginToast");
|
|
193
|
+
return impl();
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/ui/hooks.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,MAAgC;IAEhC,MAAM,IAAI,GAAG,oBAAoB,CAE/B,eAAe,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,IAAI,GAAG,oBAAoB,CAAsC,iBAAiB,CAAC,CAAC;IAC1F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,oBAAoB,CAA0B,gBAAgB,CAAC,CAAC;IAC7E,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,oBAAoB,CAAuB,mBAAmB,CAAC,CAAC;IAC7E,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,oBAAoB,CAAqB,iBAAiB,CAAC,CAAC;IACzE,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAAgC;IAEhC,MAAM,IAAI,GAAG,oBAAoB,CAE/B,iBAAiB,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,oBAAoB,CAAsB,gBAAgB,CAAC,CAAC;IACzE,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@evermore.work/plugin-sdk/ui` — Evermore plugin UI SDK.
|
|
3
|
+
*
|
|
4
|
+
* Import this subpath from plugin UI bundles (React components that run in
|
|
5
|
+
* the host frontend). Do **not** import this from plugin worker code.
|
|
6
|
+
*
|
|
7
|
+
* The worker-side SDK is available from `@evermore.work/plugin-sdk` (root).
|
|
8
|
+
*
|
|
9
|
+
* @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
|
|
10
|
+
* @see PLUGIN_SPEC.md §29.2 — SDK Versioning
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // Plugin UI bundle entry (dist/ui/index.tsx)
|
|
15
|
+
* import { usePluginData, usePluginAction } from "@evermore.work/plugin-sdk/ui";
|
|
16
|
+
* import type { PluginWidgetProps } from "@evermore.work/plugin-sdk/ui";
|
|
17
|
+
*
|
|
18
|
+
* export function DashboardWidget({ context }: PluginWidgetProps) {
|
|
19
|
+
* const { data, loading, error } = usePluginData("sync-health", {
|
|
20
|
+
* companyId: context.companyId,
|
|
21
|
+
* });
|
|
22
|
+
* const resync = usePluginAction("resync");
|
|
23
|
+
*
|
|
24
|
+
* if (loading) return <div>Loading…</div>;
|
|
25
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <div style={{ display: "grid", gap: 8 }}>
|
|
29
|
+
* <strong>Synced Issues</strong>
|
|
30
|
+
* <div>{data!.syncedCount}</div>
|
|
31
|
+
* <button onClick={() => resync({ companyId: context.companyId })}>
|
|
32
|
+
* Resync Now
|
|
33
|
+
* </button>
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Bridge hooks for plugin UI components to communicate with the plugin worker.
|
|
41
|
+
*
|
|
42
|
+
* - `usePluginData(key, params)` — fetch data from the worker's `getData` handler
|
|
43
|
+
* - `usePluginAction(key)` — get a callable that invokes the worker's `performAction` handler
|
|
44
|
+
* - `useHostContext()` — read the current active company, project, entity, and user IDs
|
|
45
|
+
* - `useHostNavigation()` — navigate Evermore-internal links through the host router
|
|
46
|
+
* - `useHostLocation()` — observe the current host pathname/search/hash for URL-driven UI
|
|
47
|
+
* - `usePluginStream(channel)` — subscribe to real-time SSE events from the worker
|
|
48
|
+
*/
|
|
49
|
+
export { usePluginData, usePluginAction, useHostContext, useHostNavigation, useHostLocation, usePluginStream, usePluginToast, } from "./hooks.js";
|
|
50
|
+
export { MetricCard, StatusBadge, DataTable, TimeseriesChart, MarkdownBlock, MarkdownEditor, KeyValueList, ActionBar, LogView, JsonTree, Spinner, ErrorBoundary, FileTree, IssuesList, AssigneePicker, ProjectPicker, ManagedRoutinesList, } from "./components.js";
|
|
51
|
+
export type { MetricTrend, MetricCardProps, StatusBadgeVariant, StatusBadgeProps, DataTableColumn, DataTableProps, TimeseriesDataPoint, TimeseriesChartProps, MarkdownBlockProps, MarkdownEditorProps, KeyValuePair, KeyValueListProps, ActionBarItem, ActionBarProps, LogViewEntry, LogViewProps, JsonTreeProps, SpinnerProps, ErrorBoundaryProps, FileTreeNode, FileTreeBadgeVariant, FileTreeBadge, FileTreeTone, FileTreeEmptyState, FileTreeErrorState, FileTreePathCollection, FileTreeProps, IssuesListFilters, IssuesListProps, AssigneePickerSelection, AssigneePickerProps, ProjectPickerProps, ManagedRoutineMissingRef, ManagedRoutinesListAgent, ManagedRoutinesListItem, ManagedRoutinesListProject, ManagedRoutinesListProps, } from "./components.js";
|
|
52
|
+
export type { PluginBridgeError, PluginBridgeErrorCode, HostNavigation, HostNavigationOptions, HostNavigationLinkOptions, HostNavigationLinkProps, HostLocation, PluginHostContext, PluginModalBoundsRequest, PluginRenderCloseEvent, PluginRenderCloseHandler, PluginRenderCloseLifecycle, PluginRenderEnvironmentContext, PluginLauncherBounds, PluginLauncherRenderEnvironment, PluginDataResult, PluginActionFn, PluginStreamResult, PluginToastTone, PluginToastAction, PluginToastInput, PluginToastFn, } from "./types.js";
|
|
53
|
+
export type { PluginPageProps, PluginWidgetProps, PluginDetailTabProps, PluginSidebarProps, PluginRouteSidebarProps, PluginProjectSidebarItemProps, PluginCommentAnnotationProps, PluginCommentContextMenuItemProps, PluginSettingsPageProps, } from "./types.js";
|
|
54
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;;;GASG;AACH,OAAO,EACL,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,YAAY,EACZ,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACb,QAAQ,EACR,UAAU,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,8BAA8B,EAC9B,oBAAoB,EACpB,+BAA+B,EAC/B,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,6BAA6B,EAC7B,4BAA4B,EAC5B,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@evermore.work/plugin-sdk/ui` — Evermore plugin UI SDK.
|
|
3
|
+
*
|
|
4
|
+
* Import this subpath from plugin UI bundles (React components that run in
|
|
5
|
+
* the host frontend). Do **not** import this from plugin worker code.
|
|
6
|
+
*
|
|
7
|
+
* The worker-side SDK is available from `@evermore.work/plugin-sdk` (root).
|
|
8
|
+
*
|
|
9
|
+
* @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
|
|
10
|
+
* @see PLUGIN_SPEC.md §29.2 — SDK Versioning
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // Plugin UI bundle entry (dist/ui/index.tsx)
|
|
15
|
+
* import { usePluginData, usePluginAction } from "@evermore.work/plugin-sdk/ui";
|
|
16
|
+
* import type { PluginWidgetProps } from "@evermore.work/plugin-sdk/ui";
|
|
17
|
+
*
|
|
18
|
+
* export function DashboardWidget({ context }: PluginWidgetProps) {
|
|
19
|
+
* const { data, loading, error } = usePluginData("sync-health", {
|
|
20
|
+
* companyId: context.companyId,
|
|
21
|
+
* });
|
|
22
|
+
* const resync = usePluginAction("resync");
|
|
23
|
+
*
|
|
24
|
+
* if (loading) return <div>Loading…</div>;
|
|
25
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <div style={{ display: "grid", gap: 8 }}>
|
|
29
|
+
* <strong>Synced Issues</strong>
|
|
30
|
+
* <div>{data!.syncedCount}</div>
|
|
31
|
+
* <button onClick={() => resync({ companyId: context.companyId })}>
|
|
32
|
+
* Resync Now
|
|
33
|
+
* </button>
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Bridge hooks for plugin UI components to communicate with the plugin worker.
|
|
41
|
+
*
|
|
42
|
+
* - `usePluginData(key, params)` — fetch data from the worker's `getData` handler
|
|
43
|
+
* - `usePluginAction(key)` — get a callable that invokes the worker's `performAction` handler
|
|
44
|
+
* - `useHostContext()` — read the current active company, project, entity, and user IDs
|
|
45
|
+
* - `useHostNavigation()` — navigate Evermore-internal links through the host router
|
|
46
|
+
* - `useHostLocation()` — observe the current host pathname/search/hash for URL-driven UI
|
|
47
|
+
* - `usePluginStream(channel)` — subscribe to real-time SSE events from the worker
|
|
48
|
+
*/
|
|
49
|
+
export { usePluginData, usePluginAction, useHostContext, useHostNavigation, useHostLocation, usePluginStream, usePluginToast, } from "./hooks.js";
|
|
50
|
+
export { MetricCard, StatusBadge, DataTable, TimeseriesChart, MarkdownBlock, MarkdownEditor, KeyValueList, ActionBar, LogView, JsonTree, Spinner, ErrorBoundary, FileTree, IssuesList, AssigneePicker, ProjectPicker, ManagedRoutinesList, } from "./components.js";
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;;;GASG;AACH,OAAO,EACL,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,cAAc,EACd,YAAY,EACZ,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACb,QAAQ,EACR,UAAU,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,GACpB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/ui/runtime.ts"],"names":[],"mappings":"AAsBA,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAMvD;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAiBT"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function getBridgeRegistry() {
|
|
2
|
+
return globalThis.__evermorePluginBridge__;
|
|
3
|
+
}
|
|
4
|
+
function missingBridgeValueError(name) {
|
|
5
|
+
return new Error(`Evermore plugin UI runtime is not initialized for "${name}". ` +
|
|
6
|
+
'Ensure the host loaded the plugin bridge before rendering this UI module.');
|
|
7
|
+
}
|
|
8
|
+
export function getSdkUiRuntimeValue(name) {
|
|
9
|
+
const value = getBridgeRegistry()?.sdkUi?.[name];
|
|
10
|
+
if (value === undefined) {
|
|
11
|
+
throw missingBridgeValueError(name);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
export function renderSdkUiComponent(name, props) {
|
|
16
|
+
const registry = getBridgeRegistry();
|
|
17
|
+
const component = registry?.sdkUi?.[name];
|
|
18
|
+
if (component === undefined) {
|
|
19
|
+
throw missingBridgeValueError(name);
|
|
20
|
+
}
|
|
21
|
+
const createElement = registry?.react?.createElement;
|
|
22
|
+
if (typeof createElement === "function") {
|
|
23
|
+
return createElement(component, props);
|
|
24
|
+
}
|
|
25
|
+
if (typeof component === "function") {
|
|
26
|
+
return component(props);
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`Evermore plugin UI component "${name}" is not callable`);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/ui/runtime.ts"],"names":[],"mappings":"AAWA,SAAS,iBAAiB;IACxB,OAAQ,UAA2B,CAAC,wBAAwB,CAAC;AAC/D,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY;IAC3C,OAAO,IAAI,KAAK,CACd,sDAAsD,IAAI,KAAK;QAC7D,2EAA2E,CAC9E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAI,IAAY;IAClD,MAAM,KAAK,GAAG,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,KAAa;IAEb,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAC;IACrD,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE,CAAC;QACxC,OAAO,aAAa,CAAC,SAAS,EAAE,KAAgC,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,mBAAmB,CAAC,CAAC;AAC5E,CAAC"}
|