Show bridge errors in connector cards
Display SCIM bridge state directly on Google Workspace and Microsoft 365 connector cards so admins can quickly identify failing bridges. When a bridge is failed, render an inline error callout and surface the latest provisioning event error message to make troubleshooting visible without leaving the connector section. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
This commit is contained in:
committed by
Bryan Frimin
parent
4d4f4fa526
commit
f02c3b88b7
@@ -23,6 +23,7 @@ import {
|
||||
DialogFooter,
|
||||
Google,
|
||||
IconSettingsGear2,
|
||||
IconWarning,
|
||||
Input,
|
||||
useDialogRef,
|
||||
useToast,
|
||||
@@ -38,9 +39,18 @@ import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||
const googleWorkspaceConnectorFragment = graphql`
|
||||
fragment GoogleWorkspaceConnectorFragment on SCIMConfiguration {
|
||||
id
|
||||
events(first: 1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
errorMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
bridge {
|
||||
id
|
||||
type
|
||||
state
|
||||
excludedUserNames
|
||||
connector {
|
||||
id
|
||||
@@ -83,9 +93,26 @@ export function GoogleWorkspaceConnector(props: {
|
||||
const connector = bridge?.connector;
|
||||
const scimConfigurationId = data?.id;
|
||||
const bridgeId = bridge?.id;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __, dateTimeFormat } = useTranslate();
|
||||
const bridgeState = bridge?.state ?? null;
|
||||
const latestBridgeError = data?.events?.edges?.[0]?.node?.errorMessage ?? null;
|
||||
const isBridgeFailed = bridgeState === "FAILED";
|
||||
const isBridgePending = bridgeState === "PENDING";
|
||||
const bridgeStatusBadgeVariant = isBridgeFailed
|
||||
? "danger"
|
||||
: isBridgePending
|
||||
? "warning"
|
||||
: "success";
|
||||
const bridgeStatusLabel = isBridgeFailed
|
||||
? __("Error")
|
||||
: isBridgePending
|
||||
? __("Syncing")
|
||||
: __("Connected");
|
||||
const bridgeErrorMessage = latestBridgeError
|
||||
?? __(
|
||||
"The bridge is currently failing to sync. Check the provisioning event history for more details.",
|
||||
);
|
||||
const { toast } = useToast();
|
||||
const dialogRef = useDialogRef();
|
||||
const excludedUserNamesDialogRef = useDialogRef();
|
||||
@@ -225,7 +252,8 @@ export function GoogleWorkspaceConnector(props: {
|
||||
|
||||
// Connected state
|
||||
return (
|
||||
<Card padded className="flex items-center gap-3">
|
||||
<Card padded className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 flex items-center justify-center bg-subtle rounded">
|
||||
<Google className="w-6 h-6" />
|
||||
</div>
|
||||
@@ -235,8 +263,8 @@ export function GoogleWorkspaceConnector(props: {
|
||||
{sprintf(__("Connected on %s"), dateTimeFormat(connector.createdAt))}
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant="success" size="md">
|
||||
{__("Connected")}
|
||||
<Badge variant={bridgeStatusBadgeVariant} size="md">
|
||||
{bridgeStatusLabel}
|
||||
</Badge>
|
||||
<Dialog
|
||||
ref={excludedUserNamesDialogRef}
|
||||
@@ -337,6 +365,21 @@ export function GoogleWorkspaceConnector(props: {
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{isBridgeFailed && (
|
||||
<div className="flex items-start gap-2 rounded-lg bg-bg-warning/10 border border-border-warning p-3">
|
||||
<IconWarning size={16} className="text-txt-danger shrink-0 mt-0.5" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm font-medium text-txt-danger">
|
||||
{__("Bridge is in an error state")}
|
||||
</p>
|
||||
<p className="text-sm text-txt-secondary whitespace-pre-wrap break-all">
|
||||
{bridgeErrorMessage}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
IconSettingsGear2,
|
||||
IconWarning,
|
||||
Input,
|
||||
Microsoft,
|
||||
useDialogRef,
|
||||
@@ -38,9 +39,18 @@ import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||
const microsoft365ConnectorFragment = graphql`
|
||||
fragment Microsoft365ConnectorFragment on SCIMConfiguration {
|
||||
id
|
||||
events(first: 1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
errorMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
bridge {
|
||||
id
|
||||
type
|
||||
state
|
||||
excludedUserNames
|
||||
connector {
|
||||
id
|
||||
@@ -83,9 +93,26 @@ export function Microsoft365Connector(props: {
|
||||
const connector = bridge?.connector;
|
||||
const scimConfigurationId = data?.id;
|
||||
const bridgeId = bridge?.id;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __, dateTimeFormat } = useTranslate();
|
||||
const bridgeState = bridge?.state ?? null;
|
||||
const latestBridgeError = data?.events?.edges?.[0]?.node?.errorMessage ?? null;
|
||||
const isBridgeFailed = bridgeState === "FAILED";
|
||||
const isBridgePending = bridgeState === "PENDING";
|
||||
const bridgeStatusBadgeVariant = isBridgeFailed
|
||||
? "danger"
|
||||
: isBridgePending
|
||||
? "warning"
|
||||
: "success";
|
||||
const bridgeStatusLabel = isBridgeFailed
|
||||
? __("Error")
|
||||
: isBridgePending
|
||||
? __("Syncing")
|
||||
: __("Connected");
|
||||
const bridgeErrorMessage = latestBridgeError
|
||||
?? __(
|
||||
"The bridge is currently failing to sync. Check the provisioning event history for more details.",
|
||||
);
|
||||
const { toast } = useToast();
|
||||
const dialogRef = useDialogRef();
|
||||
const excludedUserNamesDialogRef = useDialogRef();
|
||||
@@ -223,7 +250,8 @@ export function Microsoft365Connector(props: {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card padded className="flex items-center gap-3">
|
||||
<Card padded className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 flex items-center justify-center bg-subtle rounded">
|
||||
<Microsoft className="w-6 h-6" />
|
||||
</div>
|
||||
@@ -233,8 +261,8 @@ export function Microsoft365Connector(props: {
|
||||
{sprintf(__("Connected on %s"), dateTimeFormat(connector.createdAt))}
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant="success" size="md">
|
||||
{__("Connected")}
|
||||
<Badge variant={bridgeStatusBadgeVariant} size="md">
|
||||
{bridgeStatusLabel}
|
||||
</Badge>
|
||||
<Dialog
|
||||
ref={excludedUserNamesDialogRef}
|
||||
@@ -335,6 +363,21 @@ export function Microsoft365Connector(props: {
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{isBridgeFailed && (
|
||||
<div className="flex items-start gap-2 rounded-lg bg-bg-warning/10 border border-border-warning p-3">
|
||||
<IconWarning size={16} className="text-txt-danger shrink-0 mt-0.5" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm font-medium text-txt-danger">
|
||||
{__("Bridge is in an error state")}
|
||||
</p>
|
||||
<p className="text-sm text-txt-secondary whitespace-pre-wrap break-all">
|
||||
{bridgeErrorMessage}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user