-
Notifications
You must be signed in to change notification settings - Fork 610
feat: project details UI #3853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: project details UI #3853
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
2d568af
refactor: move deployments page
ogzhanolguncu 8470e9d
feat: add actions to nvabar
ogzhanolguncu 2419d7b
feat: add sub tab navigation
ogzhanolguncu 10357c8
feat: add details sectiopn
ogzhanolguncu d6f7a64
fix: build error
ogzhanolguncu d031471
refactor: sections
ogzhanolguncu f2bcb36
feat: add animated project details
ogzhanolguncu b97d800
feat: add active deployments section
ogzhanolguncu c40791f
feat: add domains section
ogzhanolguncu 0a27b46
feat: add build logs section
ogzhanolguncu d942a48
feat: add log ops
ogzhanolguncu 56f6d3e
feat: add env update section
ogzhanolguncu e3832dd
refactor: use proper layout
ogzhanolguncu 800de67
refactor: animations for envs
ogzhanolguncu 5276583
refactor: allow details open by default
ogzhanolguncu 5cb86b0
fix: details mount
ogzhanolguncu 558b0e4
fix: ui inconsistencies
ogzhanolguncu 7b49a8b
feat: get active project details from tRPC
ogzhanolguncu f44fd9e
feat: use tRPC
ogzhanolguncu 97c78e8
feat: add env fetch
ogzhanolguncu 3ae47b9
fix: import paths
ogzhanolguncu dcd5153
fix: import paths
ogzhanolguncu 82c3860
Merge branch 'main' into project-details-ui
ogzhanolguncu 294d449
fix: build issue
ogzhanolguncu 20aa3f4
fix: coderabbit issues
ogzhanolguncu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
apps/dashboard/app/(app)/projects/[projectId]/deployments/page.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| "use client"; | ||
|
|
||
| import { DeploymentsListControlCloud } from "./components/control-cloud"; | ||
| import { DeploymentsListControls } from "./components/controls"; | ||
| import { DeploymentsList } from "./components/table/deployments-list"; | ||
|
|
||
| export default function Deployments() { | ||
| return ( | ||
| <div className="flex flex-col"> | ||
| <DeploymentsListControls /> | ||
| <DeploymentsListControlCloud /> | ||
| <DeploymentsList /> | ||
| </div> | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ); | ||
| } | ||
12 changes: 12 additions & 0 deletions
12
apps/dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/card.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { cn } from "@unkey/ui/src/lib/utils"; | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| import type { ReactNode } from "react"; | ||
|
|
||
| export function Card({ | ||
| children, | ||
| className, | ||
| }: { | ||
| children: ReactNode; | ||
| className?: string; | ||
| }) { | ||
| return <div className={cn("border border-gray-4 w-full", className)}>{children}</div>; | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
34 changes: 34 additions & 0 deletions
34
...dashboard/app/(app)/projects/[projectId]/details/active-deployment-card/filter-button.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import type { IconProps } from "@unkey/icons/src/props"; | ||
| import { Button } from "@unkey/ui"; | ||
| import { cn } from "@unkey/ui/src/lib/utils"; | ||
|
|
||
| type FilterButtonProps = { | ||
| isActive: boolean; | ||
| count: number; | ||
| onClick: () => void; | ||
| icon: React.ComponentType<IconProps>; | ||
| label: string; | ||
| }; | ||
|
|
||
| export const FilterButton = ({ | ||
| isActive, | ||
| count, | ||
| onClick, | ||
| icon: Icon, | ||
| label, | ||
| }: FilterButtonProps) => ( | ||
| <Button | ||
| variant="primary" | ||
| className={cn( | ||
| "text-xs h-[26px] border-none hover:bg-grayA-4", | ||
| isActive ? "bg-gray-12 hover:bg-grayA-12" : "bg-grayA-3 text-grayA-9", | ||
| )} | ||
| onClick={onClick} | ||
| > | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <Icon size="sm-regular" className={isActive ? "" : "text-grayA-9"} /> | ||
| <span className={isActive ? "" : "text-grayA-9"}>{label}</span> | ||
| <div className="rounded size-[18px] flex items-center justify-center text-[10px] leading-4 bg-gray-4 text-black dark:text-white"> | ||
| {count} | ||
| </div> | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </Button> | ||
| ); | ||
162 changes: 162 additions & 0 deletions
162
...p/(app)/projects/[projectId]/details/active-deployment-card/hooks/use-deployment-logs.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| import { trpc } from "@/lib/trpc/client"; | ||
| import { format } from "date-fns"; | ||
| import { useEffect, useMemo, useRef, useState } from "react"; | ||
|
|
||
| type LogEntry = { | ||
| timestamp: string; | ||
| level?: "info" | "warning" | "error"; | ||
| message: string; | ||
| }; | ||
|
|
||
| type LogFilter = "all" | "errors" | "warnings"; | ||
|
|
||
| type UseDeploymentLogsProps = { | ||
| deploymentId: string; | ||
| }; | ||
|
|
||
| type UseDeploymentLogsReturn = { | ||
| // State | ||
| logFilter: LogFilter; | ||
| searchTerm: string; | ||
| isExpanded: boolean; | ||
| showFade: boolean; | ||
| // Computed | ||
| filteredLogs: LogEntry[]; | ||
| logCounts: { | ||
| total: number; | ||
| errors: number; | ||
| warnings: number; | ||
| }; | ||
| // Loading state | ||
| isLoading: boolean; | ||
| // Actions | ||
| setLogFilter: (filter: LogFilter) => void; | ||
| setSearchTerm: (term: string) => void; | ||
| setExpanded: (expanded: boolean) => void; | ||
| handleScroll: (e: React.UIEvent<HTMLDivElement>) => void; | ||
| handleFilterChange: (filter: LogFilter) => void; | ||
| handleSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void; | ||
| // Refs | ||
| scrollRef: React.RefObject<HTMLDivElement>; | ||
| }; | ||
|
|
||
| export function useDeploymentLogs({ | ||
| deploymentId, | ||
| }: UseDeploymentLogsProps): UseDeploymentLogsReturn { | ||
| const [logFilter, setLogFilter] = useState<LogFilter>("all"); | ||
| const [searchTerm, setSearchTerm] = useState(""); | ||
| const [isExpanded, setIsExpanded] = useState(false); | ||
| const [showFade, setShowFade] = useState(true); | ||
| const scrollRef = useRef<HTMLDivElement>(null); | ||
|
|
||
| // Fetch logs via tRPC | ||
| const { data: logsData, isLoading } = trpc.deploy.project.activeDeployment.buildLogs.useQuery({ | ||
| deploymentId, | ||
| }); | ||
|
|
||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Transform tRPC logs to match the expected format | ||
| const logs = useMemo((): LogEntry[] => { | ||
| if (!logsData?.logs) { | ||
| return []; | ||
| } | ||
|
|
||
| return logsData.logs.map((log) => ({ | ||
| timestamp: format(new Date(log.timestamp), "HH:mm:ss.SSS"), | ||
| level: log.level, | ||
| message: log.message, | ||
| })); | ||
| }, [logsData]); | ||
|
|
||
| // Auto-expand when logs are fetched | ||
| useEffect(() => { | ||
| if (logsData?.logs && logsData.logs.length > 0) { | ||
| setIsExpanded(true); | ||
| } | ||
| }, [logsData]); | ||
|
|
||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Calculate log counts | ||
| const logCounts = useMemo( | ||
| () => ({ | ||
| total: logs.length, | ||
| errors: logs.filter((log) => log.level === "error").length, | ||
| warnings: logs.filter((log) => log.level === "warning").length, | ||
| }), | ||
| [logs], | ||
| ); | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Filter logs by level and search term | ||
| const filteredLogs = useMemo(() => { | ||
| let filtered = logs; | ||
|
|
||
| // Apply level filter | ||
| if (logFilter === "errors") { | ||
| filtered = logs.filter((log) => log.level === "error"); | ||
| } else if (logFilter === "warnings") { | ||
| filtered = logs.filter((log) => log.level === "warning"); | ||
| } | ||
|
|
||
| // Apply search filter | ||
| if (searchTerm.trim()) { | ||
| filtered = filtered.filter( | ||
| (log) => | ||
| log.message.toLowerCase().includes(searchTerm.toLowerCase()) || | ||
| log.timestamp.includes(searchTerm) || | ||
| log.level?.toLowerCase().includes(searchTerm.toLowerCase()), | ||
| ); | ||
| } | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return filtered; | ||
| }, [logs, logFilter, searchTerm]); | ||
|
|
||
| const resetScroll = () => { | ||
| if (scrollRef.current) { | ||
| scrollRef.current.scrollTop = 0; | ||
| setShowFade(true); | ||
| } | ||
| }; | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const setExpanded = (expanded: boolean) => { | ||
| setIsExpanded(expanded); | ||
| if (!expanded) { | ||
| setTimeout(resetScroll, 50); | ||
| } | ||
| }; | ||
ogzhanolguncu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const handleScroll = (e: React.UIEvent<HTMLDivElement>) => { | ||
| const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; | ||
| const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1; | ||
| setShowFade(!isAtBottom); | ||
| }; | ||
|
|
||
| const handleFilterChange = (filter: LogFilter) => { | ||
| setLogFilter(filter); | ||
| resetScroll(); | ||
| }; | ||
|
|
||
| const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
| setSearchTerm(e.target.value); | ||
| resetScroll(); | ||
| }; | ||
|
|
||
| return { | ||
| // State | ||
| logFilter, | ||
| searchTerm, | ||
| isExpanded, | ||
| showFade, | ||
| // Computed | ||
| filteredLogs, | ||
| logCounts, | ||
| // Loading state | ||
| isLoading, | ||
| // Actions | ||
| setLogFilter, | ||
| setSearchTerm, | ||
| setExpanded, | ||
| handleScroll, | ||
| handleFilterChange, | ||
| handleSearchChange, | ||
| // Refs | ||
| scrollRef, | ||
| }; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.