diff --git a/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/active-deployment-card-empty.tsx b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/active-deployment-card-empty.tsx new file mode 100644 index 0000000000..290a8d990f --- /dev/null +++ b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/active-deployment-card-empty.tsx @@ -0,0 +1,48 @@ +import { Cloud, Plus } from "@unkey/icons"; +import { Button, Card } from "@unkey/ui"; +import { cn } from "@unkey/ui/src/lib/utils"; + +type Props = { + onCreateDeployment?: () => void; + className?: string; +}; + +export const ActiveDeploymentCardEmpty = ({ onCreateDeployment, className }: Props) => ( + +
+ {/* Icon with subtle animation */} +
+
+
+ +
+
+ + {/* Content */} +
+

No active deployments

+

+ Your deployments will appear here once you push code to your connected repository or + trigger a manual deployment. +

+
+ + {/* Action button */} + {onCreateDeployment && ( + + )} +
+ +); diff --git a/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/hooks/use-deployment-logs.tsx b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/hooks/use-deployment-logs.tsx index 6fb74ff464..7640dcba46 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/hooks/use-deployment-logs.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/hooks/use-deployment-logs.tsx @@ -23,7 +23,7 @@ type LogEntry = { type LogFilter = "all" | "warnings" | "errors"; type UseDeploymentLogsProps = { - deploymentId: string; + deploymentId: string | null; showBuildSteps: boolean; }; @@ -61,9 +61,12 @@ export function useDeploymentLogs({ const { queryTime: timestamp } = useQueryTime(); const { data: buildData, isLoading: buildLoading } = trpc.deploy.deployment.buildSteps.useQuery( - { deploymentId }, { - enabled: showBuildSteps && isExpanded, + // without this check TS yells at us + deploymentId: deploymentId ?? "", + }, + { + enabled: showBuildSteps && isExpanded && Boolean(deploymentId), refetchInterval: BUILD_STEPS_REFETCH_INTERVAL, }, ); diff --git a/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/index.tsx b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/index.tsx index 8868af4fb8..f82e7f4dec 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/index.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/index.tsx @@ -18,6 +18,7 @@ import { cn } from "@unkey/ui/src/lib/utils"; import { format } from "date-fns"; import { useProjectLayout } from "../../layout-provider"; import { Card } from "../card"; +import { ActiveDeploymentCardEmpty } from "./active-deployment-card-empty"; import { FilterButton } from "./filter-button"; import { Avatar } from "./git-avatar"; import { useDeploymentLogs } from "./hooks/use-deployment-logs"; @@ -68,15 +69,17 @@ export const statusIndicator = ( }; type Props = { - deploymentId: string; + deploymentId: string | null; }; export const ActiveDeploymentCard = ({ deploymentId }: Props) => { const { collections } = useProjectLayout(); - const { data } = useLiveQuery((q) => - q - .from({ deployment: collections.deployments }) - .where(({ deployment }) => eq(deployment.id, deploymentId)), + const { data, isLoading } = useLiveQuery( + (q) => + q + .from({ deployment: collections.deployments }) + .where(({ deployment }) => eq(deployment.id, deploymentId)), + [deploymentId], ); const deployment = data.at(0); @@ -101,9 +104,12 @@ export const ActiveDeploymentCard = ({ deploymentId }: Props) => { showBuildSteps, }); - if (!deployment) { + if (isLoading) { return ; } + if (!deployment) { + return ; + } const statusConfig = statusIndicator(deployment.status); diff --git a/apps/dashboard/app/(app)/projects/[projectId]/details/domain-row.tsx b/apps/dashboard/app/(app)/projects/[projectId]/details/domain-row.tsx index ebe3d05f08..b51404bb6d 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/details/domain-row.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/details/domain-row.tsx @@ -1,6 +1,7 @@ import { CircleCheck, Link4, ShareUpRight } from "@unkey/icons"; import { Badge } from "@unkey/ui"; import Link from "next/link"; +import { Card } from "./card"; type DomainRowProps = { domain: string; @@ -28,3 +29,47 @@ export function DomainRow({ domain }: DomainRowProps) {
); } + +export const DomainRowSkeleton = () => { + return ( +
+
+ +
+ +
+
+
+
+
+
+ ); +}; + +export const DomainRowEmpty = () => ( + +
+ {/* Icon with subtle animation */} +
+
+
+ +
+
+ {/* Content */} +
+

No domains found

+

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

+
+
+ +); diff --git a/apps/dashboard/app/(app)/projects/[projectId]/layout.tsx b/apps/dashboard/app/(app)/projects/[projectId]/layout.tsx index f36b35cc83..8fc0d55165 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/layout.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/layout.tsx @@ -1,5 +1,6 @@ "use client"; import { collectionManager } from "@/lib/collections"; +import { eq, useLiveQuery } from "@tanstack/react-db"; import { DoubleChevronLeft } from "@unkey/icons"; import { Button, InfoTooltip } from "@unkey/ui"; import { useState } from "react"; @@ -25,10 +26,23 @@ type ProjectLayoutProps = { const ProjectLayout = ({ projectId, children }: ProjectLayoutProps) => { const [tableDistanceToTop, setTableDistanceToTop] = useState(0); - const [isDetailsOpen, setIsDetailsOpen] = useState(true); + const [isDetailsOpen, setIsDetailsOpen] = useState(false); const collections = collectionManager.getProjectCollections(projectId); + const projects = useLiveQuery((q) => + q.from({ project: collections.projects }).where(({ project }) => eq(project.id, projectId)), + ); + + const liveDeploymentId = projects.data.at(0)?.liveDeploymentId; + + const getTooltipContent = () => { + if (!liveDeploymentId) { + return "No deployments available. Deploy your project to view details."; + } + return isDetailsOpen ? "Hide deployment details" : "Show deployment details"; + }; + return ( { detailsExpandableTrigger={ {
diff --git a/apps/dashboard/app/(app)/projects/[projectId]/navigations/project-navigation.tsx b/apps/dashboard/app/(app)/projects/[projectId]/navigations/project-navigation.tsx index 0dd3e89dde..44c7ab8db4 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/navigations/project-navigation.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/navigations/project-navigation.tsx @@ -74,16 +74,18 @@ export const ProjectNavigation = ({ projectId }: ProjectNavigationProps) => {
{activeProject.gitRepositoryUrl && ( -
- - Auto-deploys from pushes to - -
+ <> +
+ + Auto-deploys from pushes to + +
+ + )} -
Visit Project URL