Unified · Split
| @@ -4,6 +4,7 @@ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; · 3 unmodified lines | |||
| 4 | import { connectionsAtom } from "@executor-js/react/api/atoms"; | 4 | import { connectionsAtom } from "@executor-js/react/api/atoms"; |
| 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; | 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 6 | import { | 6 | import { |
| 7 | SourceCredentialLoadingBadge, | ||
| 7 | SourceCredentialNotice, | 8 | SourceCredentialNotice, |
| 8 | SourceCredentialStatusBadge, | 9 | SourceCredentialStatusBadge, |
| 9 | missingSourceCredentialLabels, | 10 | missingSourceCredentialLabels, |
| @@ -53,9 +54,7 @@ export default function GraphqlSourceSummary(props: { · 43 unmodified lines | |||
| 53 | const slots = sourceCredentialSlots(source as StoredGraphqlSource); | 54 | const slots = sourceCredentialSlots(source as StoredGraphqlSource); |
| 54 | if (slots.length === 0) return null; | 55 | if (slots.length === 0) return null; |
| 55 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { | 56 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { |
| 56 | return props.variant === "panel" ? null : ( | 57 | return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; |
| 57 | <SourceCredentialStatusBadge missing={["credentials"]} /> | ||
| 58 | ); | ||
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const)); | 60 | const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const)); |
| @@ -5,6 +5,7 @@ import { connectionsAtom } from "@executor-js/react/api/atoms"; · 4 unmodified lines | |||
| 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; | 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 6 | import { Button } from "@executor-js/react/components/button"; | 6 | import { Button } from "@executor-js/react/components/button"; |
| 7 | import { | 7 | import { |
| 8 | SourceCredentialLoadingBadge, | ||
| 8 | SourceCredentialNotice, | 9 | SourceCredentialNotice, |
| 9 | SourceCredentialStatusBadge, | 10 | SourceCredentialStatusBadge, |
| 10 | missingSourceCredentialLabels, | 11 | missingSourceCredentialLabels, |
| @@ -72,9 +73,7 @@ export default function McpSourceSummary(props: { · 61 unmodified lines | |||
| 72 | const slots = sourceCredentialSlots(source as McpStoredSourceSchemaType); | 73 | const slots = sourceCredentialSlots(source as McpStoredSourceSchemaType); |
| 73 | if (slots.length === 0) return null; | 74 | if (slots.length === 0) return null; |
| 74 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { | 75 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { |
| 75 | return props.variant === "panel" ? null : ( | 76 | return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; |
| 76 | <SourceCredentialStatusBadge missing={["credentials"]} /> | ||
| 77 | ); | ||
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const)); | 79 | const scopeRanks = new Map(scopeStack.map((scope, index) => [scope.id, index] as const)); |
| @@ -6,6 +6,7 @@ import { Badge } from "@executor-js/react/components/badge"; · 5 unmodified lines | |||
| 6 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; | 6 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 7 | import { ScopeId } from "@executor-js/sdk/shared"; | 7 | import { ScopeId } from "@executor-js/sdk/shared"; |
| 8 | import { | 8 | import { |
| 9 | SourceCredentialLoadingBadge, | ||
| 9 | SourceCredentialNotice, | 10 | SourceCredentialNotice, |
| 10 | SourceCredentialStatusBadge, | 11 | SourceCredentialStatusBadge, |
| 11 | missingSourceCredentialLabels, | 12 | missingSourceCredentialLabels, |
| @@ -20,17 +21,6 @@ function OAuthBadge() { · 8 unmodified lines | |||
| 20 | return <Badge variant="secondary">OAuth</Badge>; | 21 | return <Badge variant="secondary">OAuth</Badge>; |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | function CheckingCredentialsBadge() { | ||
| 24 | return ( | ||
| 25 | <Badge | ||
| 26 | variant="outline" | ||
| 27 | className="border-border bg-muted/50 text-[10px] text-muted-foreground" | ||
| 28 | > | ||
| 29 | Checking credentials | ||
| 30 | </Badge> | ||
| 31 | ); | ||
| 32 | } | ||
| 33 | |||
| 34 | const effectiveClientSecretSlot = (oauth2: { | 24 | const effectiveClientSecretSlot = (oauth2: { |
| 35 | readonly securitySchemeName: string; | 25 | readonly securitySchemeName: string; |
| 36 | readonly clientSecretSlot: string | null; | 26 | readonly clientSecretSlot: string | null; |
| @@ -92,12 +82,12 @@ export default function OpenApiSourceSummary(props: { · 55 unmodified lines | |||
| 92 | const bindingsLoaded = AsyncResult.isSuccess(bindingsResult); | 82 | const bindingsLoaded = AsyncResult.isSuccess(bindingsResult); |
| 93 | const connectionsLoaded = AsyncResult.isSuccess(connectionsResult); | 83 | const connectionsLoaded = AsyncResult.isSuccess(connectionsResult); |
| 94 | if (!bindingsLoaded) { | 84 | if (!bindingsLoaded) { |
| 95 | return props.variant === "panel" ? null : <CheckingCredentialsBadge />; | 85 | return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; |
| 96 | } | 86 | } |
| 97 | 87 | ||
| 98 | const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : []; | 88 | const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : []; |
| 99 | if (oauth2 && !connectionsLoaded) { | 89 | if (oauth2 && !connectionsLoaded) { |
| 100 | return props.variant === "panel" ? null : <CheckingCredentialsBadge />; | 90 | return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; |
| 101 | } | 91 | } |
| 102 | const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : []; | 92 | const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : []; |
| 103 | const liveConnectionIds = new Set(connections.map((connection) => connection.id)); | 93 | const liveConnectionIds = new Set(connections.map((connection) => connection.id)); |
| @@ -8,6 +8,17 @@ export { · 7 unmodified lines | |||
| 8 | type SourceCredentialSlot, | 8 | type SourceCredentialSlot, |
| 9 | } from "./source-credential-status-core"; | 9 | } from "./source-credential-status-core"; |
| 10 | 10 | ||
| 11 | export function SourceCredentialLoadingBadge() { | ||
| 12 | return ( | ||
| 13 | <Badge | ||
| 14 | variant="outline" | ||
| 15 | className="animate-pulse border-border bg-muted/40 text-[10px] text-muted-foreground" | ||
| 16 | > | ||
| 17 | loading | ||
| 18 | </Badge> | ||
| 19 | ); | ||
| 20 | } | ||
| 21 | |||
| 11 | export function SourceCredentialStatusBadge(props: { readonly missing: readonly string[] }) { | 22 | export function SourceCredentialStatusBadge(props: { readonly missing: readonly string[] }) { |
| 12 | if (props.missing.length === 0) { | 23 | if (props.missing.length === 0) { |
| 13 | return ( | 24 | return ( |