feat: implement new layout components and enhance UI with glassmorphism#252
feat: implement new layout components and enhance UI with glassmorphism#252SuperComboGamer wants to merge 1 commit intomainfrom
Conversation
This commit introduces a new app layout structure with an AppLayout component, a TopHeader for improved navigation, and a Sidebar for project management. Additionally, it adds GlassPanel and GlassCard components to enhance the UI with a glassmorphism effect. The Kanban board and agent views have been updated to utilize these new components, improving the overall user experience and visual consistency across the application.
📝 WalkthroughWalkthroughThis PR introduces a comprehensive redesign of the UI layer, adding new layout primitives (AppLayout, TopHeader, GlassCard, GlassPanel), restructuring multiple views to use these components, simplifying the Sidebar, completely rewriting the global stylesheet with a token-based theme system, and extending the app store with planning and Claude-related fields. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @SuperComboGamer, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a comprehensive UI/UX refresh, establishing a new, consistent application layout and a modern glassmorphism aesthetic. It introduces foundational layout components and reusable glass-effect UI elements, which are then integrated across key application views like the Kanban board and agent interfaces. The changes aim to provide a more cohesive and visually appealing user experience, supported by a revamped global styling approach. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a significant and impressive UI overhaul, implementing a new layout system and a consistent glassmorphism design across the application. The new components like AppLayout, TopHeader, GlassPanel, and GlassCard are well-structured and greatly improve the visual consistency. The refactoring of existing views to use these new components is clean and effective, especially the simplification of the Sidebar component. I've identified a few areas for improvement, mainly concerning hardcoded values that need to be made dynamic, a minor bug with a fallback icon, and some type safety issues that should be addressed.
| <div className="px-5 pb-6 space-y-4 flex-shrink-0"> | ||
| <div className="grid grid-cols-4 gap-2"> | ||
| <button className="col-span-2 bg-dark-850/60 hover:bg-dark-700 text-slate-200 py-2 px-3 rounded-lg border border-white/5 flex items-center justify-center gap-2 transition text-xs font-medium shadow-lg shadow-black/20 group"> | ||
| <Plus className="w-3.5 h-3.5 group-hover:text-brand-cyan transition-colors" /> New | ||
| </button> | ||
| <button className="col-span-1 bg-dark-850/60 hover:bg-dark-700 text-slate-400 hover:text-white py-2 rounded-lg border border-white/5 flex items-center justify-center transition"> | ||
| <Folder className="w-3.5 h-3.5" /> | ||
| <span className="ml-1 text-[10px]">0</span> | ||
| </button> | ||
| <button className="col-span-1 bg-dark-850/60 hover:bg-dark-700 text-slate-400 hover:text-white py-2 rounded-lg border border-white/5 flex items-center justify-center transition relative"> | ||
| <Bell className="w-3.5 h-3.5" /> | ||
| <span className="absolute top-2 right-2.5 w-1.5 h-1.5 bg-brand-red rounded-full ring-2 ring-dark-850"></span> | ||
| </button> | ||
| </div> | ||
|
|
||
| {/* Project Selector */} | ||
| <div className="bg-dark-850/40 border border-white/5 rounded-xl p-1 flex items-center justify-between cursor-pointer hover:border-white/10 hover:bg-dark-850/60 transition group"> | ||
| <div className="flex items-center gap-3 px-2 py-1.5"> | ||
| <FolderOpen className="w-4 h-4 text-brand-cyan group-hover:text-cyan-300 transition" /> | ||
| <span className="text-white font-medium text-sm">test case 1</span> | ||
| </div> | ||
| <div className="flex items-center gap-1 pr-1"> | ||
| <span className="w-5 h-5 rounded bg-dark-700 flex items-center justify-center text-[10px] text-slate-400 font-bold border border-white/5"> | ||
| P | ||
| </span> | ||
| <MoreVertical className="w-4 h-4 text-slate-500" /> | ||
| </div> | ||
| </div> | ||
| </div> |
| <span className="flex h-5 w-5 items-center justify-center rounded-full bg-brand-cyan text-[10px] text-black font-bold shadow-glow-cyan"> | ||
| 3 | ||
| </span> |
| <header className="h-16 glass-header flex items-center justify-between px-8 flex-shrink-0 z-20"> | ||
| <div> | ||
| <h1 className="text-white font-bold text-lg tracking-tight">Kanban Board</h1> | ||
| <p className="text-xs text-slate-500 font-medium font-mono mt-0.5">test case 1</p> | ||
| </div> | ||
|
|
||
| <div className="flex items-center gap-4"> | ||
| {/* User Toggle */} | ||
| <div className="flex items-center bg-dark-850/60 rounded-lg p-1 border border-white/5 h-9 shadow-inner-light"> | ||
| <div className="flex items-center gap-3 px-2 border-r border-white/5 h-full mr-2"> | ||
| <Users className="w-3.5 h-3.5 text-slate-400" /> | ||
| {/* Toggle Switch */} | ||
| <div className="w-[28px] h-[16px] bg-[#2d3546] rounded-full relative cursor-pointer border border-white/10 transition-colors"> | ||
| <div className="absolute top-[2px] right-[2px] w-[10px] h-[10px] bg-brand-cyan rounded-full shadow-[0_0_6px_rgba(6,182,212,0.6)]"></div> | ||
| </div> | ||
| </div> | ||
| <span className="text-xs text-slate-400 px-1 font-mono">3</span> | ||
| </div> | ||
|
|
||
| {/* Auto Mode */} | ||
| <button className="flex items-center gap-2 text-slate-300 hover:text-white px-3 py-1.5 rounded-lg border border-white/5 bg-dark-850/60 hover:bg-dark-700 transition text-xs font-medium h-9"> | ||
| <Play className="w-3.5 h-3.5 fill-current" /> | ||
| <span>Auto Mode</span> | ||
| </button> | ||
|
|
||
| {/* Add Feature */} | ||
| <button className="flex items-center gap-2 bg-brand-cyan hover:bg-cyan-400 text-dark-950 font-bold px-4 py-1.5 rounded-lg transition shadow-glow-cyan text-xs h-9 btn-hover-effect"> | ||
| <Plus className="w-4 h-4" /> | ||
| <span>Add Feature</span> | ||
| </button> | ||
| </div> | ||
| </header> |
There was a problem hiding this comment.
The TopHeader component has some hardcoded text and non-functional UI elements. The project name 'test case 1' and user count '3' should be dynamic. The user toggle switch is currently a static element and needs an onClick handler and state management to be functional. The 'Auto Mode' and 'Add Feature' buttons also lack functionality.
| {/* Fallback to SVG if i tag fails */} | ||
| <svg | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| width="14" | ||
| height="14" | ||
| viewBox="0 0 24 24" | ||
| fill="none" | ||
| stroke="currentColor" | ||
| strokeWidth="2" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| className="lucide lucide-trash w-3.5 h-3.5" | ||
| > | ||
| <path d="M3 6h18" /> | ||
| <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" /> | ||
| <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" /> | ||
| </svg> |
| const { orderedFeatures } = resolveDependencies(map.backlog as any) as { | ||
| orderedFeatures: Feature[]; | ||
| }; |
There was a problem hiding this comment.
The use of as any here bypasses type safety. It seems resolveDependencies expects a different Feature type than what's provided. To maintain type safety, consider mapping the features to the expected type before passing them to the function, or making resolveDependencies generic if you control its source. For example: resolveDependencies(map.backlog as BaseFeature[]) if that's the expected type.
|
|
||
| for (const f of orderedFeatures) { | ||
| if (getBlockingDependencies(f, allFeatures).length > 0) { | ||
| if (getBlockingDependencies(f as any, allFeatures as any).length > 0) { |
There was a problem hiding this comment.
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (1)
33-36: Props declared in interface but not destructured.
opacity,glassmorphism,cardBorderEnabled, andcardBorderOpacityare defined inKanbanCardProps(lines 33-36) but are not destructured in the function parameters (line 59 ends atsummary). This creates a misleading API where callers can pass these props with no effect.Either remove from the interface or implement the functionality.
🔎 Remove unused props from interface
interface KanbanCardProps { // ... other props summary?: string; - opacity?: number; - glassmorphism?: boolean; - cardBorderEnabled?: boolean; - cardBorderOpacity?: number; }Also applies to: 59-59
apps/ui/src/store/app-store.ts (1)
547-577: Wire Claude usage actions intoAppActionsand persist the refresh intervalThe Claude usage state/actions are well-structured, but two follow-ups are needed:
AppActionsis missing the new action signatures (type error)
setClaudeRefreshInterval,setClaudeUsageLastUpdated, andsetClaudeUsageare implemented in the store but not declared inAppActions.- With
create<AppState & AppActions>(), this object literal will have excess properties and anyuseAppStore((s) => s.setClaudeUsage)call will not type‑check.
claudeRefreshIntervalis a preference but not persisted
partializecurrently omitsclaudeRefreshInterval, so user changes revert to60on reload.Proposed typings & persistence fixes
@@ export interface AppActions { @@ // Plan Approval actions setPendingPlanApproval: ( @@ ) => void; + + // Claude Usage Tracking actions + setClaudeRefreshInterval: (interval: number) => void; + setClaudeUsageLastUpdated: (timestamp: number | null) => void; + setClaudeUsage: (usage: ClaudeUsage | null) => void; @@ // Claude Usage Tracking actions - setClaudeRefreshInterval: (interval: number) => set({ claudeRefreshInterval: interval }), - setClaudeUsageLastUpdated: (timestamp: number) => set({ claudeUsageLastUpdated: timestamp }), - setClaudeUsage: (usage: ClaudeUsage | null) => + setClaudeRefreshInterval: (interval) => set({ claudeRefreshInterval: interval }), + setClaudeUsageLastUpdated: (timestamp) => + set({ claudeUsageLastUpdated: timestamp }), + setClaudeUsage: (usage) => set({ claudeUsage: usage, claudeUsageLastUpdated: usage ? Date.now() : null, }), @@ partialize: (state) => ({ @@ defaultPlanningMode: state.defaultPlanningMode, defaultRequirePlanApproval: state.defaultRequirePlanApproval, defaultAIProfileId: state.defaultAIProfileId, + claudeRefreshInterval: state.claudeRefreshInterval, // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any,Also applies to: 586-613, 905-909, 2571-2577, 2674-2723
🧹 Nitpick comments (8)
apps/ui/src/components/layout/sidebar.tsx (1)
172-212: Consider extracting NavItem to a separate file.The local
NavItemcomponent is well-implemented but differs from theNavIteminterface inapps/ui/src/components/layout/sidebar/types.ts(which usesidinstead oftoandisActive). This could cause confusion.Consider either:
- Extracting this component to its own file
- Aligning with the existing
NavItemtype interfaceapps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (1)
149-151: Hardcoded fallback model name.The fallback
'Opus 4.2'should use a constant (likeDEFAULT_MODELfrom@/lib/agent-context-parser) for consistency and maintainability.🔎 Suggested fix
+import { DEFAULT_MODEL, formatModelName } from '@/lib/agent-context-parser'; + // In JSX: <span className="text-[10px] text-brand-cyan font-mono"> - {feature.model || 'Opus 4.2'} + {formatModelName(feature.model ?? DEFAULT_MODEL)} </span>apps/ui/src/styles/global.css (1)
4-71: Tokenized theme & glass utilities look solid; consider aligning backdrop-filter prefixesThe centralized
@themetokens andglass-*utilities are structured well and line up with the new layout/components. One minor consistency tweak you might consider later:
glass-sidebar,glass-header, andglass-carddefine bothbackdrop-filterand-webkit-backdrop-filter, butglass-panelonly setsbackdrop-filter. For Safari parity, you may want to add the-webkit-prefix there as well, unless you’re relying entirely on Lightning CSS to inject it.Also applies to: 73-142, 144-150, 152-168
apps/ui/src/components/views/board-view.tsx (2)
20-21: TopHeader is purely presentational here; consider making it data‑drivenRight now
TopHeaderrenders a hard-coded “Kanban Board” title, subtitle, and static Auto Mode/Add Feature controls, without any connection to this view’s actual state or handlers.If this header is meant to be reused across views (as in other files in this PR), it would scale better as a data‑driven component, e.g.:
- Accept
title/subtitleprops instead of hard-coding “Kanban Board” / “test case 1”.- Accept callbacks like
onToggleAutoModeandonAddFeatureand wire them to the real board actions.Not blocking, but moving this direction will avoid duplicate/placeholder controls and mismatched titles across views.
Also applies to: 922-924
265-275: Tighten upbranchCardCountstyping to avoid unnecessary castsThe
reduceimplementation is correct, but this line:const branch = (feature.branchName as string) ?? 'main';relies on a cast that isn’t needed and can hide null/undefined at the type level.
You can let types reflect the runtime behavior more directly:
- const branch = (feature.branchName as string) ?? 'main'; + const branch = feature.branchName ?? 'main';This keeps the same semantics (nullish =>
'main') while preserving accurate types forbranchName.apps/ui/src/components/views/settings-view.tsx (1)
70-81: Unify theme types instead of relying on a cast
handleSetThemeis typed against the store’sthemevalue and then cast to(theme: Theme) => voidforAppearanceSection. That’s safe as long asThemeand the store’s theme type stay in sync, but the cast will mask future drift.If possible, prefer a single shared
Theme/ThemeModetype (re-exported from the store or settings types) so bothSettingsViewandAppearanceSectionuse the same source of truth and the cast isn’t needed.Also applies to: 110-114
apps/ui/src/components/layout/top-header.tsx (1)
1-38: GeneralizeTopHeaderand wire it to real actionsThe visual implementation and use of the new glass/brand utilities are good, but as a shared layout piece:
- Title/subtitle are hard-coded to “Kanban Board” / “test case 1”.
- The user toggle, Auto Mode button, and Add Feature button are purely decorative—no props or callbacks, and the toggle isn’t even a semantic control.
Given this header is imported in multiple views, consider:
- Adding props for
title,subtitle, and handler callbacks (onToggleUsers,onToggleAutoMode,onAddFeature, etc.).- Converting the toggle markup into a
<button>(or similar) with appropriate ARIA attributes if it’s meant to be interactive.That will avoid misleading headers and dead controls as the layout is reused.
apps/ui/src/components/views/board-view/components/kanban-column.tsx (1)
64-72: Clarify the accent-to-color mapping for status dots.The mapping seems inconsistent:
accent === 'blue'renders an orange dot (bg-brand-orange) with the comment "In Progress has orange dot in design". This creates a disconnect between the semantic meaning of theaccentprop and the actual visual output.Consider either:
- Renaming the accent values to match their visual purpose (e.g.,
'in-progress'instead of'blue')- Or documenting this intentional mapping in the interface/component comments
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (24)
apps/ui/src/components/layout/app-layout.tsxapps/ui/src/components/layout/sidebar.tsxapps/ui/src/components/layout/top-header.tsxapps/ui/src/components/ui/glass-card.tsxapps/ui/src/components/ui/glass-panel.tsxapps/ui/src/components/views/agent-tools-view.tsxapps/ui/src/components/views/agent-view.tsxapps/ui/src/components/views/board-view.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-header.tsxapps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsxapps/ui/src/components/views/board-view/components/kanban-column.tsxapps/ui/src/components/views/board-view/constants.tsapps/ui/src/components/views/board-view/hooks/use-board-column-features.tsapps/ui/src/components/views/board-view/kanban-board.tsxapps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsxapps/ui/src/components/views/running-agents-view.tsxapps/ui/src/components/views/settings-view.tsxapps/ui/src/components/views/terminal-view.tsxapps/ui/src/components/views/terminal-view/terminal-panel.tsxapps/ui/src/config/terminal-themes.tsapps/ui/src/routes/__root.tsxapps/ui/src/store/app-store.tsapps/ui/src/styles/global.cssindex (28).html
🧰 Additional context used
🧬 Code graph analysis (10)
apps/ui/src/components/ui/glass-card.tsx (1)
apps/ui/src/lib/utils.ts (1)
cn(5-7)
apps/ui/src/components/views/board-view/hooks/use-board-column-features.ts (2)
apps/ui/src/store/app-store.ts (1)
Feature(267-294)apps/server/src/services/feature-loader.ts (1)
Feature(20-20)
apps/ui/src/components/views/board-view/components/kanban-column.tsx (2)
apps/ui/src/components/ui/glass-panel.tsx (1)
GlassPanel(8-27)apps/ui/src/lib/utils.ts (1)
cn(5-7)
apps/ui/src/components/layout/app-layout.tsx (1)
apps/ui/src/components/layout/sidebar.tsx (1)
Sidebar(23-170)
apps/ui/src/components/layout/sidebar.tsx (2)
apps/ui/src/components/layout/sidebar/types.ts (1)
NavItem(9-14)apps/ui/src/lib/utils.ts (1)
cn(5-7)
apps/ui/src/routes/__root.tsx (1)
apps/ui/src/components/layout/app-layout.tsx (1)
AppLayout(9-36)
apps/ui/src/components/views/board-view.tsx (1)
apps/ui/src/components/layout/top-header.tsx (1)
TopHeader(3-38)
apps/ui/src/components/views/terminal-view.tsx (3)
apps/ui/src/components/layout/top-header.tsx (1)
TopHeader(3-38)apps/ui/src/components/ui/glass-panel.tsx (1)
GlassPanel(8-27)apps/ui/src/lib/utils.ts (1)
cn(5-7)
apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (5)
apps/ui/src/components/ui/glass-card.tsx (1)
GlassCard(8-25)apps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsx (2)
CardBadges(38-122)PriorityBadges(128-244)apps/ui/src/components/views/board-view/components/kanban-card/card-header.tsx (1)
CardHeaderSection(37-314)apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx (1)
CardContentSections(9-50)apps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsx (1)
AgentInfoPanel(46-273)
apps/ui/src/components/views/agent-tools-view.tsx (4)
apps/ui/src/components/layout/top-header.tsx (1)
TopHeader(3-38)apps/ui/src/components/ui/glass-panel.tsx (1)
GlassPanel(8-27)apps/ui/src/components/ui/glass-card.tsx (1)
GlassCard(8-25)apps/ui/src/lib/utils.ts (1)
cn(5-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: e2e
🔇 Additional comments (29)
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (2)
3-3: LGTM! React import added for type support.The React import is correctly added to support the
React.ReactNodetype used on line 91. Modern React doesn't require this import for JSX rendering, but it's necessary for TypeScript type references.
91-91: LGTM! Type widening improves flexibility.The type change from
JSX.Element | nulltoReact.ReactNode | nullis a safe enhancement that maintains current behavior while allowing more flexible badge content in the future (e.g., text nodes, fragments, or arrays). This follows React conventions whereReactNodeis the standard type for renderable content.apps/ui/src/config/terminal-themes.ts (1)
64-64: Transparent terminal background may cause readability issues.With
background: 'transparent', terminal text visibility depends entirely on the parent container's glassmorphism backdrop. If the terminal is rendered outside a properly styled glass container, text may become unreadable.Consider adding a fallback or documenting the requirement that terminals must be wrapped in a glassmorphism-styled container.
apps/ui/src/components/layout/app-layout.tsx (1)
9-36: Clean layout structure with proper layering.The AppLayout component properly implements the glassmorphism foundation with:
- Ambient background blobs at
z-0- Main content elevated at
z-10- Sidebar integration
- Proper overflow handling
The comment noting TopHeader is now view-specific is helpful for maintainability.
apps/ui/src/components/ui/glass-card.tsx (1)
8-26: Well-structured GlassCard component.The implementation correctly uses
forwardReffor ref forwarding, applies variant-based classes conditionally, and allows className overrides via thecnutility.Minor consideration: The base
rounded-xl p-4classes are always applied. If a consumer needs different padding/rounding, they'd need to use!importantor override classes. This is likely acceptable for design consistency.apps/ui/src/components/views/board-view/constants.ts (1)
5-29: Clean extension of COLUMNS with accent property.The accent mapping logically aligns with column semantics and integrates well with the new GlassPanel/GlassCard styling system. The inline type definition keeps related code together.
index (28).html (1)
1-21: Clarify the purpose and location of this HTML prototype file.This static HTML file appears to be a design prototype that duplicates the glassmorphism styling and Kanban layout implemented in the React components. Key concerns:
- File naming:
index (28).htmlis non-standard (spaces and parentheses)- Location: Should be in a
/docs,/design, or/prototypesdirectory- Maintenance burden: Style definitions duplicate those in
global.cssand components, risking driftIs this intended as documentation, a design reference, or should it be removed before merge?
apps/ui/src/store/app-store.ts (1)
15-22: Planning-related Feature extensions look consistentThe new type exports, optional
steps, andPlanSpec/planning fields onFeatureare coherent and match how planning/approval is handled elsewhere. No correctness issues stand out here.Also applies to: 267-293, 305-317
apps/ui/src/components/views/board-view/kanban-board.tsx (1)
100-105: Accent forwarding intoKanbanColumnis correctPassing
accent={column.accent}keeps the board data-driven and lets columns pick up the new accent styling without affecting behavior. Looks good.apps/ui/src/components/views/terminal-view/terminal-panel.tsx (1)
535-547: Transparency enablement for xterm matches the new glass UISetting
allowTransparency: trueon theTerminaland driving the container background fromcurrentTerminalTheme.backgroundis consistent with the glassmorphism layout. No issues spotted here.Also applies to: 2066-2074
apps/ui/src/routes/__root.tsx (1)
3-4: Root layout migration toAppLayoutlooks correctWrapping non-setup routes in
AppLayoutand switching the inner container toh-fullunder that shell is consistent with the new global layout. The streamer panel z-index bump toz-50should also help avoid it being hidden behind new glass headers.Also applies to: 161-178
apps/ui/src/components/views/terminal-view.tsx (3)
49-50: LGTM!Clean imports of the new layout primitives that align with the PR's glassmorphism design system.
1419-1424: LGTM!The new layout structure using
TopHeaderandGlassPanelis well-organized and consistent with other views in this PR.
1590-1623: LGTM!The conditional rendering for active tab content, empty states, and no-tabs states is well-structured with appropriate fallbacks and actionable UI elements.
apps/ui/src/components/ui/glass-panel.tsx (1)
1-28: LGTM!Clean, well-structured component implementation. Good use of
forwardReffor ref forwarding, proper TypeScript interface extension, and the accent variant pattern aligns well with the glassmorphism design system.apps/ui/src/components/views/running-agents-view.tsx (2)
3-4: LGTM!Imports align with the new layout system established in this PR.
107-223: LGTM!Well-structured refactor using the new glassmorphism components. The responsive grid layout (
grid-cols-1 md:grid-cols-2 xl:grid-cols-3) provides good scaling, and the agent cards have clear visual hierarchy with status indicators and actions.apps/ui/src/components/views/agent-view.tsx (5)
53-54: LGTM!Clean imports for the new layout primitives.
496-514: LGTM!The new layout structure with
TopHeaderand collapsible session manager sidebar is well-organized. TheGlassPanelwrapping provides consistent styling with other views.
515-620: LGTM!The chat header with model selector, tool indicator, and action buttons is well-structured. The conditional rendering for connection status and current tool provides good user feedback.
621-779: LGTM!Message rendering is preserved with updated styling. The avatar/bubble layout, image attachment display, thinking indicator, and scroll handling are all maintained correctly within the new glass panel structure.
780-991: LGTM!Input area implementation is comprehensive with drag-drop, paste handling, file previews, and keyboard hints. The conditional rendering based on connection state and processing status is handled correctly.
apps/ui/src/components/views/board-view/components/kanban-column.tsx (2)
5-5: LGTM!GlassPanel import aligns with the new design system.
36-95: LGTM overall!The GlassPanel integration is clean. The conditional glow gradients and drop-zone styling enhance the visual design. The component correctly forwards the ref and maintains droppable behavior.
apps/ui/src/components/views/agent-tools-view.tsx (5)
21-23: LGTM!Clean imports for the new layout components.
195-215: LGTM!The new layout structure with TopHeader and GlassPanel wrapper follows the established pattern from other views in this PR. The header with gradient icon is visually consistent with the glassmorphism design.
216-290: LGTM!The Read File tool card is well-structured with clear visual hierarchy, appropriate input styling, and good feedback for success/error states.
291-374: LGTM!The Write File tool card maintains consistency with the Read File card pattern while appropriately using green theming for the write operation.
375-472: LGTM!The Terminal tool card and Tool Execution Log section complete the tools grid nicely. The log section provides helpful context for developers using the console.
| <div className="bg-dark-850/40 border border-white/5 rounded-xl p-1 flex items-center justify-between cursor-pointer hover:border-white/10 hover:bg-dark-850/60 transition group"> | ||
| <div className="flex items-center gap-3 px-2 py-1.5"> | ||
| <FolderOpen className="w-4 h-4 text-brand-cyan group-hover:text-cyan-300 transition" /> | ||
| <span className="text-white font-medium text-sm">test case 1</span> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the sidebar.tsx file exists and examine its content
cat -n apps/ui/src/components/layout/sidebar.tsx | head -220Repository: AutoMaker-Org/automaker
Length of output: 9475
🏁 Script executed:
# Search for state/context patterns related to projects and agents
rg -n "runningAgents|currentProject|activeProject" --type=ts -g '!*.test.*' -g '!*.spec.*' apps/ui/src/Repository: AutoMaker-Org/automaker
Length of output: 46013
🏁 Script executed:
# Also search for any Redux or context API usage related to agents/projects
rg -n "useSelector|useDispatch|useContext|useState" apps/ui/src/components/layout/sidebar.tsxRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Check for environment or config files that might define these values
fd -t f "config\|env\|constant" apps/ui/src/ | head -20Repository: AutoMaker-Org/automaker
Length of output: 49
Connect hardcoded values to application state.
These hardcoded placeholder values should use the existing app state:
- Line 60: Project name
"test case 1"should come fromcurrentProject(available in app-store.ts) - Line 48: Folder count
"0"should be dynamic based on project data - Lines 151-153: Running agents badge showing
"3"should use theuse-running-agentshook already available inapps/ui/src/components/layout/sidebar/hooks/use-running-agents.ts
The app already provides these via state management and hooks; other sidebar components (sidebar-footer.tsx, project-selector-with-options.tsx) demonstrate the correct pattern using useAppStore() and the running agents hook.
🤖 Prompt for AI Agents
In apps/ui/src/components/layout/sidebar.tsx around lines 48, 60, and 151-153,
replace hardcoded placeholders with app state: read currentProject from
useAppStore() and render its name instead of "test case 1" (line 60), compute
and render the folder count dynamically from currentProject (line 48) rather
than "0", and replace the hardcoded running-agents count on the badge (lines
151-153) by importing and using the existing use-running-agents hook
(apps/ui/src/components/layout/sidebar/hooks/use-running-agents.ts) to get the
current count; add any needed imports (useAppStore and the hook), guard for
null/undefined currentProject, and keep existing styling/structure while
inserting the dynamic values.
| onEdit: () => void; | ||
| onDelete: () => void; | ||
| onViewOutput?: () => void; | ||
| hideActions?: boolean; |
There was a problem hiding this comment.
hideActions prop is declared but never used.
The hideActions prop is added to the interface and destructured in the function, but the component logic never references it. All action buttons/dropdowns still render unconditionally.
If intended to hide the header actions (as suggested by usage in kanban-card.tsx with hideActions={true}), implement the conditional logic.
🔎 Suggested implementation
{/* Running task header */}
- {isCurrentAutoTask && (
+ {isCurrentAutoTask && !hideActions && (
<div className="absolute top-2 right-2 flex items-center gap-1">Apply similar guards to the other header action sections (lines 110-123, 126-179, 182-245).
Also applies to: 44-44
🤖 Prompt for AI Agents
In
apps/ui/src/components/views/board-view/components/kanban-card/card-header.tsx
around lines 34 and 44 (and the header action blocks at 110-123, 126-179,
182-245), the hideActions prop is declared/destructured but never used; update
the component to conditionally render the header action UI when hideActions is
false. Specifically, wrap each actions section (the three blocks mentioned) in a
guard such as if (!hideActions) then render that JSX (or use { !hideActions &&
(<...>) } inline), and keep the rest of the header markup unchanged; ensure
hideActions remains optional and destructured so callers passing
hideActions={true} hide all action controls.
| <button | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onDelete(); | ||
| }} | ||
| className="text-slate-600 hover:text-brand-red transition" | ||
| > | ||
| <i data-lucide="trash" className="w-3.5 h-3.5"></i> | ||
| {/* Fallback to SVG if i tag fails */} | ||
| <svg | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| width="14" | ||
| height="14" | ||
| viewBox="0 0 24 24" | ||
| fill="none" | ||
| stroke="currentColor" | ||
| strokeWidth="2" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| className="lucide lucide-trash w-3.5 h-3.5" | ||
| > | ||
| <path d="M3 6h18" /> | ||
| <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" /> | ||
| <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" /> | ||
| </svg> | ||
| </button> |
There was a problem hiding this comment.
Duplicate icons will render - both <i> tag and inline SVG.
The delete button contains both a <i data-lucide="trash"> element (which requires vanilla JS Lucide initialization) AND an inline SVG. In React, both elements will render simultaneously, showing two trash icons.
Additionally, data-lucide attributes are for vanilla JavaScript Lucide usage, not React. Use the Trash2 component from lucide-react instead.
🔎 Proposed fix
+import { Trash2 } from 'lucide-react';
+
// In the JSX:
<button
onClick={(e) => {
e.stopPropagation();
onDelete();
}}
className="text-slate-600 hover:text-brand-red transition"
>
- <i data-lucide="trash" className="w-3.5 h-3.5"></i>
- {/* Fallback to SVG if i tag fails */}
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="14"
- height="14"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- strokeWidth="2"
- strokeLinecap="round"
- strokeLinejoin="round"
- className="lucide lucide-trash w-3.5 h-3.5"
- >
- <path d="M3 6h18" />
- <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
- <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
- </svg>
+ <Trash2 className="w-3.5 h-3.5" />
</button>| const { orderedFeatures } = resolveDependencies(map.backlog as any) as { | ||
| orderedFeatures: Feature[]; | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find and examine the relevant file
find . -name "use-board-column-features.ts" -type f 2>/dev/null | head -5Repository: AutoMaker-Org/automaker
Length of output: 143
🏁 Script executed:
# Check the file size first
wc -l "$(find . -name 'use-board-column-features.ts' -type f 2>/dev/null | head -1)"Repository: AutoMaker-Org/automaker
Length of output: 147
🏁 Script executed:
# Look at the file around lines 100-135 to understand context
file_path=$(find . -name 'use-board-column-features.ts' -type f 2>/dev/null | head -1)
if [ -n "$file_path" ]; then
sed -n '100,135p' "$file_path"
fiRepository: AutoMaker-Org/automaker
Length of output: 1326
🏁 Script executed:
# Also get imports and top of the file
file_path=$(find . -name 'use-board-column-features.ts' -type f 2>/dev/null | head -1)
if [ -n "$file_path" ]; then
echo "=== Imports and top of file ===" && head -30 "$file_path"
fiRepository: AutoMaker-Org/automaker
Length of output: 1121
🏁 Script executed:
# Find Feature type definition
rg -A 10 "export.*interface Feature|export.*type Feature" --type tsRepository: AutoMaker-Org/automaker
Length of output: 7107
🏁 Script executed:
# Look for the dependency-resolver package location
find . -name "dependency-resolver" -type d 2>/dev/null | grep -v node_modulesRepository: AutoMaker-Org/automaker
Length of output: 93
🏁 Script executed:
# Check if it's in packages
ls -la packages/ 2>/dev/null | grep dependencyRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Search for resolveDependencies and getBlockingDependencies type definitions
rg -B 5 -A 10 "export.*function.*resolveDependencies|export.*const.*resolveDependencies" --type tsRepository: AutoMaker-Org/automaker
Length of output: 1478
🏁 Script executed:
# Check imports and type definitions in dependency-resolver
head -50 libs/dependency-resolver/src/resolver.tsRepository: AutoMaker-Org/automaker
Length of output: 2116
🏁 Script executed:
# Look for BaseFeature definition
rg -B 2 -A 15 "export.*interface BaseFeature|export.*type BaseFeature" --type tsRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Check DependencyResolutionResult type
rg -B 2 -A 10 "DependencyResolutionResult" libs/dependency-resolver --type tsRepository: AutoMaker-Org/automaker
Length of output: 2560
🏁 Script executed:
# Check getBlockingDependencies signature
rg -B 5 -A 10 "export.*function.*getBlockingDependencies|export.*const.*getBlockingDependencies" libs/dependency-resolver --type tsRepository: AutoMaker-Org/automaker
Length of output: 1221
🏁 Script executed:
# Find BaseFeature definition
rg -B 2 -A 20 "interface BaseFeature|type BaseFeature" --type tsRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Compare the full Feature definitions in both locations
echo "=== UI Feature ===" && sed -n '53,90p' apps/ui/src/store/app-store.ts && echo -e "\n=== Shared types Feature ===" && sed -n '33,60p' libs/types/src/feature.tsRepository: AutoMaker-Org/automaker
Length of output: 2247
🏁 Script executed:
# Check what fields the dependency-resolver actually uses from Feature
rg -n "feature\." libs/dependency-resolver/src/resolver.ts | head -20Repository: AutoMaker-Org/automaker
Length of output: 1049
🏁 Script executed:
# Get the full UI Feature interface definition
sed -n '34,110p' apps/ui/src/store/app-store.tsRepository: AutoMaker-Org/automaker
Length of output: 2074
🏁 Script executed:
# Get BaseFeature definition to understand the inheritance
rg -B 2 -A 50 "interface BaseFeature" --type tsRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Find where BaseFeature is defined
rg "BaseFeature" --type ts | grep -E "(interface|type|import|export)" | head -10Repository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Get the full Feature definition from app-store
sed -n '1,150p' apps/ui/src/store/app-store.ts | grep -A 80 "export interface Feature"Repository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Check what BaseFeature is in the shared types
rg -B 5 -A 30 "^export.*BaseFeature" libs/types/src/feature.tsRepository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
# Search for BaseFeature more broadly
rg "BaseFeature" --type ts -A 2 -B 2Repository: AutoMaker-Org/automaker
Length of output: 1122
🏁 Script executed:
# Get the complete Feature interface from app-store.ts
cat -n apps/ui/src/store/app-store.ts | sed -n '1,200p' | tail -100Repository: AutoMaker-Org/automaker
Length of output: 3335
🏁 Script executed:
# Check the imports in app-store.ts to see where BaseFeature comes from
head -20 apps/ui/src/store/app-store.tsRepository: AutoMaker-Org/automaker
Length of output: 488
🏁 Script executed:
# Get the complete UI Feature definition
sed -n '40,100p' apps/ui/src/store/app-store.tsRepository: AutoMaker-Org/automaker
Length of output: 1726
🏁 Script executed:
# Check if status field in UI Feature matches what's needed
rg -A 50 "export interface Feature extends" apps/ui/src/store/app-store.ts | head -60Repository: AutoMaker-Org/automaker
Length of output: 2057
🏁 Script executed:
# Let's verify the actual type compatibility by checking if there's a real type error
# First, check what fields dependency-resolver actually accesses
grep -n "feature\." libs/dependency-resolver/src/resolver.ts | grep -v "const\|const\|function\|export"Repository: AutoMaker-Org/automaker
Length of output: 941
🏁 Script executed:
# Check the status field values expected by getBlockingDependencies
sed -n '200,215p' libs/dependency-resolver/src/resolver.tsRepository: AutoMaker-Org/automaker
Length of output: 514
🏁 Script executed:
# Now let's trace what happens - check the usage at line 112-114
sed -n '105,130p' apps/ui/src/components/views/board-view/hooks/use-board-column-features.tsRepository: AutoMaker-Org/automaker
Length of output: 1102
🏁 Script executed:
# Final verification: Check if TypeScript would actually complain without the casts
# by looking at the tsconfig and strict settings
cat tsconfig.json | grep -A 5 '"compilerOptions"'Repository: AutoMaker-Org/automaker
Length of output: 112
🏁 Script executed:
# Check if there are any type errors in the build
find . -name "*.ts" -path "*/node_modules" -prune -o -type f -name "tsconfig.json" -print | head -3Repository: AutoMaker-Org/automaker
Length of output: 159
🏁 Script executed:
# Check UI tsconfig
cat apps/ui/tsconfig.json | head -40Repository: AutoMaker-Org/automaker
Length of output: 589
🏁 Script executed:
# Verify the actual type compatibility - simulate what TypeScript would do
# by checking if UI Feature can be passed to resolveDependencies
python3 << 'EOF'
# The key question: is UI Feature assignable to shared Feature?
# UI Feature:
# - status: 'backlog' | 'in_progress' | 'waiting_approval' | 'verified' | 'completed'
# - dependencies?: string[]
# - id: string
#
# Shared Feature (from @automaker/types):
# - status?: string (optional)
# - dependencies?: string[]
# - id: string
#
# TypeScript's structural typing analysis:
# 1. UI Feature has all required fields from Shared Feature
# 2. Extra fields in UI Feature are allowed (structural typing)
# 3. UI Feature.status is a union type that is assignable to string
# 4. Shared Feature.status is optional, UI Feature.status is required - this is OK (providing more)
#
# CONCLUSION: No type error should occur. The casts are UNNECESSARY.
print("Type Compatibility Analysis:")
print("=" * 50)
print("\nUI Feature.status: required union type")
print(" 'backlog' | 'in_progress' | 'waiting_approval' | 'verified' | 'completed'")
print("\nShared Feature.status: optional string")
print(" status?: string")
print("\nStructural Typing Result:")
print(" ✓ UI Feature IS assignable to Shared Feature")
print(" ✓ No 'as any' cast is necessary")
print(" ✓ Casts indicate misunderstanding of type system")
EOFRepository: AutoMaker-Org/automaker
Length of output: 153
Remove unnecessary as any casts — they provide no benefit and reduce type safety.
The UI Feature type from app-store.ts is structurally compatible with the Feature type expected by @automaker/dependency-resolver (from @automaker/types). Both types have the required id, optional dependencies, and a status field. The UI version provides a more specific status type (union literal), which is perfectly valid to pass where a general string type is expected. The casts at lines 112-114 and 127 are unnecessary and should be removed.
🤖 Prompt for AI Agents
In apps/ui/src/components/views/board-view/hooks/use-board-column-features.ts
around lines 112-114 (and the related cast at line 127), remove the unnecessary
"as any" casts (and any redundant "as { orderedFeatures: Feature[] }" return
cast) so TypeScript uses the actual UI Feature type that is structurally
compatible with the resolver. Simply call resolveDependencies(map.backlog)
without casting; if you need an explicit type for the returned shape, import the
appropriate Feature type and use a precise annotation (e.g., type the variable
that receives orderedFeatures) instead of forcing "any".
|
|
||
| for (const f of orderedFeatures) { | ||
| if (getBlockingDependencies(f, allFeatures).length > 0) { | ||
| if (getBlockingDependencies(f as any, allFeatures as any).length > 0) { |
There was a problem hiding this comment.
Same type safety issue: eliminate as any casts.
This line exhibits the same problem as lines 112-114: bypassing type safety with as any casts. Both f (a Feature from orderedFeatures) and allFeatures (typed as Feature[]) should already be compatible with getBlockingDependencies.
Address this together with the previous issue by properly typing the dependency-resolver functions or creating appropriate type adapters.
🤖 Prompt for AI Agents
In apps/ui/src/components/views/board-view/hooks/use-board-column-features.ts
around line 127, remove the unsafe `as any` casts when calling
getBlockingDependencies by making the function and/or its inputs correctly
typed: update getBlockingDependencies signature to accept the concrete Feature
type and Feature[] (or create a typed adapter/converter that maps the existing
values to the expected param types), then call it with `f` and `allFeatures`
directly. Ensure any downstream calls and imports reflect the new signature and
remove the other `as any` casts at lines 112-114 as part of the same type-fix.
| onClick={() => { | ||
| if (terminalState.isUnlocked) setTerminalUnlocked(false); | ||
| else { | ||
| // Trigger lock logic (input password) | ||
| // Ideally show dialog, but for now just toggle for UI demo | ||
| } | ||
| }} |
There was a problem hiding this comment.
Incomplete lock button logic when terminal is locked.
The else branch (lines 1528-1530) does nothing when clicked in the locked state. The comment suggests showing a dialog, but currently clicking the button when locked has no effect, which is confusing UX.
Consider either:
- Removing the button entirely when locked (since password prompt shows below)
- Implementing the dialog/password prompt trigger
- At minimum, scrolling to or focusing the password input
🔎 Suggested fix to focus password input when locked
onClick={() => {
if (terminalState.isUnlocked) setTerminalUnlocked(false);
else {
- // Trigger lock logic (input password)
- // Ideally show dialog, but for now just toggle for UI demo
+ // Focus the password input in the locked state UI
+ const passwordInput = document.getElementById('password');
+ passwordInput?.focus();
}
}}📝 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.
| onClick={() => { | |
| if (terminalState.isUnlocked) setTerminalUnlocked(false); | |
| else { | |
| // Trigger lock logic (input password) | |
| // Ideally show dialog, but for now just toggle for UI demo | |
| } | |
| }} | |
| onClick={() => { | |
| if (terminalState.isUnlocked) setTerminalUnlocked(false); | |
| else { | |
| // Focus the password input in the locked state UI | |
| const passwordInput = document.getElementById('password'); | |
| passwordInput?.focus(); | |
| } | |
| }} |
| {loading ? ( | ||
| <div className="absolute inset-0 flex flex-col items-center justify-center gap-4 text-muted-foreground"> | ||
| <Loader2 className="w-8 h-8 animate-spin text-brand-500" /> | ||
| <p>Connecting to terminal server...</p> | ||
| </div> | ||
| ) : error ? ( | ||
| <div className="absolute inset-0 flex flex-col items-center justify-center gap-4 text-destructive"> | ||
| <AlertCircle className="w-10 h-10" /> | ||
| <p className="text-lg font-medium">{error}</p> | ||
| <Button variant="outline" onClick={fetchStatus}> | ||
| <RefreshCw className="w-4 h-4 mr-2" /> | ||
| Retry Connection | ||
| </Button> | ||
| </div> |
There was a problem hiding this comment.
Unreachable code - duplicate loading/error handling.
These loading and error conditionals (lines 1545-1558) are unreachable because the component already returns early at lines 1297-1320 for these states. This dead code adds maintenance burden and confusion.
🔎 Suggested fix to remove unreachable code
{/* Terminal Content Area */}
<div className="flex-1 relative bg-black/40 backdrop-blur-sm">
- {loading ? (
- <div className="absolute inset-0 flex flex-col items-center justify-center gap-4 text-muted-foreground">
- <Loader2 className="w-8 h-8 animate-spin text-brand-500" />
- <p>Connecting to terminal server...</p>
- </div>
- ) : error ? (
- <div className="absolute inset-0 flex flex-col items-center justify-center gap-4 text-destructive">
- <AlertCircle className="w-10 h-10" />
- <p className="text-lg font-medium">{error}</p>
- <Button variant="outline" onClick={fetchStatus}>
- <RefreshCw className="w-4 h-4 mr-2" />
- Retry Connection
- </Button>
- </div>
- ) : !terminalState.isUnlocked ? (
+ {!terminalState.isUnlocked ? (Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/ui/src/components/views/terminal-view.tsx around lines 1545 to 1558
there is duplicate loading/error JSX that is unreachable because the component
returns early for loading and error states at lines 1297 to 1320; remove the
block between lines 1545–1558 to eliminate the dead conditional rendering and
keep the single early-return handling (ensure no other code depends on variables
declared only inside the removed block), leaving the component to render the
main UI path when not loading/error.
| <script src="https://cdn.tailwindcss.com"></script> | ||
|
|
||
| <!-- Lucide Icons --> | ||
| <script src="https://unpkg.com/lucide@latest"></script> |
There was a problem hiding this comment.
Unpinned CDN dependencies pose security and stability risks.
Using https://cdn.tailwindcss.com and https://unpkg.com/lucide@latest without version pinning:
- May break unexpectedly when upstream updates
- Prevents reproducible builds
- Potential security risk from compromised CDN resources
If this file is kept, pin specific versions.
🔎 Suggested fix
- <script src="https://cdn.tailwindcss.com"></script>
+ <script src="https://cdn.tailwindcss.com?plugins=forms@0.5.7"></script>
- <script src="https://unpkg.com/lucide@latest"></script>
+ <script src="https://unpkg.com/lucide@0.562.0"></script>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In index (28).html around lines 17 to 20, the HTML loads Tailwind and Lucide
from unpinned CDN URLs which risks breakage and security issues; update these
script references to use specific, tested versioned URLs (e.g., replace
https://cdn.tailwindcss.com with a pinned Tailwind CDN URL for the intended
version and replace https://unpkg.com/lucide@latest with a specific Lucide
release URL), and optionally add SRI integrity and crossorigin attributes or
vendor the assets into the project/build for reproducible, secure builds.
|
keep branch around, closing to clean up pr queue |
This commit introduces a new app layout structure with an AppLayout component, a TopHeader for improved navigation, and a Sidebar for project management. Additionally, it adds GlassPanel and GlassCard components to enhance the UI with a glassmorphism effect. The Kanban board and agent views have been updated to utilize these new components, improving the overall user experience and visual consistency across the application.
Summary by CodeRabbit
New Features
Style
✏️ Tip: You can customize this high-level summary in your review settings.