Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"react-color": "^2.19.3",
"react-dom": "19.2.1",
"react-dropzone": "^14.3.8",
"react-grid-layout": "^2.2.2",
"react-grid-layout": "git+https://github.com/urjitc/react-grid-layout.git",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Using a personal GitHub fork instead of npm package introduces dependency management risks. Verify the fork has anchor property changes, and consider contributing upstream to react-grid-layout for long-term maintainability.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: package.json
Line: 117:117

Comment:
**style:** Using a personal GitHub fork instead of npm package introduces dependency management risks. Verify the fork has anchor property changes, and consider contributing upstream to `react-grid-layout` for long-term maintainability.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@cubic-dev-ai cubic-dev-ai Bot Jan 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Git dependency should be pinned to a specific commit hash for reproducible builds and supply chain security. Without pinning, any push to this repository will change what gets installed, making builds non-reproducible and potentially introducing breaking changes or security vulnerabilities.

Pin to a specific commit: git+https://github.com/urjitc/react-grid-layout.git#<commit-sha>

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 117:

<comment>Git dependency should be pinned to a specific commit hash for reproducible builds and supply chain security. Without pinning, any push to this repository will change what gets installed, making builds non-reproducible and potentially introducing breaking changes or security vulnerabilities.

Pin to a specific commit: `git+https://github.com/urjitc/react-grid-layout.git#<commit-sha>`</comment>

<file context>
@@ -114,7 +114,7 @@
     "react-dom": "19.2.1",
     "react-dropzone": "^14.3.8",
-    "react-grid-layout": "^2.2.2",
+    "react-grid-layout": "git+https://github.com/urjitc/react-grid-layout.git",
     "react-helmet-async": "^2.0.5",
     "react-hook-form": "^7.69.0",
</file context>
Fix with Cubic

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pin the git dependency to a specific commit hash for reproducible builds.

Using an unpinned git URL means builds are non-deterministic—any push to the default branch changes what gets installed. This creates several risks:

  1. Build reproducibility: Different builds may pull different code
  2. Supply chain security: Changes to the fork aren't reviewed before inclusion
  3. Debugging difficulty: Hard to identify which version caused issues
Suggested fix
-    "react-grid-layout": "git+https://github.com/urjitc/react-grid-layout.git",
+    "react-grid-layout": "git+https://github.com/urjitc/react-grid-layout.git#<commit-sha>",

Replace <commit-sha> with the specific commit hash you want to use. You can find this by running:

git ls-remote https://github.com/urjitc/react-grid-layout.git HEAD

Additionally, consider documenting why this fork is needed (e.g., anchor property support) in a comment or README so future maintainers understand the dependency choice.

🤖 Prompt for AI Agents
In `@package.json` at line 117, The git dependency "react-grid-layout":
"git+https://github.com/urjitc/react-grid-layout.git" is unpinned; pin it to a
specific commit by replacing the URL with a commit-specific ref (e.g.
"git+https://github.com/urjitc/react-grid-layout.git#<commit-sha>") using a
commit hash obtained via git ls-remote, and add a brief comment or README note
explaining why this fork is used (e.g., anchor property support) so future
maintainers understand the choice.

"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.69.0",
"react-icons": "^5.5.0",
Expand Down
10 changes: 5 additions & 5 deletions src/components/workspace-canvas/WorkspaceGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export function WorkspaceGrid({
}, []);

// Handle drag start - with RGL v2, this only fires after 3px movement (real drag, not click)
const handleDragStart = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | undefined) => {
const handleDragStart = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | null) => {
// Check if the click originated from a dropdown menu - if so, don't start drag
const target = e.target as HTMLElement;
if (
Expand All @@ -156,7 +156,7 @@ export function WorkspaceGrid({
}, [onDragStart, onGridDragStateChange]);

// Handle drag to detect folder hover based on cursor position
const handleDrag = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | undefined) => {
const handleDrag = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | null) => {
const draggedItemId = draggedItemIdRef.current;
if (!draggedItemId || !e) return;

Expand Down Expand Up @@ -245,7 +245,7 @@ export function WorkspaceGrid({
}, [selectedCardIds]);

// Handle resize start - track which item is being resized
const handleResizeStart = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | undefined) => {
const handleResizeStart = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | null) => {
hasUserInteractedRef.current = true;
// Track which item is being resized (same as drag)
if (!oldItem) return;
Expand All @@ -257,7 +257,7 @@ export function WorkspaceGrid({

// Handle drag stop - with RGL v2, this only fires for actual drags (not clicks)
// Click handling is now done by individual card components via their onClick handlers
const handleDragStop = useCallback((newLayout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | undefined) => {
const handleDragStop = useCallback((newLayout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | null) => {
const draggedItemId = draggedItemIdRef.current;

// If no drag was started (e.g., click on dropdown), exit early
Expand Down Expand Up @@ -393,7 +393,7 @@ export function WorkspaceGrid({
// Handle resize to enforce constraints
// Note cards can transition between compact (w=1, h=4) and expanded (w>=2, h>=9) modes
// based on EITHER width or height changes, allowing vertical-only resizing to trigger mode switches
const handleResize = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | undefined) => {
const handleResize = useCallback((layout: Layout, oldItem: LayoutItem | null, newItem: LayoutItem | null, placeholder: LayoutItem | null, e: Event, element: HTMLElement | null) => {
// Enforce custom constraints for YouTube and single-column items
if (!newItem || !oldItem) return;
const itemData = allItemsRef.current.find(i => i.id === newItem.i);
Expand Down
18 changes: 17 additions & 1 deletion src/lib/workspace-state/grid-layout-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Layout, LayoutItem } from "react-grid-layout";
import type { Layout, LayoutItem } from "react-grid-layout";
import type { Item, CardType, LayoutPosition, ResponsiveLayouts } from "./types";

/**
Expand Down Expand Up @@ -92,6 +92,22 @@ export function itemsToLayout(items: Item[], breakpoint: 'lg' | 'xxs' = 'lg'): L
};
}

// Folders are anchor items - they act as obstacles but can be dragged/resized
if (item.type === 'folder') {
return {
i: item.id,
x: layout?.x ?? 0,
y: layout?.y ?? 0,
w: layout?.w ?? DEFAULT_CARD_DIMENSIONS[item.type].w,
h: layout?.h ?? DEFAULT_CARD_DIMENSIONS[item.type].h,
minW: 1,
minH: 4,
maxW: 4,
maxH: 25,
anchor: true, // Anchor items act as obstacles but can be moved
};
}

// Default constraints for other card types
return {
i: item.id,
Expand Down