@executor-js/plugin-graphql 0.1.0 → 0.2.1
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/dist/AddGraphqlSource-LGXJQEAR.js +239 -0
- package/dist/AddGraphqlSource-LGXJQEAR.js.map +1 -0
- package/dist/EditGraphqlSource-5Y47ZAZ7.js +251 -0
- package/dist/EditGraphqlSource-5Y47ZAZ7.js.map +1 -0
- package/dist/GraphqlSourceSummary-F3JWR4YN.js +70 -0
- package/dist/GraphqlSourceSummary-F3JWR4YN.js.map +1 -0
- package/dist/api/group.d.ts +169 -13
- package/dist/api/handlers.d.ts +15 -3
- package/dist/api/index.d.ts +410 -0
- package/dist/chunk-7QSGNR4C.js +162 -0
- package/dist/chunk-7QSGNR4C.js.map +1 -0
- package/dist/chunk-HDPYOBBG.js +1633 -0
- package/dist/chunk-HDPYOBBG.js.map +1 -0
- package/dist/chunk-M4SJY6CB.js +45 -0
- package/dist/chunk-M4SJY6CB.js.map +1 -0
- package/dist/chunk-WPRU5C6M.js +182 -0
- package/dist/chunk-WPRU5C6M.js.map +1 -0
- package/dist/client.js +75 -0
- package/dist/client.js.map +1 -0
- package/dist/core.js +32 -10
- package/dist/index.js +2 -1
- package/dist/react/GraphqlSourceFields.d.ts +8 -0
- package/dist/react/GraphqlSourceSummary.d.ts +3 -1
- package/dist/react/atoms.d.ts +170 -10
- package/dist/react/client.d.ts +164 -12
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/introspect.d.ts +437 -43
- package/dist/sdk/invoke.d.ts +3 -2
- package/dist/sdk/plugin.d.ts +120 -170
- package/dist/sdk/store.d.ts +84 -11
- package/dist/sdk/types.d.ts +107 -3
- package/dist/testing/index.d.ts +52 -0
- package/dist/testing.js +131 -0
- package/dist/testing.js.map +1 -0
- package/package.json +18 -4
- package/dist/chunk-EIC5WI6C.js +0 -1225
- package/dist/chunk-EIC5WI6C.js.map +0 -1
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GraphqlSourceFields
|
|
3
|
+
} from "./chunk-M4SJY6CB.js";
|
|
4
|
+
import {
|
|
5
|
+
addGraphqlSourceOptimistic
|
|
6
|
+
} from "./chunk-WPRU5C6M.js";
|
|
7
|
+
import "./chunk-7QSGNR4C.js";
|
|
8
|
+
|
|
9
|
+
// src/react/AddGraphqlSource.tsx
|
|
10
|
+
import { useCallback, useState } from "react";
|
|
11
|
+
import { useAtomSet } from "@effect/atom-react";
|
|
12
|
+
import * as Exit from "effect/Exit";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import { useScope } from "@executor-js/react/api/scope-context";
|
|
16
|
+
import { sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
|
|
17
|
+
import {
|
|
18
|
+
HttpCredentialsEditor,
|
|
19
|
+
httpCredentialsValid,
|
|
20
|
+
serializeScopedHttpCredentials,
|
|
21
|
+
serializeHttpCredentials
|
|
22
|
+
} from "@executor-js/react/plugins/http-credentials";
|
|
23
|
+
import {
|
|
24
|
+
sourceDisplayNameFromUrl,
|
|
25
|
+
slugifyNamespace,
|
|
26
|
+
useSourceIdentity
|
|
27
|
+
} from "@executor-js/react/plugins/source-identity";
|
|
28
|
+
import {
|
|
29
|
+
oauthCallbackUrl,
|
|
30
|
+
oauthConnectionId,
|
|
31
|
+
useOAuthPopupFlow
|
|
32
|
+
} from "@executor-js/react/plugins/oauth-sign-in";
|
|
33
|
+
import {
|
|
34
|
+
CredentialControlField,
|
|
35
|
+
CredentialUsageRow,
|
|
36
|
+
useCredentialTargetScope
|
|
37
|
+
} from "@executor-js/react/plugins/credential-target-scope";
|
|
38
|
+
import { useSecretPickerSecrets } from "@executor-js/react/plugins/use-secret-picker-secrets";
|
|
39
|
+
import { Button } from "@executor-js/react/components/button";
|
|
40
|
+
import { FilterTabs } from "@executor-js/react/components/filter-tabs";
|
|
41
|
+
import { FloatActions } from "@executor-js/react/components/float-actions";
|
|
42
|
+
import { Spinner } from "@executor-js/react/components/spinner";
|
|
43
|
+
|
|
44
|
+
// src/react/defaults.ts
|
|
45
|
+
import {
|
|
46
|
+
emptyHttpCredentials
|
|
47
|
+
} from "@executor-js/react/plugins/http-credentials";
|
|
48
|
+
var initialGraphqlCredentials = () => emptyHttpCredentials();
|
|
49
|
+
|
|
50
|
+
// src/react/AddGraphqlSource.tsx
|
|
51
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
52
|
+
var ErrorMessage = Schema.Struct({ message: Schema.String });
|
|
53
|
+
var decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage);
|
|
54
|
+
var errorMessageFromExit = (exit, fallback) => Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), {
|
|
55
|
+
onNone: () => fallback,
|
|
56
|
+
onSome: ({ message }) => message
|
|
57
|
+
});
|
|
58
|
+
function AddGraphqlSource(props) {
|
|
59
|
+
const [endpoint, setEndpoint] = useState(props.initialUrl ?? "");
|
|
60
|
+
const identity = useSourceIdentity({
|
|
61
|
+
fallbackName: sourceDisplayNameFromUrl(endpoint, "GraphQL") ?? ""
|
|
62
|
+
});
|
|
63
|
+
const [credentials, setCredentials] = useState(initialGraphqlCredentials);
|
|
64
|
+
const [adding, setAdding] = useState(false);
|
|
65
|
+
const [addError, setAddError] = useState(null);
|
|
66
|
+
const [authMode, setAuthMode] = useState("none");
|
|
67
|
+
const [tokens, setTokens] = useState(null);
|
|
68
|
+
const scopeId = useScope();
|
|
69
|
+
const { credentialTargetScope: requestCredentialTargetScope } = useCredentialTargetScope();
|
|
70
|
+
const {
|
|
71
|
+
credentialTargetScope: oauthCredentialTargetScope,
|
|
72
|
+
setCredentialTargetScope: setOAuthCredentialTargetScope,
|
|
73
|
+
credentialScopeOptions
|
|
74
|
+
} = useCredentialTargetScope();
|
|
75
|
+
const doAdd = useAtomSet(addGraphqlSourceOptimistic(scopeId), {
|
|
76
|
+
mode: "promiseExit"
|
|
77
|
+
});
|
|
78
|
+
const secretList = useSecretPickerSecrets();
|
|
79
|
+
const oauth = useOAuthPopupFlow({
|
|
80
|
+
popupName: "graphql-oauth",
|
|
81
|
+
startErrorMessage: "Failed to start OAuth"
|
|
82
|
+
});
|
|
83
|
+
const canAdd = endpoint.trim().length > 0 && httpCredentialsValid(credentials) && (authMode === "none" || tokens !== null) && !oauth.busy;
|
|
84
|
+
const sourceIdentity = useCallback(() => {
|
|
85
|
+
const trimmedEndpoint = endpoint.trim();
|
|
86
|
+
const namespace = slugifyNamespace(identity.namespace) || slugifyNamespace(sourceDisplayNameFromUrl(trimmedEndpoint, "GraphQL") ?? "") || "graphql";
|
|
87
|
+
const displayName = identity.name.trim() || sourceDisplayNameFromUrl(trimmedEndpoint, "GraphQL") || namespace;
|
|
88
|
+
return { trimmedEndpoint, namespace, displayName };
|
|
89
|
+
}, [endpoint, identity.name, identity.namespace]);
|
|
90
|
+
const handleOAuth = useCallback(async () => {
|
|
91
|
+
if (!endpoint.trim() || !httpCredentialsValid(credentials)) return;
|
|
92
|
+
setAddError(null);
|
|
93
|
+
const { trimmedEndpoint, namespace, displayName } = sourceIdentity();
|
|
94
|
+
const { headers, queryParams } = serializeHttpCredentials(credentials);
|
|
95
|
+
await oauth.start({
|
|
96
|
+
payload: {
|
|
97
|
+
endpoint: trimmedEndpoint,
|
|
98
|
+
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
99
|
+
...Object.keys(queryParams).length > 0 ? { queryParams } : {},
|
|
100
|
+
redirectUrl: oauthCallbackUrl(),
|
|
101
|
+
connectionId: oauthConnectionId({ pluginId: "graphql", namespace }),
|
|
102
|
+
tokenScope: oauthCredentialTargetScope,
|
|
103
|
+
strategy: { kind: "dynamic-dcr" },
|
|
104
|
+
pluginId: "graphql",
|
|
105
|
+
identityLabel: `${displayName} OAuth`
|
|
106
|
+
},
|
|
107
|
+
onSuccess: (result) => {
|
|
108
|
+
setTokens({
|
|
109
|
+
connectionId: result.connectionId,
|
|
110
|
+
expiresAt: result.expiresAt,
|
|
111
|
+
scope: result.scope
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
onError: setAddError
|
|
115
|
+
});
|
|
116
|
+
}, [endpoint, credentials, oauth, sourceIdentity, oauthCredentialTargetScope]);
|
|
117
|
+
const handleAdd = async () => {
|
|
118
|
+
setAdding(true);
|
|
119
|
+
setAddError(null);
|
|
120
|
+
const { headers: headerMap, queryParams } = serializeScopedHttpCredentials(
|
|
121
|
+
credentials,
|
|
122
|
+
requestCredentialTargetScope
|
|
123
|
+
);
|
|
124
|
+
const { trimmedEndpoint, namespace, displayName } = sourceIdentity();
|
|
125
|
+
const exit = await doAdd({
|
|
126
|
+
params: { scopeId },
|
|
127
|
+
payload: {
|
|
128
|
+
targetScope: scopeId,
|
|
129
|
+
endpoint: trimmedEndpoint,
|
|
130
|
+
name: displayName,
|
|
131
|
+
namespace,
|
|
132
|
+
...Object.keys(headerMap).length > 0 ? { headers: headerMap } : {},
|
|
133
|
+
...Object.keys(queryParams).length > 0 ? {
|
|
134
|
+
queryParams
|
|
135
|
+
} : {},
|
|
136
|
+
credentialTargetScope: authMode === "oauth2" && tokens ? oauthCredentialTargetScope : requestCredentialTargetScope,
|
|
137
|
+
...authMode === "oauth2" && tokens ? {
|
|
138
|
+
auth: {
|
|
139
|
+
kind: "oauth2",
|
|
140
|
+
connectionId: tokens.connectionId
|
|
141
|
+
}
|
|
142
|
+
} : {}
|
|
143
|
+
},
|
|
144
|
+
reactivityKeys: sourceWriteKeys
|
|
145
|
+
});
|
|
146
|
+
if (Exit.isFailure(exit)) {
|
|
147
|
+
setAddError(errorMessageFromExit(exit, "Failed to add source"));
|
|
148
|
+
setAdding(false);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
props.onComplete();
|
|
152
|
+
};
|
|
153
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-6", children: [
|
|
154
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Add GraphQL Source" }),
|
|
155
|
+
/* @__PURE__ */ jsx(GraphqlSourceFields, { endpoint, onEndpointChange: setEndpoint, identity }),
|
|
156
|
+
/* @__PURE__ */ jsx(
|
|
157
|
+
HttpCredentialsEditor,
|
|
158
|
+
{
|
|
159
|
+
credentials,
|
|
160
|
+
onChange: setCredentials,
|
|
161
|
+
existingSecrets: secretList,
|
|
162
|
+
sourceName: identity.name,
|
|
163
|
+
targetScope: requestCredentialTargetScope,
|
|
164
|
+
credentialScopeOptions,
|
|
165
|
+
bindingScopeOptions: credentialScopeOptions
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
/* @__PURE__ */ jsxs("section", { className: "hidden space-y-2.5", children: [
|
|
169
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
170
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: "Authentication" }),
|
|
171
|
+
/* @__PURE__ */ jsx(
|
|
172
|
+
FilterTabs,
|
|
173
|
+
{
|
|
174
|
+
tabs: [
|
|
175
|
+
{ value: "none", label: "None" },
|
|
176
|
+
{ value: "oauth2", label: "OAuth" }
|
|
177
|
+
],
|
|
178
|
+
value: authMode,
|
|
179
|
+
onChange: (value) => {
|
|
180
|
+
setAuthMode(value);
|
|
181
|
+
setTokens(null);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
] }),
|
|
186
|
+
authMode === "oauth2" && /* @__PURE__ */ jsx(
|
|
187
|
+
CredentialUsageRow,
|
|
188
|
+
{
|
|
189
|
+
value: oauthCredentialTargetScope,
|
|
190
|
+
options: credentialScopeOptions,
|
|
191
|
+
onChange: (targetScope) => {
|
|
192
|
+
setOAuthCredentialTargetScope(targetScope);
|
|
193
|
+
setTokens(null);
|
|
194
|
+
},
|
|
195
|
+
label: "Connection saved to",
|
|
196
|
+
help: "Choose who can use the OAuth connection.",
|
|
197
|
+
children: /* @__PURE__ */ jsx(CredentialControlField, { label: "Connect via OAuth", help: "Start the provider OAuth flow.", children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-9 items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2", children: [
|
|
198
|
+
tokens ? /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-emerald-600 dark:text-emerald-400", children: "Authenticated" }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Not connected" }),
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
Button,
|
|
201
|
+
{
|
|
202
|
+
type: "button",
|
|
203
|
+
variant: "outline",
|
|
204
|
+
size: "sm",
|
|
205
|
+
className: "ml-auto h-7 px-2 text-xs",
|
|
206
|
+
onClick: () => void handleOAuth(),
|
|
207
|
+
disabled: !endpoint.trim() || !httpCredentialsValid(credentials) || oauth.busy,
|
|
208
|
+
children: oauth.busy ? "Signing in..." : tokens ? "Reconnect" : "Sign in"
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
] }) })
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
] }),
|
|
215
|
+
addError && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-[12px] text-destructive", children: addError }) }),
|
|
216
|
+
/* @__PURE__ */ jsxs(FloatActions, { children: [
|
|
217
|
+
/* @__PURE__ */ jsx(
|
|
218
|
+
Button,
|
|
219
|
+
{
|
|
220
|
+
variant: "ghost",
|
|
221
|
+
onClick: () => {
|
|
222
|
+
oauth.cancel();
|
|
223
|
+
props.onCancel();
|
|
224
|
+
},
|
|
225
|
+
disabled: adding,
|
|
226
|
+
children: "Cancel"
|
|
227
|
+
}
|
|
228
|
+
),
|
|
229
|
+
/* @__PURE__ */ jsxs(Button, { onClick: handleAdd, disabled: !canAdd || adding, children: [
|
|
230
|
+
adding && /* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }),
|
|
231
|
+
adding ? "Adding..." : "Add source"
|
|
232
|
+
] })
|
|
233
|
+
] })
|
|
234
|
+
] });
|
|
235
|
+
}
|
|
236
|
+
export {
|
|
237
|
+
AddGraphqlSource as default
|
|
238
|
+
};
|
|
239
|
+
//# sourceMappingURL=AddGraphqlSource-LGXJQEAR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/AddGraphqlSource.tsx","../src/react/defaults.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\nimport { useAtomSet } from \"@effect/atom-react\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\n\nimport { useScope } from \"@executor-js/react/api/scope-context\";\nimport { sourceWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport {\n HttpCredentialsEditor,\n httpCredentialsValid,\n serializeScopedHttpCredentials,\n serializeHttpCredentials,\n type HttpCredentialsState,\n} from \"@executor-js/react/plugins/http-credentials\";\nimport {\n sourceDisplayNameFromUrl,\n slugifyNamespace,\n useSourceIdentity,\n} from \"@executor-js/react/plugins/source-identity\";\nimport {\n oauthCallbackUrl,\n oauthConnectionId,\n useOAuthPopupFlow,\n type OAuthCompletionPayload,\n} from \"@executor-js/react/plugins/oauth-sign-in\";\nimport {\n CredentialControlField,\n CredentialUsageRow,\n useCredentialTargetScope,\n} from \"@executor-js/react/plugins/credential-target-scope\";\nimport { useSecretPickerSecrets } from \"@executor-js/react/plugins/use-secret-picker-secrets\";\nimport { Button } from \"@executor-js/react/components/button\";\nimport { FilterTabs } from \"@executor-js/react/components/filter-tabs\";\nimport { FloatActions } from \"@executor-js/react/components/float-actions\";\nimport { Spinner } from \"@executor-js/react/components/spinner\";\nimport { addGraphqlSourceOptimistic } from \"./atoms\";\nimport { initialGraphqlCredentials } from \"./defaults\";\nimport { GraphqlSourceFields } from \"./GraphqlSourceFields\";\nimport type { GraphqlCredentialInput } from \"../sdk/types\";\n\nconst ErrorMessage = Schema.Struct({ message: Schema.String });\nconst decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage);\n\nconst errorMessageFromExit = (exit: Exit.Exit<unknown, unknown>, fallback: string): string =>\n Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), {\n onNone: () => fallback,\n onSome: ({ message }) => message,\n });\n\ntype AuthMode = \"none\" | \"oauth2\";\n\nexport default function AddGraphqlSource(props: {\n onComplete: () => void;\n onCancel: () => void;\n initialUrl?: string;\n}) {\n const [endpoint, setEndpoint] = useState(props.initialUrl ?? \"\");\n const identity = useSourceIdentity({\n fallbackName: sourceDisplayNameFromUrl(endpoint, \"GraphQL\") ?? \"\",\n });\n const [credentials, setCredentials] = useState<HttpCredentialsState>(initialGraphqlCredentials);\n const [adding, setAdding] = useState(false);\n const [addError, setAddError] = useState<string | null>(null);\n const [authMode, setAuthMode] = useState<AuthMode>(\"none\");\n const [tokens, setTokens] = useState<OAuthCompletionPayload | null>(null);\n\n const scopeId = useScope();\n const { credentialTargetScope: requestCredentialTargetScope } = useCredentialTargetScope();\n const {\n credentialTargetScope: oauthCredentialTargetScope,\n setCredentialTargetScope: setOAuthCredentialTargetScope,\n credentialScopeOptions,\n } = useCredentialTargetScope();\n const doAdd = useAtomSet(addGraphqlSourceOptimistic(scopeId), {\n mode: \"promiseExit\",\n });\n const secretList = useSecretPickerSecrets();\n const oauth = useOAuthPopupFlow({\n popupName: \"graphql-oauth\",\n startErrorMessage: \"Failed to start OAuth\",\n });\n\n const canAdd =\n endpoint.trim().length > 0 &&\n httpCredentialsValid(credentials) &&\n (authMode === \"none\" || tokens !== null) &&\n !oauth.busy;\n\n const sourceIdentity = useCallback(() => {\n const trimmedEndpoint = endpoint.trim();\n const namespace =\n slugifyNamespace(identity.namespace) ||\n slugifyNamespace(sourceDisplayNameFromUrl(trimmedEndpoint, \"GraphQL\") ?? \"\") ||\n \"graphql\";\n const displayName =\n identity.name.trim() || sourceDisplayNameFromUrl(trimmedEndpoint, \"GraphQL\") || namespace;\n return { trimmedEndpoint, namespace, displayName };\n }, [endpoint, identity.name, identity.namespace]);\n\n const handleOAuth = useCallback(async () => {\n if (!endpoint.trim() || !httpCredentialsValid(credentials)) return;\n setAddError(null);\n const { trimmedEndpoint, namespace, displayName } = sourceIdentity();\n const { headers, queryParams } = serializeHttpCredentials(credentials);\n await oauth.start({\n payload: {\n endpoint: trimmedEndpoint,\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n ...(Object.keys(queryParams).length > 0 ? { queryParams } : {}),\n redirectUrl: oauthCallbackUrl(),\n connectionId: oauthConnectionId({ pluginId: \"graphql\", namespace }),\n tokenScope: oauthCredentialTargetScope,\n strategy: { kind: \"dynamic-dcr\" },\n pluginId: \"graphql\",\n identityLabel: `${displayName} OAuth`,\n },\n onSuccess: (result) => {\n setTokens({\n connectionId: result.connectionId,\n expiresAt: result.expiresAt,\n scope: result.scope,\n });\n },\n onError: setAddError,\n });\n }, [endpoint, credentials, oauth, sourceIdentity, oauthCredentialTargetScope]);\n\n const handleAdd = async () => {\n setAdding(true);\n setAddError(null);\n const { headers: headerMap, queryParams } = serializeScopedHttpCredentials(\n credentials,\n requestCredentialTargetScope,\n );\n\n const { trimmedEndpoint, namespace, displayName } = sourceIdentity();\n const exit = await doAdd({\n params: { scopeId },\n payload: {\n targetScope: scopeId,\n endpoint: trimmedEndpoint,\n name: displayName,\n namespace,\n ...(Object.keys(headerMap).length > 0 ? { headers: headerMap } : {}),\n ...(Object.keys(queryParams).length > 0\n ? {\n queryParams: queryParams as Record<string, GraphqlCredentialInput>,\n }\n : {}),\n credentialTargetScope:\n authMode === \"oauth2\" && tokens\n ? oauthCredentialTargetScope\n : requestCredentialTargetScope,\n ...(authMode === \"oauth2\" && tokens\n ? {\n auth: {\n kind: \"oauth2\" as const,\n connectionId: tokens.connectionId,\n },\n }\n : {}),\n },\n reactivityKeys: sourceWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setAddError(errorMessageFromExit(exit, \"Failed to add source\"));\n setAdding(false);\n return;\n }\n props.onComplete();\n };\n\n return (\n <div className=\"flex flex-1 flex-col gap-6\">\n <h1 className=\"text-xl font-semibold text-foreground\">Add GraphQL Source</h1>\n\n <GraphqlSourceFields endpoint={endpoint} onEndpointChange={setEndpoint} identity={identity} />\n\n <HttpCredentialsEditor\n credentials={credentials}\n onChange={setCredentials}\n existingSecrets={secretList}\n sourceName={identity.name}\n targetScope={requestCredentialTargetScope}\n credentialScopeOptions={credentialScopeOptions}\n bindingScopeOptions={credentialScopeOptions}\n />\n\n {/* Temporarily hidden while we revisit GraphQL OAuth discovery and UX. */}\n <section className=\"hidden space-y-2.5\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-sm font-medium text-foreground\">Authentication</span>\n <FilterTabs<AuthMode>\n tabs={[\n { value: \"none\", label: \"None\" },\n { value: \"oauth2\", label: \"OAuth\" },\n ]}\n value={authMode}\n onChange={(value) => {\n setAuthMode(value);\n setTokens(null);\n }}\n />\n </div>\n\n {authMode === \"oauth2\" && (\n <CredentialUsageRow\n value={oauthCredentialTargetScope}\n options={credentialScopeOptions}\n onChange={(targetScope) => {\n setOAuthCredentialTargetScope(targetScope);\n setTokens(null);\n }}\n label=\"Connection saved to\"\n help=\"Choose who can use the OAuth connection.\"\n >\n <CredentialControlField label=\"Connect via OAuth\" help=\"Start the provider OAuth flow.\">\n <div className=\"flex min-h-9 items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2\">\n {tokens ? (\n <span className=\"text-xs font-medium text-emerald-600 dark:text-emerald-400\">\n Authenticated\n </span>\n ) : (\n <span className=\"text-xs text-muted-foreground\">Not connected</span>\n )}\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"ml-auto h-7 px-2 text-xs\"\n onClick={() => void handleOAuth()}\n disabled={!endpoint.trim() || !httpCredentialsValid(credentials) || oauth.busy}\n >\n {oauth.busy ? \"Signing in...\" : tokens ? \"Reconnect\" : \"Sign in\"}\n </Button>\n </div>\n </CredentialControlField>\n </CredentialUsageRow>\n )}\n </section>\n\n {/* Error */}\n {addError && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2\">\n <p className=\"text-[12px] text-destructive\">{addError}</p>\n </div>\n )}\n\n <FloatActions>\n <Button\n variant=\"ghost\"\n onClick={() => {\n oauth.cancel();\n props.onCancel();\n }}\n disabled={adding}\n >\n Cancel\n </Button>\n <Button onClick={handleAdd} disabled={!canAdd || adding}>\n {adding && <Spinner className=\"size-3.5\" />}\n {adding ? \"Adding...\" : \"Add source\"}\n </Button>\n </FloatActions>\n </div>\n );\n}\n","import {\n emptyHttpCredentials,\n type HttpCredentialsState,\n} from \"@executor-js/react/plugins/http-credentials\";\n\nexport const initialGraphqlCredentials = (): HttpCredentialsState => emptyHttpCredentials();\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GraphqlSourceFields
|
|
3
|
+
} from "./chunk-M4SJY6CB.js";
|
|
4
|
+
import {
|
|
5
|
+
graphqlSourceAtom,
|
|
6
|
+
graphqlSourceBindingsAtom,
|
|
7
|
+
setGraphqlSourceBinding,
|
|
8
|
+
updateGraphqlSource
|
|
9
|
+
} from "./chunk-WPRU5C6M.js";
|
|
10
|
+
import {
|
|
11
|
+
GRAPHQL_OAUTH_CONNECTION_SLOT,
|
|
12
|
+
GraphqlSourceBindingInput
|
|
13
|
+
} from "./chunk-7QSGNR4C.js";
|
|
14
|
+
|
|
15
|
+
// src/react/EditGraphqlSource.tsx
|
|
16
|
+
import { useState } from "react";
|
|
17
|
+
import { useAtomValue, useAtomSet } from "@effect/atom-react";
|
|
18
|
+
import * as Exit from "effect/Exit";
|
|
19
|
+
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
20
|
+
import { connectionsAtom } from "@executor-js/react/api/atoms";
|
|
21
|
+
import { useScope, useScopeStack } from "@executor-js/react/api/scope-context";
|
|
22
|
+
import { connectionWriteKeys, sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
|
|
23
|
+
import { useSecretPickerSecrets } from "@executor-js/react/plugins/use-secret-picker-secrets";
|
|
24
|
+
import {
|
|
25
|
+
HttpCredentialsEditor,
|
|
26
|
+
serializeHttpCredentials,
|
|
27
|
+
serializeScopedHttpCredentials
|
|
28
|
+
} from "@executor-js/react/plugins/http-credentials";
|
|
29
|
+
import {
|
|
30
|
+
effectiveCredentialBindingForScope,
|
|
31
|
+
httpCredentialsFromConfiguredCredentialBindings,
|
|
32
|
+
initialCredentialTargetScope
|
|
33
|
+
} from "@executor-js/react/plugins/credential-bindings";
|
|
34
|
+
import { slugifyNamespace, useSourceIdentity } from "@executor-js/react/plugins/source-identity";
|
|
35
|
+
import { useCredentialTargetScope } from "@executor-js/react/plugins/credential-target-scope";
|
|
36
|
+
import { Button } from "@executor-js/react/components/button";
|
|
37
|
+
import { FilterTabs } from "@executor-js/react/components/filter-tabs";
|
|
38
|
+
import { SourceOAuthConnectionControl } from "@executor-js/react/plugins/source-oauth-connection";
|
|
39
|
+
import { Badge } from "@executor-js/react/components/badge";
|
|
40
|
+
import { ScopeId } from "@executor-js/sdk/core";
|
|
41
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
42
|
+
function EditForm(props) {
|
|
43
|
+
const displayScope = useScope();
|
|
44
|
+
const scopeStack = useScopeStack();
|
|
45
|
+
const sourceScope = ScopeId.make(props.initial.scope);
|
|
46
|
+
const { credentialTargetScope, credentialScopeOptions } = useCredentialTargetScope({
|
|
47
|
+
sourceScope,
|
|
48
|
+
initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings)
|
|
49
|
+
});
|
|
50
|
+
const {
|
|
51
|
+
credentialTargetScope: oauthCredentialTargetScope,
|
|
52
|
+
setCredentialTargetScope: setOAuthCredentialTargetScope
|
|
53
|
+
} = useCredentialTargetScope({
|
|
54
|
+
sourceScope,
|
|
55
|
+
initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings)
|
|
56
|
+
});
|
|
57
|
+
const doUpdate = useAtomSet(updateGraphqlSource, { mode: "promiseExit" });
|
|
58
|
+
const setBinding = useAtomSet(setGraphqlSourceBinding, { mode: "promise" });
|
|
59
|
+
const secretList = useSecretPickerSecrets();
|
|
60
|
+
const connectionsResult = useAtomValue(connectionsAtom(displayScope));
|
|
61
|
+
const identity = useSourceIdentity({
|
|
62
|
+
fallbackName: props.initial.name,
|
|
63
|
+
fallbackNamespace: props.initial.namespace
|
|
64
|
+
});
|
|
65
|
+
const [endpoint, setEndpoint] = useState(props.initial.endpoint);
|
|
66
|
+
const [credentials, setCredentials] = useState(
|
|
67
|
+
() => httpCredentialsFromConfiguredCredentialBindings({
|
|
68
|
+
headers: props.initial.headers,
|
|
69
|
+
queryParams: props.initial.queryParams,
|
|
70
|
+
bindings: props.bindings
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
const [authMode, setAuthMode] = useState(props.initial.auth.kind);
|
|
74
|
+
const [saving, setSaving] = useState(false);
|
|
75
|
+
const [error, setError] = useState(null);
|
|
76
|
+
const [credentialsDirty, setCredentialsDirty] = useState(false);
|
|
77
|
+
const [authDirty, setAuthDirty] = useState(false);
|
|
78
|
+
const identityDirty = identity.name.trim() !== props.initial.name.trim();
|
|
79
|
+
const metadataDirty = identityDirty || endpoint.trim() !== props.initial.endpoint.trim();
|
|
80
|
+
const dirty = metadataDirty || credentialsDirty || authDirty;
|
|
81
|
+
const oauth2 = props.initial.auth.kind === "oauth2" ? props.initial.auth : null;
|
|
82
|
+
const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : [];
|
|
83
|
+
const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index]));
|
|
84
|
+
const connectionBinding = oauth2 ? effectiveCredentialBindingForScope(
|
|
85
|
+
props.bindings,
|
|
86
|
+
oauth2.connectionSlot,
|
|
87
|
+
oauthCredentialTargetScope,
|
|
88
|
+
scopeRanks
|
|
89
|
+
) : null;
|
|
90
|
+
const boundConnectionId = connectionBinding?.value.kind === "connection" ? connectionBinding.value.connectionId : null;
|
|
91
|
+
const isConnected = boundConnectionId !== null && connections.some((connection) => connection.id === boundConnectionId);
|
|
92
|
+
const oauthRequestCredentials = serializeHttpCredentials(credentials);
|
|
93
|
+
const handleCredentialsChange = (next) => {
|
|
94
|
+
setCredentials(next);
|
|
95
|
+
setCredentialsDirty(true);
|
|
96
|
+
};
|
|
97
|
+
const handleSave = async () => {
|
|
98
|
+
setSaving(true);
|
|
99
|
+
setError(null);
|
|
100
|
+
const { headers, queryParams } = serializeScopedHttpCredentials(
|
|
101
|
+
credentials,
|
|
102
|
+
credentialTargetScope
|
|
103
|
+
);
|
|
104
|
+
const payload = {
|
|
105
|
+
sourceScope,
|
|
106
|
+
name: metadataDirty ? identity.name.trim() || void 0 : void 0,
|
|
107
|
+
endpoint: metadataDirty ? endpoint.trim() || void 0 : void 0
|
|
108
|
+
};
|
|
109
|
+
if (credentialsDirty) {
|
|
110
|
+
payload.headers = headers;
|
|
111
|
+
payload.queryParams = queryParams;
|
|
112
|
+
payload.credentialTargetScope = credentialTargetScope;
|
|
113
|
+
}
|
|
114
|
+
if (authDirty) {
|
|
115
|
+
payload.auth = authMode === "oauth2" ? {
|
|
116
|
+
kind: "oauth2",
|
|
117
|
+
connectionSlot: props.initial.auth.kind === "oauth2" ? props.initial.auth.connectionSlot : GRAPHQL_OAUTH_CONNECTION_SLOT
|
|
118
|
+
} : { kind: "none" };
|
|
119
|
+
payload.credentialTargetScope = credentialTargetScope;
|
|
120
|
+
}
|
|
121
|
+
const exit = await doUpdate({
|
|
122
|
+
params: { scopeId: displayScope, namespace: props.sourceId },
|
|
123
|
+
payload,
|
|
124
|
+
reactivityKeys: sourceWriteKeys
|
|
125
|
+
});
|
|
126
|
+
if (Exit.isFailure(exit)) {
|
|
127
|
+
setError("Failed to update source");
|
|
128
|
+
setSaving(false);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
setCredentialsDirty(false);
|
|
132
|
+
setAuthDirty(false);
|
|
133
|
+
props.onSave();
|
|
134
|
+
setSaving(false);
|
|
135
|
+
};
|
|
136
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
137
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
138
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit GraphQL Source" }),
|
|
139
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Update the endpoint and authentication headers for this source." })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-card px-4 py-3", children: [
|
|
142
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-card-foreground", children: props.sourceId }) }),
|
|
143
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: "GraphQL" })
|
|
144
|
+
] }),
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
GraphqlSourceFields,
|
|
147
|
+
{
|
|
148
|
+
endpoint,
|
|
149
|
+
onEndpointChange: setEndpoint,
|
|
150
|
+
identity,
|
|
151
|
+
namespaceReadOnly: true
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
/* @__PURE__ */ jsx(
|
|
155
|
+
HttpCredentialsEditor,
|
|
156
|
+
{
|
|
157
|
+
credentials,
|
|
158
|
+
onChange: handleCredentialsChange,
|
|
159
|
+
existingSecrets: secretList,
|
|
160
|
+
sourceName: identity.name,
|
|
161
|
+
targetScope: credentialTargetScope,
|
|
162
|
+
credentialScopeOptions,
|
|
163
|
+
bindingScopeOptions: credentialScopeOptions
|
|
164
|
+
}
|
|
165
|
+
),
|
|
166
|
+
/* @__PURE__ */ jsxs("section", { className: "hidden space-y-2.5", children: [
|
|
167
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
168
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: "Authentication" }),
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
FilterTabs,
|
|
171
|
+
{
|
|
172
|
+
tabs: [
|
|
173
|
+
{ value: "none", label: "None" },
|
|
174
|
+
{ value: "oauth2", label: "OAuth" }
|
|
175
|
+
],
|
|
176
|
+
value: authMode,
|
|
177
|
+
onChange: (value) => {
|
|
178
|
+
setAuthMode(value);
|
|
179
|
+
setAuthDirty(true);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
] }),
|
|
184
|
+
authMode === "oauth2" && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "OAuth sign-in is available from the source header after saving." })
|
|
185
|
+
] }),
|
|
186
|
+
oauth2 && /* @__PURE__ */ jsx(
|
|
187
|
+
SourceOAuthConnectionControl,
|
|
188
|
+
{
|
|
189
|
+
popupName: "graphql-oauth",
|
|
190
|
+
pluginId: "graphql",
|
|
191
|
+
namespace: slugifyNamespace(props.initial.namespace) || "graphql",
|
|
192
|
+
fallbackNamespace: "graphql",
|
|
193
|
+
endpoint: endpoint.trim(),
|
|
194
|
+
tokenScope: oauthCredentialTargetScope,
|
|
195
|
+
onTokenScopeChange: setOAuthCredentialTargetScope,
|
|
196
|
+
credentialScopeOptions,
|
|
197
|
+
connectionId: boundConnectionId,
|
|
198
|
+
sourceLabel: `${identity.name.trim() || props.initial.namespace || "GraphQL"} OAuth`,
|
|
199
|
+
headers: oauthRequestCredentials.headers,
|
|
200
|
+
queryParams: oauthRequestCredentials.queryParams,
|
|
201
|
+
isConnected,
|
|
202
|
+
onConnected: async (connectionId) => {
|
|
203
|
+
await setBinding({
|
|
204
|
+
params: { scopeId: oauthCredentialTargetScope },
|
|
205
|
+
payload: new GraphqlSourceBindingInput({
|
|
206
|
+
sourceId: props.sourceId,
|
|
207
|
+
sourceScope,
|
|
208
|
+
scope: oauthCredentialTargetScope,
|
|
209
|
+
slot: oauth2.connectionSlot,
|
|
210
|
+
value: { kind: "connection", connectionId }
|
|
211
|
+
}),
|
|
212
|
+
reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys]
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
),
|
|
217
|
+
error && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }) }),
|
|
218
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t border-border pt-4", children: [
|
|
219
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: props.onSave, children: "Cancel" }),
|
|
220
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: !dirty || saving, children: saving ? "Saving\u2026" : "Save changes" })
|
|
221
|
+
] })
|
|
222
|
+
] });
|
|
223
|
+
}
|
|
224
|
+
function EditGraphqlSource(props) {
|
|
225
|
+
const scopeId = useScope();
|
|
226
|
+
const sourceResult = useAtomValue(graphqlSourceAtom(scopeId, props.sourceId));
|
|
227
|
+
const source = AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
|
|
228
|
+
const sourceScope = source ? ScopeId.make(source.scope) : scopeId;
|
|
229
|
+
const bindingsResult = useAtomValue(
|
|
230
|
+
graphqlSourceBindingsAtom(scopeId, props.sourceId, sourceScope)
|
|
231
|
+
);
|
|
232
|
+
if (!AsyncResult.isSuccess(sourceResult) || !source || !AsyncResult.isSuccess(bindingsResult)) {
|
|
233
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { children: [
|
|
234
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit GraphQL Source" }),
|
|
235
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Loading configuration\u2026" })
|
|
236
|
+
] }) });
|
|
237
|
+
}
|
|
238
|
+
return /* @__PURE__ */ jsx(
|
|
239
|
+
EditForm,
|
|
240
|
+
{
|
|
241
|
+
sourceId: props.sourceId,
|
|
242
|
+
initial: source,
|
|
243
|
+
bindings: bindingsResult.value,
|
|
244
|
+
onSave: props.onSave
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
export {
|
|
249
|
+
EditGraphqlSource as default
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=EditGraphqlSource-5Y47ZAZ7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/EditGraphqlSource.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useAtomValue, useAtomSet } from \"@effect/atom-react\";\nimport * as Exit from \"effect/Exit\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport {\n graphqlSourceAtom,\n graphqlSourceBindingsAtom,\n setGraphqlSourceBinding,\n updateGraphqlSource,\n} from \"./atoms\";\nimport { connectionsAtom } from \"@executor-js/react/api/atoms\";\nimport { useScope, useScopeStack } from \"@executor-js/react/api/scope-context\";\nimport { connectionWriteKeys, sourceWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport { useSecretPickerSecrets } from \"@executor-js/react/plugins/use-secret-picker-secrets\";\nimport {\n HttpCredentialsEditor,\n serializeHttpCredentials,\n serializeScopedHttpCredentials,\n type HttpCredentialsState,\n} from \"@executor-js/react/plugins/http-credentials\";\nimport {\n effectiveCredentialBindingForScope,\n httpCredentialsFromConfiguredCredentialBindings,\n initialCredentialTargetScope,\n} from \"@executor-js/react/plugins/credential-bindings\";\nimport { slugifyNamespace, useSourceIdentity } from \"@executor-js/react/plugins/source-identity\";\nimport { useCredentialTargetScope } from \"@executor-js/react/plugins/credential-target-scope\";\nimport { Button } from \"@executor-js/react/components/button\";\nimport { FilterTabs } from \"@executor-js/react/components/filter-tabs\";\nimport { SourceOAuthConnectionControl } from \"@executor-js/react/plugins/source-oauth-connection\";\nimport { Badge } from \"@executor-js/react/components/badge\";\nimport { ScopeId } from \"@executor-js/sdk/core\";\nimport { GraphqlSourceFields } from \"./GraphqlSourceFields\";\nimport {\n GRAPHQL_OAUTH_CONNECTION_SLOT,\n type GraphqlCredentialInput,\n GraphqlSourceBindingInput,\n type GraphqlSourceBindingRef,\n} from \"../sdk/types\";\nimport type { StoredGraphqlSource } from \"../sdk/store\";\n\ntype EditableSource = StoredGraphqlSource;\ntype AuthMode = \"none\" | \"oauth2\";\n\n// ---------------------------------------------------------------------------\n// Edit form\n// ---------------------------------------------------------------------------\n\nfunction EditForm(props: {\n sourceId: string;\n initial: EditableSource;\n bindings: readonly GraphqlSourceBindingRef[];\n onSave: () => void;\n}) {\n const displayScope = useScope();\n const scopeStack = useScopeStack();\n const sourceScope = ScopeId.make(props.initial.scope);\n const { credentialTargetScope, credentialScopeOptions } = useCredentialTargetScope({\n sourceScope,\n initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings),\n });\n const {\n credentialTargetScope: oauthCredentialTargetScope,\n setCredentialTargetScope: setOAuthCredentialTargetScope,\n } = useCredentialTargetScope({\n sourceScope,\n initialTargetScope: initialCredentialTargetScope(sourceScope, props.bindings),\n });\n const doUpdate = useAtomSet(updateGraphqlSource, { mode: \"promiseExit\" });\n const setBinding = useAtomSet(setGraphqlSourceBinding, { mode: \"promise\" });\n const secretList = useSecretPickerSecrets();\n const connectionsResult = useAtomValue(connectionsAtom(displayScope));\n\n const identity = useSourceIdentity({\n fallbackName: props.initial.name,\n fallbackNamespace: props.initial.namespace,\n });\n const [endpoint, setEndpoint] = useState(props.initial.endpoint);\n const [credentials, setCredentials] = useState<HttpCredentialsState>(() =>\n httpCredentialsFromConfiguredCredentialBindings({\n headers: props.initial.headers,\n queryParams: props.initial.queryParams,\n bindings: props.bindings,\n }),\n );\n const [authMode, setAuthMode] = useState<AuthMode>(props.initial.auth.kind);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [credentialsDirty, setCredentialsDirty] = useState(false);\n const [authDirty, setAuthDirty] = useState(false);\n\n const identityDirty = identity.name.trim() !== props.initial.name.trim();\n const metadataDirty = identityDirty || endpoint.trim() !== props.initial.endpoint.trim();\n const dirty = metadataDirty || credentialsDirty || authDirty;\n const oauth2 = props.initial.auth.kind === \"oauth2\" ? props.initial.auth : null;\n const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : [];\n const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const));\n const connectionBinding = oauth2\n ? effectiveCredentialBindingForScope(\n props.bindings,\n oauth2.connectionSlot,\n oauthCredentialTargetScope,\n scopeRanks,\n )\n : null;\n const boundConnectionId =\n connectionBinding?.value.kind === \"connection\" ? connectionBinding.value.connectionId : null;\n const isConnected =\n boundConnectionId !== null &&\n connections.some((connection) => connection.id === boundConnectionId);\n const oauthRequestCredentials = serializeHttpCredentials(credentials);\n\n const handleCredentialsChange = (next: HttpCredentialsState) => {\n setCredentials(next);\n setCredentialsDirty(true);\n };\n\n const handleSave = async () => {\n setSaving(true);\n setError(null);\n const { headers, queryParams } = serializeScopedHttpCredentials(\n credentials,\n credentialTargetScope,\n );\n const payload: {\n sourceScope: ScopeId;\n name?: string;\n endpoint?: string;\n headers?: Record<string, GraphqlCredentialInput>;\n queryParams?: Record<string, GraphqlCredentialInput>;\n credentialTargetScope?: ScopeId;\n auth?: { kind: \"none\" } | { kind: \"oauth2\"; connectionSlot: string };\n } = {\n sourceScope,\n name: metadataDirty ? identity.name.trim() || undefined : undefined,\n endpoint: metadataDirty ? endpoint.trim() || undefined : undefined,\n };\n if (credentialsDirty) {\n payload.headers = headers;\n payload.queryParams = queryParams as Record<string, GraphqlCredentialInput>;\n payload.credentialTargetScope = credentialTargetScope;\n }\n if (authDirty) {\n payload.auth =\n authMode === \"oauth2\"\n ? {\n kind: \"oauth2\",\n connectionSlot:\n props.initial.auth.kind === \"oauth2\"\n ? props.initial.auth.connectionSlot\n : GRAPHQL_OAUTH_CONNECTION_SLOT,\n }\n : { kind: \"none\" };\n payload.credentialTargetScope = credentialTargetScope;\n }\n const exit = await doUpdate({\n params: { scopeId: displayScope, namespace: props.sourceId },\n payload,\n reactivityKeys: sourceWriteKeys,\n });\n\n if (Exit.isFailure(exit)) {\n setError(\"Failed to update source\");\n setSaving(false);\n return;\n }\n\n setCredentialsDirty(false);\n setAuthDirty(false);\n props.onSave();\n setSaving(false);\n };\n\n return (\n <div className=\"space-y-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Edit GraphQL Source</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Update the endpoint and authentication headers for this source.\n </p>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-lg border border-border bg-card px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-card-foreground\">{props.sourceId}</p>\n </div>\n <Badge variant=\"secondary\" className=\"text-xs\">\n GraphQL\n </Badge>\n </div>\n\n <GraphqlSourceFields\n endpoint={endpoint}\n onEndpointChange={setEndpoint}\n identity={identity}\n namespaceReadOnly\n />\n\n <HttpCredentialsEditor\n credentials={credentials}\n onChange={handleCredentialsChange}\n existingSecrets={secretList}\n sourceName={identity.name}\n targetScope={credentialTargetScope}\n credentialScopeOptions={credentialScopeOptions}\n bindingScopeOptions={credentialScopeOptions}\n />\n\n {/* Temporarily hidden while we revisit GraphQL OAuth discovery and UX. */}\n <section className=\"hidden space-y-2.5\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-sm font-medium text-foreground\">Authentication</span>\n <FilterTabs<AuthMode>\n tabs={[\n { value: \"none\", label: \"None\" },\n { value: \"oauth2\", label: \"OAuth\" },\n ]}\n value={authMode}\n onChange={(value) => {\n setAuthMode(value);\n setAuthDirty(true);\n }}\n />\n </div>\n {authMode === \"oauth2\" && (\n <p className=\"text-xs text-muted-foreground\">\n OAuth sign-in is available from the source header after saving.\n </p>\n )}\n </section>\n\n {oauth2 && (\n <SourceOAuthConnectionControl\n popupName=\"graphql-oauth\"\n pluginId=\"graphql\"\n namespace={slugifyNamespace(props.initial.namespace) || \"graphql\"}\n fallbackNamespace=\"graphql\"\n endpoint={endpoint.trim()}\n tokenScope={oauthCredentialTargetScope}\n onTokenScopeChange={setOAuthCredentialTargetScope}\n credentialScopeOptions={credentialScopeOptions}\n connectionId={boundConnectionId}\n sourceLabel={`${identity.name.trim() || props.initial.namespace || \"GraphQL\"} OAuth`}\n headers={oauthRequestCredentials.headers}\n queryParams={oauthRequestCredentials.queryParams}\n isConnected={isConnected}\n onConnected={async (connectionId) => {\n await setBinding({\n params: { scopeId: oauthCredentialTargetScope },\n payload: new GraphqlSourceBindingInput({\n sourceId: props.sourceId,\n sourceScope,\n scope: oauthCredentialTargetScope,\n slot: oauth2.connectionSlot,\n value: { kind: \"connection\", connectionId },\n }),\n reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys],\n });\n }}\n />\n )}\n\n {error && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n )}\n\n <div className=\"flex items-center justify-between border-t border-border pt-4\">\n <Button variant=\"ghost\" onClick={props.onSave}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={!dirty || saving}>\n {saving ? \"Saving…\" : \"Save changes\"}\n </Button>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport default function EditGraphqlSource(props: { sourceId: string; onSave: () => void }) {\n const scopeId = useScope();\n const sourceResult = useAtomValue(graphqlSourceAtom(scopeId, props.sourceId));\n const source =\n AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;\n const sourceScope = source ? ScopeId.make(source.scope) : scopeId;\n const bindingsResult = useAtomValue(\n graphqlSourceBindingsAtom(scopeId, props.sourceId, sourceScope),\n );\n\n if (!AsyncResult.isSuccess(sourceResult) || !source || !AsyncResult.isSuccess(bindingsResult)) {\n return (\n <div className=\"space-y-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Edit GraphQL Source</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">Loading configuration…</p>\n </div>\n </div>\n );\n }\n\n return (\n <EditForm\n sourceId={props.sourceId}\n initial={source as EditableSource}\n bindings={bindingsResult.value}\n onSave={props.onSave}\n />\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
graphqlSourceAtom,
|
|
3
|
+
graphqlSourceBindingsAtom
|
|
4
|
+
} from "./chunk-WPRU5C6M.js";
|
|
5
|
+
import "./chunk-7QSGNR4C.js";
|
|
6
|
+
|
|
7
|
+
// src/react/GraphqlSourceSummary.tsx
|
|
8
|
+
import { useAtomValue } from "@effect/atom-react";
|
|
9
|
+
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
|
|
10
|
+
import { connectionsAtom } from "@executor-js/react/api/atoms";
|
|
11
|
+
import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context";
|
|
12
|
+
import {
|
|
13
|
+
SourceCredentialNotice,
|
|
14
|
+
SourceCredentialStatusBadge,
|
|
15
|
+
missingSourceCredentialLabels
|
|
16
|
+
} from "@executor-js/react/plugins/source-credential-status";
|
|
17
|
+
import { ScopeId } from "@executor-js/sdk/core";
|
|
18
|
+
import { jsx } from "react/jsx-runtime";
|
|
19
|
+
var sourceCredentialSlots = (source) => {
|
|
20
|
+
const slots = [];
|
|
21
|
+
for (const [name, value] of Object.entries(source.headers)) {
|
|
22
|
+
if (typeof value !== "string") slots.push({ kind: "secret", slot: value.slot, label: name });
|
|
23
|
+
}
|
|
24
|
+
for (const [name, value] of Object.entries(source.queryParams)) {
|
|
25
|
+
if (typeof value !== "string") slots.push({ kind: "secret", slot: value.slot, label: name });
|
|
26
|
+
}
|
|
27
|
+
if (source.auth.kind === "oauth2") {
|
|
28
|
+
slots.push({
|
|
29
|
+
kind: "connection",
|
|
30
|
+
slot: source.auth.connectionSlot,
|
|
31
|
+
label: "OAuth sign-in"
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return slots;
|
|
35
|
+
};
|
|
36
|
+
function GraphqlSourceSummary(props) {
|
|
37
|
+
const displayScope = useScope();
|
|
38
|
+
const userScope = useUserScope();
|
|
39
|
+
const scopeStack = useScopeStack();
|
|
40
|
+
const sourceResult = useAtomValue(graphqlSourceAtom(displayScope, props.sourceId));
|
|
41
|
+
const source = AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;
|
|
42
|
+
const sourceScope = source ? ScopeId.make(source.scope) : displayScope;
|
|
43
|
+
const bindingsResult = useAtomValue(
|
|
44
|
+
graphqlSourceBindingsAtom(displayScope, props.sourceId, sourceScope)
|
|
45
|
+
);
|
|
46
|
+
const connectionsResult = useAtomValue(connectionsAtom(displayScope));
|
|
47
|
+
if (!source) return null;
|
|
48
|
+
const slots = sourceCredentialSlots(source);
|
|
49
|
+
if (slots.length === 0) return null;
|
|
50
|
+
if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) {
|
|
51
|
+
return props.variant === "panel" ? null : /* @__PURE__ */ jsx(SourceCredentialStatusBadge, { missing: ["credentials"] });
|
|
52
|
+
}
|
|
53
|
+
const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index]));
|
|
54
|
+
const liveConnectionIds = new Set(connectionsResult.value.map((connection) => connection.id));
|
|
55
|
+
const missing = missingSourceCredentialLabels({
|
|
56
|
+
slots,
|
|
57
|
+
bindings: bindingsResult.value,
|
|
58
|
+
targetScope: userScope,
|
|
59
|
+
scopeRanks,
|
|
60
|
+
liveConnectionIds
|
|
61
|
+
});
|
|
62
|
+
if (props.variant === "panel") {
|
|
63
|
+
return /* @__PURE__ */ jsx(SourceCredentialNotice, { missing, onAction: props.onAction });
|
|
64
|
+
}
|
|
65
|
+
return /* @__PURE__ */ jsx(SourceCredentialStatusBadge, { missing });
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
GraphqlSourceSummary as default
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=GraphqlSourceSummary-F3JWR4YN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/GraphqlSourceSummary.tsx"],"sourcesContent":["import { useAtomValue } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\n\nimport { connectionsAtom } from \"@executor-js/react/api/atoms\";\nimport { useScope, useScopeStack, useUserScope } from \"@executor-js/react/api/scope-context\";\nimport {\n SourceCredentialNotice,\n SourceCredentialStatusBadge,\n missingSourceCredentialLabels,\n type SourceCredentialSlot,\n} from \"@executor-js/react/plugins/source-credential-status\";\nimport { ScopeId } from \"@executor-js/sdk/core\";\n\nimport { graphqlSourceAtom, graphqlSourceBindingsAtom } from \"./atoms\";\nimport type { StoredGraphqlSource } from \"../sdk/store\";\n\nconst sourceCredentialSlots = (source: StoredGraphqlSource): readonly SourceCredentialSlot[] => {\n const slots: SourceCredentialSlot[] = [];\n for (const [name, value] of Object.entries(source.headers)) {\n if (typeof value !== \"string\") slots.push({ kind: \"secret\", slot: value.slot, label: name });\n }\n for (const [name, value] of Object.entries(source.queryParams)) {\n if (typeof value !== \"string\") slots.push({ kind: \"secret\", slot: value.slot, label: name });\n }\n if (source.auth.kind === \"oauth2\") {\n slots.push({\n kind: \"connection\",\n slot: source.auth.connectionSlot,\n label: \"OAuth sign-in\",\n });\n }\n return slots;\n};\n\nexport default function GraphqlSourceSummary(props: {\n sourceId: string;\n variant?: \"badge\" | \"panel\";\n onAction?: () => void;\n}) {\n const displayScope = useScope();\n const userScope = useUserScope();\n const scopeStack = useScopeStack();\n const sourceResult = useAtomValue(graphqlSourceAtom(displayScope, props.sourceId));\n const source =\n AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;\n const sourceScope = source ? ScopeId.make(source.scope) : displayScope;\n const bindingsResult = useAtomValue(\n graphqlSourceBindingsAtom(displayScope, props.sourceId, sourceScope),\n );\n const connectionsResult = useAtomValue(connectionsAtom(displayScope));\n\n if (!source) return null;\n const slots = sourceCredentialSlots(source as StoredGraphqlSource);\n if (slots.length === 0) return null;\n if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) {\n return props.variant === \"panel\" ? null : (\n <SourceCredentialStatusBadge missing={[\"credentials\"]} />\n );\n }\n\n const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const));\n const liveConnectionIds = new Set(connectionsResult.value.map((connection) => connection.id));\n const missing = missingSourceCredentialLabels({\n slots,\n bindings: bindingsResult.value,\n targetScope: userScope,\n scopeRanks,\n liveConnectionIds,\n });\n\n if (props.variant === \"panel\") {\n return <SourceCredentialNotice missing={missing} onAction={props.onAction} />;\n }\n\n return <SourceCredentialStatusBadge missing={missing} />;\n}\n"],"mappings":";;;;;;;AAAA,SAAS,oBAAoB;AAC7B,YAAY,iBAAiB;AAE7B,SAAS,uBAAuB;AAChC,SAAS,UAAU,eAAe,oBAAoB;AACtD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,eAAe;AA6ClB;AAxCN,IAAM,wBAAwB,CAAC,WAAiE;AAC9F,QAAM,QAAgC,CAAC;AACvC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,OAAO,GAAG;AAC1D,QAAI,OAAO,UAAU,SAAU,OAAM,KAAK,EAAE,MAAM,UAAU,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,EAC7F;AACA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,WAAW,GAAG;AAC9D,QAAI,OAAO,UAAU,SAAU,OAAM,KAAK,EAAE,MAAM,UAAU,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,EAC7F;AACA,MAAI,OAAO,KAAK,SAAS,UAAU;AACjC,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,MAAM,OAAO,KAAK;AAAA,MAClB,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEe,SAAR,qBAAsC,OAI1C;AACD,QAAM,eAAe,SAAS;AAC9B,QAAM,YAAY,aAAa;AAC/B,QAAM,aAAa,cAAc;AACjC,QAAM,eAAe,aAAa,kBAAkB,cAAc,MAAM,QAAQ,CAAC;AACjF,QAAM,SACQ,sBAAU,YAAY,KAAK,aAAa,QAAQ,aAAa,QAAQ;AACnF,QAAM,cAAc,SAAS,QAAQ,KAAK,OAAO,KAAK,IAAI;AAC1D,QAAM,iBAAiB;AAAA,IACrB,0BAA0B,cAAc,MAAM,UAAU,WAAW;AAAA,EACrE;AACA,QAAM,oBAAoB,aAAa,gBAAgB,YAAY,CAAC;AAEpE,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,sBAAsB,MAA6B;AACjE,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI,CAAa,sBAAU,cAAc,KAAK,CAAa,sBAAU,iBAAiB,GAAG;AACvF,WAAO,MAAM,YAAY,UAAU,OACjC,oBAAC,+BAA4B,SAAS,CAAC,aAAa,GAAG;AAAA,EAE3D;AAEA,QAAM,aAAa,IAAI,IAAI,WAAW,IAAI,CAAC,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAU,CAAC;AACvF,QAAM,oBAAoB,IAAI,IAAI,kBAAkB,MAAM,IAAI,CAAC,eAAe,WAAW,EAAE,CAAC;AAC5F,QAAM,UAAU,8BAA8B;AAAA,IAC5C;AAAA,IACA,UAAU,eAAe;AAAA,IACzB,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,MAAM,YAAY,SAAS;AAC7B,WAAO,oBAAC,0BAAuB,SAAkB,UAAU,MAAM,UAAU;AAAA,EAC7E;AAEA,SAAO,oBAAC,+BAA4B,SAAkB;AACxD;","names":[]}
|