Unified · Split
| @@ -4,6 +4,7 @@ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; · 3 unmodified lines | ||
| 4 | 4 | import { connectionsAtom } from "@executor-js/react/api/atoms"; |
| 5 | 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 6 | 6 | import { |
| 7 | + SourceCredentialLoadingBadge, | |
| 7 | 8 | SourceCredentialNotice, |
| 8 | 9 | SourceCredentialStatusBadge, |
| 9 | 10 | missingSourceCredentialLabels, |
| @@ -53,9 +54,7 @@ export default function GraphqlSourceSummary(props: { · 43 unmodified lines | ||
| 53 | 54 | const slots = sourceCredentialSlots(source as StoredGraphqlSource); |
| 54 | 55 | if (slots.length === 0) return null; |
| 55 | 56 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { |
| 56 | − return props.variant === "panel" ? null : ( | |
| 57 | − <SourceCredentialStatusBadge missing={["credentials"]} /> | |
| 58 | − ); | |
| 57 | + return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; | |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | 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 | 5 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 6 | 6 | import { Button } from "@executor-js/react/components/button"; |
| 7 | 7 | import { |
| 8 | + SourceCredentialLoadingBadge, | |
| 8 | 9 | SourceCredentialNotice, |
| 9 | 10 | SourceCredentialStatusBadge, |
| 10 | 11 | missingSourceCredentialLabels, |
| @@ -72,9 +73,7 @@ export default function McpSourceSummary(props: { · 61 unmodified lines | ||
| 72 | 73 | const slots = sourceCredentialSlots(source as McpStoredSourceSchemaType); |
| 73 | 74 | if (slots.length === 0) return null; |
| 74 | 75 | if (!AsyncResult.isSuccess(bindingsResult) || !AsyncResult.isSuccess(connectionsResult)) { |
| 75 | − return props.variant === "panel" ? null : ( | |
| 76 | − <SourceCredentialStatusBadge missing={["credentials"]} /> | |
| 77 | − ); | |
| 76 | + return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; | |
| 78 | 77 | } |
| 79 | 78 | |
| 80 | 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 | 6 | import { useScope, useScopeStack, useUserScope } from "@executor-js/react/api/scope-context"; |
| 7 | 7 | import { ScopeId } from "@executor-js/sdk/shared"; |
| 8 | 8 | import { |
| 9 | + SourceCredentialLoadingBadge, | |
| 9 | 10 | SourceCredentialNotice, |
| 10 | 11 | SourceCredentialStatusBadge, |
| 11 | 12 | missingSourceCredentialLabels, |
| @@ -20,17 +21,6 @@ function OAuthBadge() { · 8 unmodified lines | ||
| 20 | 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 | 24 | const effectiveClientSecretSlot = (oauth2: { |
| 35 | 25 | readonly securitySchemeName: string; |
| 36 | 26 | readonly clientSecretSlot: string | null; |
| @@ -92,12 +82,12 @@ export default function OpenApiSourceSummary(props: { · 55 unmodified lines | ||
| 92 | 82 | const bindingsLoaded = AsyncResult.isSuccess(bindingsResult); |
| 93 | 83 | const connectionsLoaded = AsyncResult.isSuccess(connectionsResult); |
| 94 | 84 | if (!bindingsLoaded) { |
| 95 | − return props.variant === "panel" ? null : <CheckingCredentialsBadge />; | |
| 85 | + return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; | |
| 96 | 86 | } |
| 97 | 87 | |
| 98 | 88 | const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : []; |
| 99 | 89 | if (oauth2 && !connectionsLoaded) { |
| 100 | − return props.variant === "panel" ? null : <CheckingCredentialsBadge />; | |
| 90 | + return props.variant === "panel" ? null : <SourceCredentialLoadingBadge />; | |
| 101 | 91 | } |
| 102 | 92 | const connections = AsyncResult.isSuccess(connectionsResult) ? connectionsResult.value : []; |
| 103 | 93 | const liveConnectionIds = new Set(connections.map((connection) => connection.id)); |
| @@ -8,6 +8,17 @@ export { · 7 unmodified lines | ||
| 8 | 8 | type SourceCredentialSlot, |
| 9 | 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 | 22 | export function SourceCredentialStatusBadge(props: { readonly missing: readonly string[] }) { |
| 12 | 23 | if (props.missing.length === 0) { |
| 13 | 24 | return ( |