From be8985edf4a02bb1ddbbfbd8b315a3c5f1f0c223 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Wed, 11 Feb 2026 14:59:09 +0300 Subject: [PATCH 01/10] fix: deploy ui issues --- .../components/scroll-to-bottom-button.tsx | 73 ++++++++++++++ .../sections/deployment-domains-section.tsx | 2 +- .../sections/deployment-logs-section.tsx | 14 +-- .../deployments/[deploymentId]/layout.tsx | 2 +- .../network/deployment-network-view.tsx | 2 +- .../deployments/[deploymentId]/page.tsx | 17 ++-- .../details/custom-domains-section/index.tsx | 46 +++------ .../(overview)/details/domain-row.tsx | 36 +++++-- .../env-variables-section/add-env-vars.tsx | 18 ++-- .../components/env-var-secret-switch.tsx | 15 ++- .../details/env-variables-section/index.tsx | 96 ++++++------------- .../project-details-expandables/sections.tsx | 2 +- .../components/region-flags-skeleton.tsx | 12 +++ .../[projectId]/components/region-flags.tsx | 5 + .../projects/[projectId]/page.tsx | 2 +- web/apps/dashboard/components/ui/switch.tsx | 5 +- 16 files changed, 199 insertions(+), 148 deletions(-) create mode 100644 web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx create mode 100644 web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags-skeleton.tsx diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx new file mode 100644 index 0000000000..ec91e8ba88 --- /dev/null +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx @@ -0,0 +1,73 @@ +"use client"; +import { eq, useLiveQuery } from "@tanstack/react-db"; +import { ChevronDown } from "@unkey/icons"; +import { cn } from "@unkey/ui/src/lib/utils"; +import { useParams } from "next/navigation"; +import { useProject } from "../../../../layout-provider"; + +export function ScrollToBottomButton() { + const params = useParams(); + const deploymentId = params?.deploymentId as string; + const { collections } = useProject(); + const deployment = useLiveQuery( + (q) => + q + .from({ deployment: collections.deployments }) + .where(({ deployment }) => eq(deployment.id, deploymentId)), + [deploymentId], + ); + const isVisible = deployment.data.at(0)?.status !== "ready"; + + const handleScrollToBottom = () => { + const container = document.getElementById("deployment-scroll-container"); + if (container) { + container.scrollTo({ + top: container.scrollHeight, + behavior: "smooth", + }); + } + }; + + return ( + + ); +} diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-domains-section.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-domains-section.tsx index 7340620afc..9233827c65 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-domains-section.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-domains-section.tsx @@ -37,7 +37,7 @@ export function DeploymentDomainsSection() { )) ) : ( - + )} diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-logs-section.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-logs-section.tsx index 63f215ec76..d0c05790a3 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-logs-section.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-logs-section.tsx @@ -28,13 +28,13 @@ export function DeploymentLogsSection() { const deploymentStatus = deployment?.status; // During build phase, default to "Build logs" and disable "Logs" tab - const isBuildPhase = deploymentStatus === "building"; + const isReady = deploymentStatus !== "ready"; - const [tab, setTab] = useState(isBuildPhase ? "build-logs" : "sentinel"); + const [tab, setTab] = useState(isReady ? "build-logs" : "requests"); useEffect(() => { - setTab(isBuildPhase ? "build-logs" : "sentinel"); - }, [isBuildPhase]); + setTab(isReady ? "build-logs" : "requests"); + }, [isReady]); return (
@@ -43,9 +43,9 @@ export function DeploymentLogsSection() { Requests @@ -54,7 +54,7 @@ export function DeploymentLogsSection() { - + diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/layout.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/layout.tsx index 828fef9753..f036646d41 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/layout.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/layout.tsx @@ -8,7 +8,7 @@ export default function DeploymentLayout({ return (
-
{children}
+
{children}
); } diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx index 4d6305efe7..c6229465e0 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/network/deployment-network-view.tsx @@ -41,7 +41,7 @@ export function DeploymentNetworkView({ { deploymentId: deploymentId ?? "", }, - { enabled: Boolean(deploymentId) }, + { refetchInterval: 2000, enabled: Boolean(deploymentId) }, ); const currentTree = generatedTree ?? defaultTree ?? SKELETON_TREE; diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/page.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/page.tsx index 6e3a4b8db8..2e7361accb 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/page.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/page.tsx @@ -1,18 +1,23 @@ "use client"; import { ProjectContentWrapper } from "../../../components/project-content-wrapper"; +import { ScrollToBottomButton } from "./(overview)/components/scroll-to-bottom-button"; import { DeploymentDomainsSection } from "./(overview)/components/sections/deployment-domains-section"; import { DeploymentInfoSection } from "./(overview)/components/sections/deployment-info-section"; import { DeploymentLogsSection } from "./(overview)/components/sections/deployment-logs-section"; import { DeploymentNetworkSection } from "./(overview)/components/sections/deployment-network-section"; export default function DeploymentOverview() { + return ( - - - - - - + <> + + + + + + + + ); } diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/custom-domains-section/index.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/custom-domains-section/index.tsx index 5c653b005b..f3d58c8c3b 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/custom-domains-section/index.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/custom-domains-section/index.tsx @@ -1,11 +1,12 @@ "use client"; -import { Link4, Plus } from "@unkey/icons"; +import { Plus } from "@unkey/icons"; import { Button } from "@unkey/ui"; import { cn } from "@unkey/ui/src/lib/utils"; import { useState } from "react"; import { AddCustomDomain } from "./add-custom-domain"; import { CustomDomainRow, CustomDomainRowSkeleton } from "./custom-domain-row"; import { useCustomDomainsManager } from "./hooks/use-custom-domains-manager"; +import { DomainRowEmpty } from "../domain-row"; type CustomDomainsSectionProps = { projectId: string; @@ -80,39 +81,14 @@ export function CustomDomainsSection({ projectId, environments }: CustomDomainsS function EmptyState({ onAdd, hasEnvironments }: { onAdd: () => void; hasEnvironments: boolean }) { return ( -
-
- {/* Icon with subtle animation */} -
-
-
- -
-
- {/* Content */} -
-

No custom domains configured

- {hasEnvironments ? ( -

- Add a custom domain to serve your application from your own domain. -

- ) : ( -

- Create an environment first to add custom domains -

- )} -
- {/* Button */} - {hasEnvironments && ( - - )} -
-
+ + {hasEnvironments && ( + + )} + ); } + diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/domain-row.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/domain-row.tsx index 4e185cacd3..f424b276fe 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/domain-row.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/domain-row.tsx @@ -3,6 +3,7 @@ import { Badge } from "@unkey/ui"; import { cn } from "@unkey/ui/src/lib/utils"; import Link from "next/link"; import { Card } from "../components/card"; +import { PropsWithChildren, ReactNode } from "react"; type DomainRowProps = { domain: string; @@ -53,30 +54,45 @@ export const DomainRowSkeleton = () => { ); }; -export const DomainRowEmpty = () => ( + +type DomainRowEmptyProps = PropsWithChildren<{ + title: string; + description: string; + icon?: ReactNode; + className?: string; +}>; + +export const DomainRowEmpty = ({ + title, + description, + children, + icon = , + className, +}: DomainRowEmptyProps) => (
{/* Icon with subtle animation */}
- +
+ {icon} +
{/* Content */}
-

No domains found

+

{title}

- Your configured domains will appear here once they're set up and verified. + {description}

+ {children}
); diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/add-env-vars.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/add-env-vars.tsx index d9581c1616..52c0cea1e3 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/add-env-vars.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/add-env-vars.tsx @@ -207,9 +207,8 @@ export function AddEnvVars({ toast.promise(mutation, { loading: "Adding environment variables...", - success: `Added ${validEntries.length} environment variable${ - validEntries.length > 1 ? "s" : "" - }`, + success: `Added ${validEntries.length} environment variable${validEntries.length > 1 ? "s" : "" + }`, error: (err) => ({ message: "Failed to add environment variables", description: err.message || "Please try again", @@ -219,7 +218,7 @@ export function AddEnvVars({ try { await mutation; onSuccess(); - } catch {} + } catch { } }; return ( @@ -284,15 +283,14 @@ export function AddEnvVars({ disabled={isSubmitting} /> -
+ +
); })} diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/components/env-var-secret-switch.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/components/env-var-secret-switch.tsx index 6f329ae69c..dfd38c1f07 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/components/env-var-secret-switch.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/env-variables-section/components/env-var-secret-switch.tsx @@ -11,10 +11,19 @@ export const EnvVarSecretSwitch = ({ }) => { return (
- Secret + Secret {/* Header */} -
+
{icon}
{title} {envVars.length > 0 && `(${envVars.length})`}
-
- - -
+ /> +
- - {/* Expandable Content */}
+ {/* Concave separator */} +
+
+
)} - {envVars.length === 0 && !isAddingNew && } + {envVars.length === 0 && !isAddingNew && + }> + + }
@@ -153,46 +154,3 @@ const getItemAnimationProps = (index: number, isExpanded: boolean) => { style: { transitionDelay: isExpanded ? `${delay}ms` : "0ms" }, }; }; - -// Concave separator component -function ConcaveSeparator({ isExpanded }: { isExpanded: boolean }) { - return ( -
-
-
-
-
- ); -} - -// Empty state component -function EmptyState() { - return ( -
-
- {/* Icon with subtle animation */} -
-
-
- -
-
- {/* Content */} -
-

No environment variables configured

-

- Add environment variables to configure your application's runtime settings. -

-
-
-
- ); -} diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/project-details-expandables/sections.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/project-details-expandables/sections.tsx index 041391160e..e57ba7c242 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/project-details-expandables/sections.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/project-details-expandables/sections.tsx @@ -134,7 +134,7 @@ export const createDetailSections = ( alignment: "start", content: (
- +
), }, diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags-skeleton.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags-skeleton.tsx new file mode 100644 index 0000000000..c2863dc676 --- /dev/null +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags-skeleton.tsx @@ -0,0 +1,12 @@ +export function RegionFlagsSkeleton() { + return ( +
+ {Array.from({ length: 3 }).map((_, i) => ( +
+ ))} +
+ ); +} diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags.tsx index 6122b31ff9..7af5bd7238 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/region-flags.tsx @@ -1,11 +1,16 @@ import type { FlagCode } from "@/lib/trpc/routers/deploy/network/utils"; import { RegionFlag } from "./region-flag"; +import { RegionFlagsSkeleton } from "./region-flags-skeleton"; type RegionFlagsProps = { instances: { id: string; flagCode: FlagCode }[]; }; export function RegionFlags({ instances }: RegionFlagsProps) { + if (instances.length === 0) { + return ; + } + return (
{instances.map((instance) => ( diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/page.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/page.tsx index facb3b9fa6..bdbf0d0bc5 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/page.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/page.tsx @@ -80,7 +80,7 @@ export default function ProjectDetails() { )) ) : ( - + )}
diff --git a/web/apps/dashboard/components/ui/switch.tsx b/web/apps/dashboard/components/ui/switch.tsx index a07ba3a713..af37f31a63 100644 --- a/web/apps/dashboard/components/ui/switch.tsx +++ b/web/apps/dashboard/components/ui/switch.tsx @@ -22,11 +22,10 @@ const Switch = React.forwardRef< - + /> )); Switch.displayName = SwitchPrimitives.Root.displayName; From 0d1c9cc4d07a70bcdff3dbe2dfe6e710b343d757 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Wed, 11 Feb 2026 16:28:49 +0300 Subject: [PATCH 02/10] fix: organize frequently used queries --- .../[projectId]/(overview)/data-provider.tsx | 93 +++++++++++++++++++ .../components/scroll-to-bottom-button.tsx | 16 ++-- .../sections/deployment-domains-section.tsx | 25 ++--- .../sections/deployment-info-section.tsx | 8 +- .../sections/deployment-logs-section.tsx | 14 ++- .../use-deployment-sentinel-logs-query.ts | 8 +- .../deployments/[deploymentId]/layout.tsx | 4 +- .../deployments/[deploymentId]/page.tsx | 1 - .../components/environment-filter.tsx | 13 ++- .../components/promotion-dialog.tsx | 27 ++---- .../components/rollback-dialog.tsx | 25 ++--- ...nt-list-table-action.popover.constants.tsx | 14 +-- .../components/actions/promotion-dialog.tsx | 21 ++--- .../components/actions/rollback-dialog.tsx | 20 ++-- .../table/components/domain_list.tsx | 41 +++++--- .../components/table/deployments-list.tsx | 46 +++++---- .../components/table/utils/get-row-class.ts | 6 +- .../deployments/hooks/use-deployments.ts | 17 ++-- .../hooks/use-deployment-logs.tsx | 8 +- .../details/custom-domains-section/index.tsx | 14 ++- .../(overview)/details/domain-row.tsx | 9 +- .../env-variables-section/add-env-vars.tsx | 10 +- .../details/env-variables-section/index.tsx | 55 ++++++----- .../project-details-content.tsx | 27 +++--- .../sections/open-api-diff.tsx | 10 +- .../(overview)/layout-provider.tsx | 3 - .../(overview)/openapi-diff/page.tsx | 22 +++-- .../sentinel-logs-environment-filter.tsx | 13 ++- .../table/sentinel-log-details/index.tsx | 10 +- .../active-deployment-card/index.tsx | 20 ++-- .../components/region-flags-skeleton.tsx | 5 +- .../projects/[projectId]/layout.tsx | 75 +++++++-------- .../projects/[projectId]/page.tsx | 35 +++---- .../projects/_components/list/index.tsx | 4 +- web/apps/dashboard/components/ui/switch.tsx | 3 +- .../lib/collections/deploy/deployments.ts | 48 ++++++---- .../lib/collections/deploy/domains.ts | 46 ++++++--- .../lib/collections/deploy/environments.ts | 46 ++++++--- .../lib/collections/deploy/projects.ts | 2 +- .../dashboard/lib/collections/deploy/utils.ts | 78 ++++++++++++++++ web/apps/dashboard/lib/collections/index.ts | 70 ++------------ web/apps/dashboard/package.json | 4 +- web/pnpm-lock.yaml | 51 +++++----- 43 files changed, 622 insertions(+), 445 deletions(-) create mode 100644 web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/data-provider.tsx create mode 100644 web/apps/dashboard/lib/collections/deploy/utils.ts diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/data-provider.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/data-provider.tsx new file mode 100644 index 0000000000..a5935150a1 --- /dev/null +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/data-provider.tsx @@ -0,0 +1,93 @@ +"use client"; + +import { collection } from "@/lib/collections"; +import type { Deployment } from "@/lib/collections/deploy/deployments"; +import type { Domain } from "@/lib/collections/deploy/domains"; +import { eq, useLiveQuery } from "@tanstack/react-db"; +import { createContext, useContext, useMemo } from "react"; + +type ProjectDataContextType = { + // Cached project-level data + domains: Domain[]; + deployments: Deployment[]; + + isDomainsLoading: boolean; + isDeploymentsLoading: boolean; + + getDomainsForDeployment: (deploymentId: string) => Domain[]; + getLiveDomains: () => Domain[]; + getEnvironmentOrLiveDomains: () => Domain[]; + getDeploymentById: (id: string) => Deployment | undefined; + + refetchDomains: () => void; + refetchDeployments: () => void; + refetchAll: () => void; +}; + +const ProjectDataContext = createContext(null); + +export const ProjectDataProvider = ({ + children, + projectId, +}: { + children: React.ReactNode; + projectId: string; +}) => { + const domainsQuery = useLiveQuery( + (q) => + q + .from({ domain: collection.domains }) + .where(({ domain }) => eq(domain.projectId, projectId)) + .orderBy(({ domain }) => domain.createdAt, "desc"), + [projectId], + ); + + const deploymentsQuery = useLiveQuery( + (q) => + q + .from({ deployment: collection.deployments }) + .where(({ deployment }) => eq(deployment.projectId, projectId)) + .orderBy(({ deployment }) => deployment.createdAt, "desc"), + [projectId], + ); + + const value = useMemo(() => { + const domains = domainsQuery.data ?? []; + const deployments = deploymentsQuery.data ?? []; + + return { + domains, + deployments, + isDomainsLoading: domainsQuery.isLoading, + isDeploymentsLoading: deploymentsQuery.isLoading, + + getDomainsForDeployment: (deploymentId: string) => + domains.filter((d) => d.deploymentId === deploymentId), + + getLiveDomains: () => domains.filter((d) => d.sticky === "live"), + + getEnvironmentOrLiveDomains: () => + domains.filter((d) => d.sticky === "environment" || d.sticky === "live"), + + getDeploymentById: (id: string) => deployments.find((d) => d.id === id), + + refetchDomains: () => collection.domains.utils.refetch(), + refetchDeployments: () => collection.deployments.utils.refetch(), + refetchAll: () => { + collection.projects.utils.refetch(); + collection.deployments.utils.refetch(); + collection.domains.utils.refetch(); + }, + }; + }, [domainsQuery, deploymentsQuery]); + + return {children}; +}; + +export const useProjectData = () => { + const context = useContext(ProjectDataContext); + if (!context) { + throw new Error("useProjectData must be used within ProjectDataProvider"); + } + return context; +}; diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx index ec91e8ba88..efbb1bc93f 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/scroll-to-bottom-button.tsx @@ -1,4 +1,5 @@ "use client"; +import { collection } from "@/lib/collections"; import { eq, useLiveQuery } from "@tanstack/react-db"; import { ChevronDown } from "@unkey/icons"; import { cn } from "@unkey/ui/src/lib/utils"; @@ -8,13 +9,14 @@ import { useProject } from "../../../../layout-provider"; export function ScrollToBottomButton() { const params = useParams(); const deploymentId = params?.deploymentId as string; - const { collections } = useProject(); + const { projectId } = useProject(); const deployment = useLiveQuery( (q) => q - .from({ deployment: collections.deployments }) + .from({ deployment: collection.deployments }) + .where(({ deployment }) => eq(deployment.projectId, projectId)) .where(({ deployment }) => eq(deployment.id, deploymentId)), - [deploymentId], + [projectId, deploymentId], ); const isVisible = deployment.data.at(0)?.status !== "ready"; @@ -41,9 +43,7 @@ export function ScrollToBottomButton() { "overflow-hidden", "before:absolute before:inset-0 before:bg-gradient-to-r before:from-infoA-5 before:to-transparent before:-z-10", "after:absolute after:inset-0 after:bg-gray-1 after:dark:bg-black after:-z-20", - isVisible - ? "opacity-100 translate-y-0" - : "opacity-0 translate-y-4 pointer-events-none", + isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4 pointer-events-none", )} aria-label="Scroll to bottom of build logs" > @@ -54,9 +54,7 @@ export function ScrollToBottomButton() { animation: "shimmer 1.2s ease-in-out infinite", }} /> - - Building... - + Building... ); } diff --git a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/components/table/components/deployment-status-badge.tsx b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/components/table/components/deployment-status-badge.tsx index d7c7ada268..09701063e9 100644 --- a/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/components/table/components/deployment-status-badge.tsx +++ b/web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/components/table/components/deployment-status-badge.tsx @@ -93,31 +93,13 @@ export const DeploymentStatusBadge = ({ status, className }: DeploymentStatusBad )} > {animated && ( -
+
)} {label} - - {animated && ( - - )}
); }; diff --git a/web/apps/dashboard/tailwind.config.js b/web/apps/dashboard/tailwind.config.js index 1f8695729c..a599152c50 100644 --- a/web/apps/dashboard/tailwind.config.js +++ b/web/apps/dashboard/tailwind.config.js @@ -119,11 +119,16 @@ module.exports = { "background-position": "calc(100% + var(--shiny-width)) 0", }, }, + shimmer: { + "0%": { transform: "translateX(-100%)" }, + "100%": { transform: "translateX(100%)" }, + }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", "shiny-text": "shiny-text 10s infinite", + shimmer: "shimmer 1.2s ease-in-out infinite", }, fontFamily: { sans: ["var(--font-geist-sans)"],