History

feat: plugin API routes + frontend component registration

OpenAPI plugin now has three sub-path exports: - @executor/plugin-openapi (SDK plugin, unchanged) - @executor/plugin-openapi/api (HTTP routes + handlers) - OpenApiGroup: previewSpec, addSpec, listSpecs, removeSpec endpoints - OpenApiHandlers: Effect HttpApiBuilder handlers - OpenApiExtensionService: Context tag for wiring - @executor/plugin-openapi/react (React components + atoms) - OpenApiClient: typed AtomHttpApi client (core + openapi routes) - Atoms: openApiSpecsAtom, previewOpenApiSpec, addOpenApiSpec, removeOpenApiSpec - openApiSourcePlugin: implements SourcePlugin contract - Lazy-loaded components: AddOpenApiSource (multi-step), EditOpenApiSource, OpenApiSourceSummary Shared infrastructure: - @executor/api: addGroup() composes plugin HttpApiGroups with CoreExecutorApi - @executor/react: SourcePlugin contract type for shell↔plugin UI composition Shell owns layout/nav/common actions, plugin owns content within typed frames Pattern: plugins use addGroup() + AtomHttpApi.Tag to get typed query/mutation atoms for both core and plugin-specific routes. Peer deps with optional metadata so SDK-only consumers don't pull in React. 10 packages typecheck clean, 21 OpenAPI tests passing.

Rhys Sullivan committed 7 months ago

Commit 1ddae2a1 parent f973e3218 files · +416 −6Browse files

Showing the changes to packages/plugins/openapi/src/react (7 of 18 files). Show all

Unified · Split

7 files
  1. packages/plugins/openapi/src/react/AddOpenApiSource.tsx +55 −0
  2. packages/plugins/openapi/src/react/EditOpenApiSource.tsx +13 −0
  3. packages/plugins/openapi/src/react/OpenApiSourceSummary.tsx +9 −0
  4. packages/plugins/openapi/src/react/atoms.ts +35 −0
  5. packages/plugins/openapi/src/react/client.ts +20 −0
  6. packages/plugins/openapi/src/react/index.ts +8 −0
  7. packages/plugins/openapi/src/react/source-plugin.ts +14 −0
packages/plugins/openapi/src/react/AddOpenApiSource.tsx+55−0
@@ -0,0 +1,55 @@
1import { useState } from "react";
2
3export default function AddOpenApiSource(props: {
4 onComplete: () => void;
5 onCancel: () => void;
6}) {
7 const [step, setStep] = useState<"url" | "auth" | "confirm">("url");
8 const [specUrl, setSpecUrl] = useState("");
9
10 return (
11 <div>
12 <h3>Add OpenAPI Source</h3>
13
14 {step === "url" && (
15 <div>
16 <label>
17 Spec URL or paste content:
18 <input
19 type="text"
20 value={specUrl}
21 onChange={(e) => setSpecUrl((e.target as HTMLInputElement).value)}
22 placeholder="https://api.example.com/openapi.json"
23 />
24 </label>
25 <div>
26 <button onClick={props.onCancel}>Cancel</button>
27 <button onClick={() => setStep("auth")} disabled={!specUrl}>
28 Next
29 </button>
30 </div>
31 </div>
32 )}
33
34 {step === "auth" && (
35 <div>
36 <p>Configure authentication headers…</p>
37 <div>
38 <button onClick={() => setStep("url")}>Back</button>
39 <button onClick={() => setStep("confirm")}>Next</button>
40 </div>
41 </div>
42 )}
43
44 {step === "confirm" && (
45 <div>
46 <p>Ready to add spec from: {specUrl}</p>
47 <div>
48 <button onClick={() => setStep("auth")}>Back</button>
49 <button onClick={props.onComplete}>Add Source</button>
50 </div>
51 </div>
52 )}
53 </div>
54 );
55}
packages/plugins/openapi/src/react/EditOpenApiSource.tsx+13−0
@@ -0,0 +1,13 @@
1export default function EditOpenApiSource(props: {
2 sourceId: string;
3 onSave: () => void;
4}) {
5 return (
6 <div>
7 <h3>Edit OpenAPI Source</h3>
8 <p>Source: {props.sourceId}</p>
9 {/* TODO: show spec info, auth config, operation list */}
10 <button onClick={props.onSave}>Save</button>
11 </div>
12 );
13}
packages/plugins/openapi/src/react/OpenApiSourceSummary.tsx+9−0
@@ -0,0 +1,9 @@
1export default function OpenApiSourceSummary(props: {
2 sourceId: string;
3}) {
4 return (
5 <span>
6 OpenAPI · {props.sourceId}
7 </span>
8 );
9}
packages/plugins/openapi/src/react/atoms.ts+35−0
@@ -0,0 +1,35 @@
1import { ScopeId } from "@executor/sdk";
2
3import { OpenApiClient } from "./client";
4
5// ---------------------------------------------------------------------------
6// Default scope
7// ---------------------------------------------------------------------------
8
9const DEFAULT_SCOPE = ScopeId.make("default");
10
11// ---------------------------------------------------------------------------
12// Query atoms
13// ---------------------------------------------------------------------------
14
15export const openApiSpecsAtom = (scopeId: ScopeId = DEFAULT_SCOPE) =>
16 OpenApiClient.query("openapi", "listSpecs", {
17 path: { scopeId },
18 timeToLive: "30 seconds",
19 });
20
21// ---------------------------------------------------------------------------
22// Mutation atoms
23// ---------------------------------------------------------------------------
24
25export const previewOpenApiSpec = OpenApiClient.mutation(
26 "openapi",
27 "previewSpec",
28);
29
30export const addOpenApiSpec = OpenApiClient.mutation("openapi", "addSpec");
31
32export const removeOpenApiSpec = OpenApiClient.mutation(
33 "openapi",
34 "removeSpec",
35);
packages/plugins/openapi/src/react/client.ts+20−0
@@ -0,0 +1,20 @@
1import { AtomHttpApi } from "@effect-atom/atom-react";
2import { FetchHttpClient } from "@effect/platform";
3import { addGroup } from "@executor/api";
4import { getBaseUrl } from "@executor/react";
5import { OpenApiGroup } from "../api/group";
6
7// ---------------------------------------------------------------------------
8// OpenAPI-aware client — core routes + openapi routes
9// ---------------------------------------------------------------------------
10
11const OpenApiApi = addGroup(OpenApiGroup);
12
13export const OpenApiClient = AtomHttpApi.Tag<"OpenApiClient">()(
14 "OpenApiClient",
15 {
16 api: OpenApiApi,
17 httpClient: FetchHttpClient.layer,
18 baseUrl: getBaseUrl(),
19 },
20);
packages/plugins/openapi/src/react/index.ts+8−0
@@ -0,0 +1,8 @@
1export { openApiSourcePlugin } from "./source-plugin";
2export { OpenApiClient } from "./client";
3export {
4 openApiSpecsAtom,
5 previewOpenApiSpec,
6 addOpenApiSpec,
7 removeOpenApiSpec,
8} from "./atoms";
packages/plugins/openapi/src/react/source-plugin.ts+14−0
@@ -0,0 +1,14 @@
1import { lazy } from "react";
2import type { SourcePlugin } from "@executor/react";
3
4// ---------------------------------------------------------------------------
5// OpenAPI source plugin — lazy-loaded components
6// ---------------------------------------------------------------------------
7
8export const openApiSourcePlugin: SourcePlugin = {
9 key: "openapi",
10 label: "OpenAPI",
11 add: lazy(() => import("./AddOpenApiSource")),
12 edit: lazy(() => import("./EditOpenApiSource")),
13 summary: lazy(() => import("./OpenApiSourceSummary")),
14};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t