@anchrd/intel-ui 0.8.0 → 0.8.2
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/package.json +1 -1
- package/src/i18n/en.json +5 -0
- package/src/tools/tools.tsx +36 -7
package/package.json
CHANGED
package/src/i18n/en.json
CHANGED
|
@@ -147,6 +147,11 @@
|
|
|
147
147
|
"tools.emptyHelp": "The portal answered, and it offers your account no tools. An administrator decides in the portal which servers exist and who may reach them.",
|
|
148
148
|
"tools.unreachable": "Portal not reachable",
|
|
149
149
|
"tools.unreachableHelp": "The company MCP portal did not answer, so Intel cannot tell which tools you have. Nothing is stored here; try again once the portal responds.",
|
|
150
|
+
"tools.connectExpired": "The portal sign-in took too long",
|
|
151
|
+
"tools.connectExpiredHelp": "The connection to the company MCP portal has to be completed within a few minutes, and this one ran out while the authorization screen was open. Nothing went wrong and nothing was refused — start it again and confirm the servers when the screen appears.",
|
|
152
|
+
"tools.connectRetry": "Start again",
|
|
153
|
+
"tools.connectFailed": "Portal sign-in failed",
|
|
154
|
+
"tools.connectFailedHelp": "The sign-in to the company MCP portal broke before it could be answered. This is a technical fault, not a decision about your access — reload to try again, and tell an administrator if it stays.",
|
|
150
155
|
"tools.origin": "Origin",
|
|
151
156
|
"tools.originPortal": "Company portal",
|
|
152
157
|
"tools.inputSchema": "Input schema",
|
package/src/tools/tools.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ToolCapability } from "@anchrd/intel-contract";
|
|
2
2
|
import { useQuery } from "@tanstack/react-query";
|
|
3
3
|
import { useRouterState } from "@tanstack/react-router";
|
|
4
|
-
import { AlertTriangle, ChevronRight, PlugZap, ShieldOff, Wrench } from "lucide-react";
|
|
4
|
+
import { AlertTriangle, ChevronRight, PlugZap, ShieldOff, Timer, Wrench } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import { Button } from "@/components/ui/button";
|
|
7
7
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
|
@@ -44,11 +44,17 @@ export function Tools() {
|
|
|
44
44
|
// A hit from the header search arrives as `?select=<tool name>`, and the row it names opens with
|
|
45
45
|
// the list. Nothing else about the row changes: it is still only a disclosure.
|
|
46
46
|
const requested = useRouterState({ select: (state) => selectedFrom(state.location.search) });
|
|
47
|
-
// The silent sign-in returns here with a marker when
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
// The silent sign-in returns here with a marker when it failed. The value comes from outside
|
|
48
|
+
// and could carry provider detail, so it is never rendered — it is only compared against the
|
|
49
|
+
// codes Intel itself writes, to tell "you may not" from "the sign-in broke" (#93): the first is
|
|
50
|
+
// a sentence about access, the second must not masquerade as one.
|
|
51
|
+
const connectError =
|
|
52
|
+
typeof window === "undefined"
|
|
53
|
+
? null
|
|
54
|
+
: new URLSearchParams(window.location.search).get("connectError");
|
|
55
|
+
const refused = connectError !== null;
|
|
56
|
+
const accessDenied =
|
|
57
|
+
connectError === "portal_sign_in_refused" || connectError === "permission_required";
|
|
52
58
|
const [signingIn, setSigningIn] = React.useState(false);
|
|
53
59
|
|
|
54
60
|
// ⚠️ Nobody is asked to start this. The portal sign-in is a browser redirect, so the screen
|
|
@@ -90,7 +96,20 @@ export function Tools() {
|
|
|
90
96
|
) : !catalog.data.portalConnected ? (
|
|
91
97
|
signingIn ? (
|
|
92
98
|
<p className="text-sm text-muted-foreground">{i18n.t("tools.signingIn")}</p>
|
|
93
|
-
) : (
|
|
99
|
+
) : connectError === "portal_sign_in_expired" ? (
|
|
100
|
+
// Ran out of time on the consent screen. Nothing is broken and nobody was refused, so
|
|
101
|
+
// neither of the other two sentences fits — and this one is the only case the reader
|
|
102
|
+
// can fix alone, by starting over (#95).
|
|
103
|
+
<Notice
|
|
104
|
+
icon={<Timer aria-hidden="true" className="mx-auto size-8 text-muted-foreground" />}
|
|
105
|
+
title={i18n.t("tools.connectExpired")}
|
|
106
|
+
help={i18n.t("tools.connectExpiredHelp")}
|
|
107
|
+
>
|
|
108
|
+
<Button variant="outline" onClick={() => data.startPortalSignIn("/tools")}>
|
|
109
|
+
{i18n.t("tools.connectRetry")}
|
|
110
|
+
</Button>
|
|
111
|
+
</Notice>
|
|
112
|
+
) : accessDenied || !refused ? (
|
|
94
113
|
// The end of the silent walk for somebody no Access policy carries. It is a sentence
|
|
95
114
|
// about access, not an invitation to connect: there is nothing they could click that
|
|
96
115
|
// would change the answer, and what the portal replied is not repeated here.
|
|
@@ -102,6 +121,16 @@ export function Tools() {
|
|
|
102
121
|
title={i18n.t("tools.noAccess")}
|
|
103
122
|
help={i18n.t("tools.noAccessHelp")}
|
|
104
123
|
/>
|
|
124
|
+
) : (
|
|
125
|
+
// Every other marker is machinery, not policy: the sign-in broke before anyone could
|
|
126
|
+
// be allowed or refused. Saying "no access" here sent the last reader hunting through
|
|
127
|
+
// Access policies while the real fault sat in a failed client registration (#93).
|
|
128
|
+
<Notice
|
|
129
|
+
alert
|
|
130
|
+
icon={<PlugZap aria-hidden="true" className="mx-auto size-8 text-destructive" />}
|
|
131
|
+
title={i18n.t("tools.connectFailed")}
|
|
132
|
+
help={i18n.t("tools.connectFailedHelp")}
|
|
133
|
+
/>
|
|
105
134
|
)
|
|
106
135
|
) : catalog.data.items.length === 0 ? (
|
|
107
136
|
<Notice
|