Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 67 additions & 2 deletions frontend/src/components/secret-syncs/SecretSyncStatusBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { useMemo } from "react";
import { faCalendarCheck, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import {
AlertTriangleIcon,
CheckIcon,
Expand All @@ -6,14 +10,17 @@ import {
RefreshCwIcon
} from "lucide-react";

import { Tooltip } from "@app/components/v2";
import { Badge, TBadgeProps } from "@app/components/v3";
import { SecretSyncStatus } from "@app/hooks/api/secretSyncs";

type Props = {
status: SecretSyncStatus;
lastSyncedAt?: Date | string | null;
lastSyncMessage?: string | null;
} & Omit<TBadgeProps, "children" | "variant">;

export const SecretSyncStatusBadge = ({ status }: Props) => {
export const SecretSyncStatusBadge = ({ status, lastSyncedAt, lastSyncMessage }: Props) => {
let variant: TBadgeProps["variant"];
let text: string;
let Icon: LucideIcon;
Expand Down Expand Up @@ -42,10 +49,68 @@ export const SecretSyncStatusBadge = ({ status }: Props) => {
break;
}

return (
const failureMessage = useMemo(() => {
if (status === SecretSyncStatus.Failed) {
if (lastSyncMessage)
try {
return JSON.stringify(JSON.parse(lastSyncMessage), null, 2);
} catch {
return lastSyncMessage;
}

return "An Unknown Error Occurred.";
}
return null;
}, [status, lastSyncMessage]);

const badge = (
<Badge variant={variant}>
<Icon className={[SecretSyncStatus.Running].includes(status) ? "animate-spin" : ""} />
{text}
</Badge>
);

if (
![SecretSyncStatus.Succeeded, SecretSyncStatus.Failed].includes(status) ||
(!lastSyncedAt && !failureMessage)
) {
return badge;
}

return (
<Tooltip
position="left"
className="max-w-sm"
content={
<div className="flex flex-col gap-2 py-1 whitespace-normal">
{lastSyncedAt && (
<div>
<div
className={`mb-2 flex self-start ${status === SecretSyncStatus.Failed ? "text-yellow" : "text-green"}`}
>
<FontAwesomeIcon icon={faCalendarCheck} className="ml-1 pt-0.5 pr-1.5 text-sm" />
<div className="text-xs">Last Synced</div>
</div>
<div className="rounded-sm bg-mineshaft-600 p-2 text-xs">
{format(new Date(lastSyncedAt), "yyyy-MM-dd, hh:mm aaa")}
</div>
</div>
)}
{failureMessage && (
<div>
<div className="mb-2 flex self-start text-red">
<FontAwesomeIcon icon={faXmark} className="ml-1 pt-0.5 pr-1.5 text-sm" />
<div className="text-xs">Failure Reason</div>
</div>
<div className="rounded-sm bg-mineshaft-600 p-2 text-xs break-words">
{failureMessage}
</div>
</div>
)}
</div>
}
>
<div>{badge}</div>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useCallback, useMemo } from "react";
import { useCallback } from "react";
import {
faBan,
faCalendarCheck,
faCheck,
faCopy,
faDownload,
Expand All @@ -11,12 +10,10 @@ import {
faRotate,
faToggleOff,
faToggleOn,
faTrash,
faXmark
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { format } from "date-fns";
import { AlertTriangleIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";

Expand Down Expand Up @@ -103,20 +100,6 @@ export const SecretSyncRow = ({
return () => clearTimeout(timer);
}, [isIdCopied]);

const failureMessage = useMemo(() => {
if (syncStatus === SecretSyncStatus.Failed) {
if (lastSyncMessage)
try {
return JSON.stringify(JSON.parse(lastSyncMessage), null, 2);
} catch {
return lastSyncMessage;
}

return "An Unknown Error Occurred.";
}
return null;
}, [syncStatus, lastSyncMessage]);

const destinationDetails = SECRET_SYNC_MAP[destination];

const permissionSubject = getSecretSyncPermissionSubject(secretSync);
Expand Down Expand Up @@ -180,47 +163,11 @@ export const SecretSyncRow = ({
<Td>
<div className="flex items-center gap-1">
{syncStatus && (
<Tooltip
position="left"
className="max-w-sm"
content={
[SecretSyncStatus.Succeeded, SecretSyncStatus.Failed].includes(syncStatus) ? (
<div className="flex flex-col gap-2 py-1 whitespace-normal">
{lastSyncedAt && (
<div>
<div
className={`mb-2 flex self-start ${syncStatus === SecretSyncStatus.Failed ? "text-yellow" : "text-green"}`}
>
<FontAwesomeIcon
icon={faCalendarCheck}
className="ml-1 pt-0.5 pr-1.5 text-sm"
/>
<div className="text-xs">Last Synced</div>
</div>
<div className="rounded-sm bg-mineshaft-600 p-2 text-xs">
{format(new Date(lastSyncedAt), "yyyy-MM-dd, hh:mm aaa")}
</div>
</div>
)}
{failureMessage && (
<div>
<div className="mb-2 flex self-start text-red">
<FontAwesomeIcon icon={faXmark} className="ml-1 pt-0.5 pr-1.5 text-sm" />
<div className="text-xs">Failure Reason</div>
</div>
<div className="rounded-sm bg-mineshaft-600 p-2 text-xs break-words">
{failureMessage}
</div>
</div>
)}
</div>
) : undefined
}
>
<div>
<SecretSyncStatusBadge status={syncStatus} />
</div>
</Tooltip>
<SecretSyncStatusBadge
status={syncStatus}
lastSyncedAt={lastSyncedAt}
lastSyncMessage={lastSyncMessage}
/>
)}
{!isAutoSyncEnabled && (
<Tooltip
Expand Down
33 changes: 29 additions & 4 deletions frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ import {
SecretImportTableRow,
SecretNoAccessTableRow,
SecretRotationTableRow,
SecretSyncStatusBadgeOverview,
SecretTableRow
} from "./components";

Expand Down Expand Up @@ -2562,6 +2563,9 @@ const OverviewPageContent = () => {
: "Click to enable batch edit mode. Changes will be grouped into a single commit."}
</TooltipContent>
</Tooltip>
<SecretSyncStatusBadgeOverview
environmentSlugs={visibleEnvs.map((e) => e.slug)}
/>
</div>
)}
<SecretDropzone
Expand All @@ -2579,7 +2583,12 @@ const OverviewPageContent = () => {
<UnstableTable ref={tableRef} className="border-separate border-spacing-0">
<UnstableTableHeader>
<UnstableTableRow className="h-10">
<UnstableTableHead className="sticky left-0 z-10 w-[40px] max-w-[40px] min-w-[40px] bg-container">
<UnstableTableHead
className={twMerge(
!isSingleEnvView && "sticky",
"left-0 z-10 w-[40px] max-w-[40px] min-w-[40px] bg-container"
)}
>
<Checkbox
variant="project"
isDisabled={totalCount === 0 || hasPendingBatchChanges}
Expand All @@ -2590,7 +2599,10 @@ const OverviewPageContent = () => {
/>
</UnstableTableHead>
<UnstableTableHead
className="sticky left-10 z-10 max-w-60 min-w-60 border-r bg-container lg:max-w-none lg:min-w-96"
className={twMerge(
!isSingleEnvView && "sticky",
"left-10 z-10 max-w-60 min-w-60 border-r bg-container lg:max-w-none lg:min-w-96"
)}
onClick={() =>
setOrderDirection((prev) =>
prev === OrderByDirection.ASC
Expand Down Expand Up @@ -2799,6 +2811,9 @@ const OverviewPageContent = () => {
: "Click to enable batch edit mode. Changes will be grouped into a single commit."}
</TooltipContent>
</Tooltip>
<SecretSyncStatusBadgeOverview
environmentSlugs={visibleEnvs.map((e) => e.slug)}
/>
</div>
</div>
</UnstableTableHead>
Expand All @@ -2809,10 +2824,20 @@ const OverviewPageContent = () => {
{isOverviewLoading || isPlaceholderData ? (
Array.from({ length: prevPageSize.current || perPage }).map((_, index) => (
<UnstableTableRow className="group" key={`loading-row-${index + 1}`}>
<UnstableTableCell className="sticky left-0 z-10 bg-container group-hover:bg-container-hover">
<UnstableTableCell
className={twMerge(
!isSingleEnvView && "sticky",
"left-0 z-10 bg-container group-hover:bg-container-hover"
)}
>
<Skeleton className="h-4 w-full" />
</UnstableTableCell>
<UnstableTableCell className="sticky left-10 z-10 border-r bg-container group-hover:bg-container-hover">
<UnstableTableCell
className={twMerge(
!isSingleEnvView && "sticky",
"left-10 z-10 border-r bg-container group-hover:bg-container-hover"
)}
>
<Skeleton className="h-4 w-full" />
</UnstableTableCell>
{visibleEnvs.map((env) => {
Expand Down
Loading
Loading