feat(profile): redesign profile dashboard to match Editron theme#240
feat(profile): redesign profile dashboard to match Editron theme#240piyushdotcomm wants to merge 1 commit into
Conversation
- Rebuilt /dashboard/profile as a developer console. - Implemented compact project table with search, filter, and sort. - Styled heatmaps, analytics charts, and KPI cards with Editron red theme (#ef4444). - Added heatmap keyboard/ARIA support. - Disabled coming soon quick actions for a cleaner UI.
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
👋 Thanks for opening a PR, @piyushdotcomm!Your PR has entered the 🚦 PR Review Pipeline.
What happens next
A pipeline status comment will appear below and update automatically as your PR progresses. While you wait
This comment is posted only once. |
WalkthroughThe PR redesigns the profile dashboard page with a new sticky header and sidebar layout, introduces dynamic currentStreak calculation from heatmap activity data, refactors multiple components to remove animations and use static Tailwind styling, adds comprehensive filtering and sorting to the project table, and updates secondary analytics/activity widgets. Dashboard action routes are revalidated to target ChangesProfile Dashboard Redesign
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@pari-dubey1 @sidhacks check this out is it good or not. be honest |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
modules/profile/components/CompactProjectTable.tsx (1)
285-286:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd
relfor links opened in a new tab.Line 285 uses
target="_blank"withoutrel="noopener noreferrer", which leaves a reverse-tabnabbing surface.Suggested fix
-<Link href={`/playground/${project.id}`} target="_blank" className="flex items-center cursor-pointer"> +<Link + href={`/playground/${project.id}`} + target="_blank" + rel="noopener noreferrer" + className="flex items-center cursor-pointer" +>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modules/profile/components/CompactProjectTable.tsx` around lines 285 - 286, In CompactProjectTable, the Link that opens project details in a new tab (the Link with href={`/playground/${project.id}`} and target="_blank`, and the ExternalLink icon) must include rel="noopener noreferrer" to prevent reverse-tabnabbing; update that Link element (inside the CompactProjectTable component) to add the rel attribute with both noopener and noreferrer values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@modules/profile/components/CompactProjectTable.tsx`:
- Around line 84-85: project.template can be null/undefined causing
.toLowerCase()/.includes() to throw during filtering/sorting; update all uses in
CompactProjectTable (the filter using normalizedQuery and the sort comparator
referencing project.template) to guard the value by falling back to an empty
string (or use optional chaining + default) before calling
toLowerCase/localeCompare/includes so template-less projects don't break table
rendering.
- Around line 172-185: The filter buttons in CompactProjectTable do not expose
their selected state and the search input lacks an accessible name; update the
Button elements (where setProjectFilter and projectFilter are used) to include
an accessible state attribute (e.g., aria-pressed or aria-current="true" when
projectFilter === value) and ensure the search input element has an explicit
label or aria-label/aria-labelledby that conveys its purpose; also apply the
same accessible-state attribute to the other button group instance referenced
around lines 189-194 so assistive tech can detect which filter is active.
In `@modules/profile/components/ContributionHeatmap.tsx`:
- Line 40: The tooltip/ARIA date rendering in ContributionHeatmap uses new
Date(day.date).toDateString(), which converts the YYYY-MM-DD UTC key (created as
dateStr) into a local-time date and can shift by ±1 day; change the rendering to
format the date in UTC consistently (for example use Intl.DateTimeFormat with
timeZone: "UTC" or display the dateStr key directly) wherever day.date is passed
to toDateString() (the tooltip/ARIA text around the render functions at the
locations referencing day.date and the earlier dateStr generation) so displayed
dates match the UTC bucket keys.
In `@modules/profile/components/RunningEnvironments.tsx`:
- Line 41: The width calculation for the memory meter in RunningEnvironments.tsx
uses (runtime.memoryUsage / 512) * 100 and can produce values outside 0–100%;
clamp the computed percentage with Math.min/Math.max (e.g., percent =
Math.min(100, Math.max(0, (runtime.memoryUsage / 512) * 100))) and use that
clamped percent in the style on the <div> (the element with className "h-full
bg-red-500 rounded-full transition-all duration-500") so the rendered width is
always between "0%" and "100%".
---
Outside diff comments:
In `@modules/profile/components/CompactProjectTable.tsx`:
- Around line 285-286: In CompactProjectTable, the Link that opens project
details in a new tab (the Link with href={`/playground/${project.id}`} and
target="_blank`, and the ExternalLink icon) must include rel="noopener
noreferrer" to prevent reverse-tabnabbing; update that Link element (inside the
CompactProjectTable component) to add the rel attribute with both noopener and
noreferrer values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 2277acb1-be6a-4de3-9e94-2149173ec6a5
📒 Files selected for processing (11)
app/dashboard/profile/page.tsxmodules/dashboard/actions/index.tsmodules/profile/actions.tsmodules/profile/components/CompactProjectTable.tsxmodules/profile/components/ContributionHeatmap.tsxmodules/profile/components/HeaderNewProjectButton.tsxmodules/profile/components/KPIStats.tsxmodules/profile/components/RecentActivity.tsxmodules/profile/components/RunningEnvironments.tsxmodules/profile/components/SidebarWidgets.tsxmodules/profile/components/UsageAnalytics.tsx
| project.description?.toLowerCase().includes(normalizedQuery) || | ||
| project.template.toLowerCase().includes(normalizedQuery) |
There was a problem hiding this comment.
Guard template-based search/sort against nullable template values.
createPlayground can persist a project without a template for BLANK, so Line 85 and Line 91 can throw when template is null/undefined. This can break table rendering as soon as filter/sort runs.
Suggested fix
- const matchesSearch =
+ const templateValue = project.template ?? ""
+ const matchesSearch =
normalizedQuery.length === 0 ||
project.title.toLowerCase().includes(normalizedQuery) ||
project.description?.toLowerCase().includes(normalizedQuery) ||
- project.template.toLowerCase().includes(normalizedQuery)
+ templateValue.toLowerCase().includes(normalizedQuery)
...
- if (sortMode === "template") return a.template.localeCompare(b.template)
+ if (sortMode === "template") {
+ return (a.template ?? "").localeCompare(b.template ?? "")
+ }Also applies to: 90-91
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modules/profile/components/CompactProjectTable.tsx` around lines 84 - 85,
project.template can be null/undefined causing .toLowerCase()/.includes() to
throw during filtering/sorting; update all uses in CompactProjectTable (the
filter using normalizedQuery and the sort comparator referencing
project.template) to guard the value by falling back to an empty string (or use
optional chaining + default) before calling toLowerCase/localeCompare/includes
so template-less projects don't break table rendering.
| <Button | ||
| key={value} | ||
| type="button" | ||
| variant="ghost" | ||
| size="sm" | ||
| onClick={() => setProjectFilter(value as "all" | "starred" | "recent")} | ||
| className={`h-7 rounded-[5px] px-3 text-xs ${projectFilter === value | ||
| ? "bg-white text-[#171717] shadow-sm dark:bg-background dark:text-foreground" | ||
| : "text-[#4d4d4d] hover:text-[#171717] dark:text-muted-foreground dark:hover:text-foreground" | ||
| }`} | ||
| > | ||
| {label} | ||
| </Button> | ||
| ))} |
There was a problem hiding this comment.
Expose filter/search state more clearly to assistive tech.
The filter buttons don’t expose selected state, and the search input has no explicit accessible name.
Suggested fix
<Button
key={value}
type="button"
variant="ghost"
size="sm"
onClick={() => setProjectFilter(value as "all" | "starred" | "recent")}
+ aria-pressed={projectFilter === value}
+ aria-label={`Filter projects: ${label}`}
className={`h-7 rounded-[5px] px-3 text-xs ${projectFilter === value
...
<Input
value={searchQuery}
onChange={(event) => setSearchQuery(event.target.value)}
placeholder="Search projects..."
+ aria-label="Search projects"
className="h-9 rounded-md border-[`#ebebeb`] bg-white pl-9 text-sm shadow-none dark:border-border dark:bg-card"
/>Also applies to: 189-194
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modules/profile/components/CompactProjectTable.tsx` around lines 172 - 185,
The filter buttons in CompactProjectTable do not expose their selected state and
the search input lacks an accessible name; update the Button elements (where
setProjectFilter and projectFilter are used) to include an accessible state
attribute (e.g., aria-pressed or aria-current="true" when projectFilter ===
value) and ensure the search input element has an explicit label or
aria-label/aria-labelledby that conveys its purpose; also apply the same
accessible-state attribute to the other button group instance referenced around
lines 189-194 so assistive tech can detect which filter is active.
| const d = new Date(today); | ||
| d.setDate(d.getDate() - i); | ||
| const dateStr = d.toISOString().split('T')[0]; | ||
| const dateStr = d.toISOString().split("T")[0]; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In JavaScript, does new Date("YYYY-MM-DD")parse as UTC or local time, and cantoISOString().split("T")[0] cause off-by-one-day bugs in local time zones?
💡 Result:
Yes: new Date("YYYY-MM-DD") parses the date-only string as midnight UTC (then converts to a Date value/instant; displaying it locally can make the local calendar day appear one day earlier than expected). [1][2] Why the off-by-one happens 1) Date-only ISO strings are treated as UTC by the JavaScript parsing rules for the date-time string format: when the time zone designator is absent for a date-only form, the spec interpretation is UTC. [2] 2) toISOString() always formats the instant in UTC (it returns a string with suffix Z). [3] 3) If your intention is “get the local day as YYYY-MM-DD”, then doing new Date("YYYY-MM-DD").toISOString().split("T")[0] mixes “interpret as UTC” with “present as local day”. In negative UTC offsets (e.g., UTC-05:00), midnight UTC is still the previous local date, so the YYYY-MM-DD substring taken from the UTC ISO string can be shifted relative to the user’s local calendar day. This exact “one day off” behavior is described in examples where date-only strings are interpreted as UTC. [4] Can toISOString().split("T")[0] cause off-by-one-day bugs? Yes, when you’re trying to derive a date string for local time zones (or when the input date is meant to represent a local calendar day rather than a UTC moment). The off-by-one happens because the “day” boundary you’re using is UTC (via toISOString()), not the user’s local time zone. [3][4] Safer alternatives - If the YYYY-MM-DD input is meant to be a local calendar date, construct the date using local components instead of parsing a UTC date-only string: new Date(year, monthIndex, day) (month is 0-based). This avoids the UTC midnight assumption. - If you need an ISO-like YYYY-MM-DD in the user’s local time zone, don’t use toISOString(); format using local getters (getFullYear(), getMonth(), getDate()) or Intl.DateTimeFormat with an explicit timeZone as needed. (Reason: toISOString() is explicitly UTC.) [3] Concrete example of the failure mode If a user in UTC-05:00 runs: - new Date("2019-09-24") (interpreted as 2019-09-24T00:00:00Z), then local time is 2019-09-23 evening; displaying/deriving a local calendar day from that instant can appear “one day earlier”. [4] Sources: [1] MDN Date.parse; [2] TC39 proposal summarizing Date.parse behavior for date-only vs date-time; [3] MDN toISOString; [4] discussion of the one-day-off due to date-only parsing as UTC; MDN Date constructor notes local interpretation when using numeric components.
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
- 2: https://tc39.es/proposal-uniform-interchange-date-parsing/
- 3: https://learn.microsoft.com/en-us/openspecs/ie_standards/ms-es3/79e429c6-8d02-422b-ac7a-7e18b5892eaf
- 4: https://apisurfer.com/js-date-constructor-timezone-oddity
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="modules/profile/components/ContributionHeatmap.tsx"
# Show around the referenced line numbers with context
nl -ba "$FILE" | sed -n '1,160p' | sed -n '1,160p'Repository: piyushdotcomm/Editron
Length of output: 108
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="modules/profile/components/ContributionHeatmap.tsx"
awk 'NR>=20 && NR<=130 {printf "%6d:%s\n", NR, $0}' "$FILE"Repository: piyushdotcomm/Editron
Length of output: 6527
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "type HeatmapData|interface HeatmapData|HeatmapData" .
rg -n "ContributionHeatmap" modules/profile -S
rg -n "date:\s*.*toISOString\(\)|toISOString\(\)\.split\(\"T\"\)\[0\]|YYYY-MM-DD" . -SRepository: piyushdotcomm/Editron
Length of output: 812
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# ContributionHeatmap.tsx: interface + relevant date usage
FILE1="modules/profile/components/ContributionHeatmap.tsx"
awk 'NR>=1 && NR<=90 {printf "%5d:%s\n", NR, $0}' "$FILE1"
echo "----"
awk 'NR>=90 && NR<=160 {printf "%5d:%s\n", NR, $0}' "$FILE1"
echo "===="
# mock-data: how date strings are created
FILE2="modules/profile/data/mock-data.ts"
awk 'NR>=100 && NR<=190 {printf "%5d:%s\n", NR, $0}' "$FILE2"
echo "===="
# actions: how date strings are used for iteration/lookups
FILE3="modules/profile/actions.ts"
awk 'NR>=70 && NR<=140 {printf "%5d:%s\n", NR, $0}' "$FILE3"Repository: piyushdotcomm/Editron
Length of output: 14563
Prevent off-by-one day in ContributionHeatmap tooltip/ARIA by formatting UTC date keys consistently.
modules/profile/components/ContributionHeatmap.tsx line 40 generates UTC YYYY-MM-DD keys, but lines 95 and 111 render them via new Date(day.date).toDateString(). Since new Date("YYYY-MM-DD") is interpreted as midnight UTC and toDateString() displays in local time, the tooltip/ARIA date can shift by ±1 day for some time zones (while bucket/count mapping remains aligned). Format the displayed date in UTC (e.g., from day.date using Intl.DateTimeFormat with timeZone: "UTC" or by displaying the key directly) instead of new Date(day.date).toDateString().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modules/profile/components/ContributionHeatmap.tsx` at line 40, The
tooltip/ARIA date rendering in ContributionHeatmap uses new
Date(day.date).toDateString(), which converts the YYYY-MM-DD UTC key (created as
dateStr) into a local-time date and can shift by ±1 day; change the rendering to
format the date in UTC consistently (for example use Intl.DateTimeFormat with
timeZone: "UTC" or display the dateStr key directly) wherever day.date is passed
to toDateString() (the tooltip/ARIA text around the render functions at the
locations referencing day.date and the earlier dateStr generation) so displayed
dates match the UTC bucket keys.
| <span className="uppercase tracking-wider text-[10px] mb-1">MEM</span> | ||
| <div className="h-1.5 w-full bg-secondary rounded-full overflow-hidden"> | ||
| <div className="h-full bg-blue-500 rounded-full transition-all duration-500" style={{ width: `${(runtime.memoryUsage / 512) * 100}%` }} /> | ||
| <div className="h-full bg-red-500 rounded-full transition-all duration-500" style={{ width: `${(runtime.memoryUsage / 512) * 100}%` }} /> |
There was a problem hiding this comment.
Clamp memory progress width to valid bounds.
Line 41 can render widths outside 0–100% when runtime.memoryUsage is out of expected range, which can misrepresent the meter. Clamp before rendering.
Proposed fix
- <div className="h-full bg-red-500 rounded-full transition-all duration-500" style={{ width: `${(runtime.memoryUsage / 512) * 100}%` }} />
+ <div
+ className="h-full bg-red-500 rounded-full transition-all duration-500"
+ style={{ width: `${Math.min(100, Math.max(0, (runtime.memoryUsage / 512) * 100))}%` }}
+ />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className="h-full bg-red-500 rounded-full transition-all duration-500" style={{ width: `${(runtime.memoryUsage / 512) * 100}%` }} /> | |
| <div | |
| className="h-full bg-red-500 rounded-full transition-all duration-500" | |
| style={{ width: `${Math.min(100, Math.max(0, (runtime.memoryUsage / 512) * 100))}%` }} | |
| /> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modules/profile/components/RunningEnvironments.tsx` at line 41, The width
calculation for the memory meter in RunningEnvironments.tsx uses
(runtime.memoryUsage / 512) * 100 and can produce values outside 0–100%; clamp
the computed percentage with Math.min/Math.max (e.g., percent = Math.min(100,
Math.max(0, (runtime.memoryUsage / 512) * 100))) and use that clamped percent in
the style on the <div> (the element with className "h-full bg-red-500
rounded-full transition-all duration-500") so the rendered width is always
between "0%" and "100%".
|
This one looks clean and goes well with the current theme, good work looks really impressive |
Description
This PR introduces a complete redesign of the /dashboard/profile page, transforming it into a developer console that fully integrates the Editron red theme.
Changes Included
ed-500\ (#ef4444) theme across charts, heatmaps, KPI stats, and UI interactions.
Summary by CodeRabbit
New Features
Style