feat(web): drag-to-reorder projects in sidebar
- Add @dnd-kit (core, sortable, utilities) for mouse + touch drag reorder - SortableGroup.tsx: sortable wrapper with grip handle icon - project-sidebar-order.ts: localStorage persistence for order - Shell.tsx: DndContext + SortableContext around project sidebar - Folder icon for projects instead of lock icon
This commit is contained in:
parent
f1ac32fd61
commit
e70f0bd414
60
apps/web/src/components/SortableGroup.tsx
Normal file
60
apps/web/src/components/SortableGroup.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Sortable wrapper for a project (space) sidebar group card.
|
||||||
|
*
|
||||||
|
* Wraps the card in @dnd-kit's useSortable so it can be dragged to reorder.
|
||||||
|
* Renders a grip handle icon on the title row.
|
||||||
|
*/
|
||||||
|
import { CSS as DndCSS } from "@dnd-kit/utilities";
|
||||||
|
import { useSortable } from "@dnd-kit/sortable";
|
||||||
|
import { GripVertical } from "lucide-react";
|
||||||
|
import { memo, useMemo } from "react";
|
||||||
|
import { cn } from "@rakazo/ui-web";
|
||||||
|
|
||||||
|
interface SortableGroupProps {
|
||||||
|
group: { spaceId: string; key: string; title?: string | null };
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SortableGroup = memo(function SortableGroup({ group, children }: SortableGroupProps) {
|
||||||
|
const {
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
isDragging,
|
||||||
|
} = useSortable({ id: group.spaceId });
|
||||||
|
|
||||||
|
const style: React.CSSProperties = useMemo(
|
||||||
|
() => ({
|
||||||
|
transform: DndCSS.Translate.toString(transform),
|
||||||
|
transition,
|
||||||
|
opacity: isDragging ? 0.5 : undefined,
|
||||||
|
zIndex: isDragging ? 1000 : undefined,
|
||||||
|
}),
|
||||||
|
[transform, transition, isDragging],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={setNodeRef} style={style} data-drag-id={group.spaceId}>
|
||||||
|
{children}
|
||||||
|
{/* Invisible drag handle — left edge of the title row */}
|
||||||
|
{group.title ? (
|
||||||
|
<button
|
||||||
|
{...attributes}
|
||||||
|
{...listeners}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
"absolute left-0 top-3 w-7 h-7 rounded-md flex items-center justify-center",
|
||||||
|
"text-muted-foreground/30 hover:text-muted-foreground/70 active:text-muted-foreground",
|
||||||
|
"transition-colors cursor-grab active:cursor-grabbing",
|
||||||
|
"z-10",
|
||||||
|
)}
|
||||||
|
aria-label="Drag to reorder"
|
||||||
|
>
|
||||||
|
<GripVertical className="size-icon-sm" strokeWidth={2} />
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
32
apps/web/src/lib/project-sidebar-order.ts
Normal file
32
apps/web/src/lib/project-sidebar-order.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Persisted project (space) sort order in the sidebar.
|
||||||
|
*
|
||||||
|
* Stores a JSON array of space IDs. When the array is present, it
|
||||||
|
* overrides the natural API order; an empty or missing array means
|
||||||
|
* “use API order”.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const STORAGE_KEY = "rakazo:project-sidebar-order";
|
||||||
|
|
||||||
|
export function readProjectSidebarOrder(): string[] {
|
||||||
|
try {
|
||||||
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
||||||
|
if (!raw) return [];
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
return Array.isArray(parsed) ? parsed : [];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function writeProjectSidebarOrder(ids: string[]): void {
|
||||||
|
try {
|
||||||
|
if (ids.length === 0) {
|
||||||
|
window.localStorage.removeItem(STORAGE_KEY);
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore quota / private-mode failures
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -32,6 +32,8 @@ import {
|
|||||||
type MessageReaction,
|
type MessageReaction,
|
||||||
normalizeCreateBotProfile,
|
normalizeCreateBotProfile,
|
||||||
} from "@rakazo/contracts";
|
} from "@rakazo/contracts";
|
||||||
|
import { SortableGroup } from "../components/SortableGroup";
|
||||||
|
import { readProjectSidebarOrder, writeProjectSidebarOrder } from "../lib/project-sidebar-order";
|
||||||
import {
|
import {
|
||||||
attachmentsForThread,
|
attachmentsForThread,
|
||||||
buildComposerMentionOptions,
|
buildComposerMentionOptions,
|
||||||
@ -84,6 +86,7 @@ import {
|
|||||||
} from "@rakazo/ui-web";
|
} from "@rakazo/ui-web";
|
||||||
import {
|
import {
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
|
GripVertical,
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
ArrowUp,
|
ArrowUp,
|
||||||
Bell,
|
Bell,
|
||||||
@ -93,8 +96,8 @@ import {
|
|||||||
Clock,
|
Clock,
|
||||||
Copy,
|
Copy,
|
||||||
Gauge,
|
Gauge,
|
||||||
|
Folder,
|
||||||
LayoutGrid,
|
LayoutGrid,
|
||||||
Lock,
|
|
||||||
LogOut,
|
LogOut,
|
||||||
Maximize2,
|
Maximize2,
|
||||||
Menu,
|
Menu,
|
||||||
@ -136,6 +139,21 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
|
import {
|
||||||
|
DndContext,
|
||||||
|
DragOverlay,
|
||||||
|
closestCenter,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
} from "@dnd-kit/core";
|
||||||
|
import { MouseSensor, TouchSensor } from "@dnd-kit/core";
|
||||||
|
import {
|
||||||
|
SortableContext,
|
||||||
|
sortableKeyboardCoordinates,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
useSortable,
|
||||||
|
} from "@dnd-kit/sortable";
|
||||||
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||||
import { ArtifactFileCard } from "../components/ArtifactFileCard";
|
import { ArtifactFileCard } from "../components/ArtifactFileCard";
|
||||||
import { AskCard } from "../components/AskCard";
|
import { AskCard } from "../components/AskCard";
|
||||||
@ -429,6 +447,23 @@ export function ShellPage() {
|
|||||||
|
|
||||||
const [showCreateBotModal, setShowCreateBotModal] = useState(false);
|
const [showCreateBotModal, setShowCreateBotModal] = useState(false);
|
||||||
|
|
||||||
|
// Persisted project (space) sort order
|
||||||
|
const [projectOrder, setProjectOrder] = useState<string[]>(() => readProjectSidebarOrder());
|
||||||
|
const handleReorderProjects = useCallback(
|
||||||
|
(orderedIds: string[]) => {
|
||||||
|
setProjectOrder(orderedIds);
|
||||||
|
writeProjectSidebarOrder(orderedIds);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag-to-reorder project sidebar state & sensors
|
||||||
|
const [draggedProjectId, setDraggedProjectId] = useState<string | null>(null);
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(MouseSensor, { activationConstraint: { distance: 8 } }),
|
||||||
|
useSensor(TouchSensor, { activationConstraint: { distance: 8 } }),
|
||||||
|
);
|
||||||
|
|
||||||
// Browser Preview lifecycle
|
// Browser Preview lifecycle
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const bp = bridge?.browserPreview;
|
const bp = bridge?.browserPreview;
|
||||||
@ -1581,7 +1616,7 @@ export function ShellPage() {
|
|||||||
.filter((group) => group.bots.length > 0);
|
.filter((group) => group.bots.length > 0);
|
||||||
}, [homeSpaceId, sidebarGroups]);
|
}, [homeSpaceId, sidebarGroups]);
|
||||||
|
|
||||||
const projectSidebarGroups = useMemo(() => {
|
const projectSidebarGroups = useMemo((): typeof sidebarGroups => {
|
||||||
if (!homeSpaceId) return [];
|
if (!homeSpaceId) return [];
|
||||||
const entries: typeof sidebarGroups = [];
|
const entries: typeof sidebarGroups = [];
|
||||||
|
|
||||||
@ -1625,8 +1660,49 @@ export function ShellPage() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply persisted drag-to-reorder order if present
|
||||||
|
if (projectOrder.length > 0) {
|
||||||
|
const orderMap = new Map(entries.map((e, i) => [e.spaceId, i]));
|
||||||
|
entries.sort((a, b) => {
|
||||||
|
const aIdx = orderMap.get(a.spaceId) ?? -1;
|
||||||
|
const bIdx = orderMap.get(b.spaceId) ?? -1;
|
||||||
|
// Items in order come first, then remaining in original order
|
||||||
|
const aInOrder = aIdx !== -1;
|
||||||
|
const bInOrder = bIdx !== -1;
|
||||||
|
if (aInOrder && bInOrder) return aIdx - bIdx;
|
||||||
|
if (aInOrder) return -1;
|
||||||
|
if (bInOrder) return 1;
|
||||||
|
return orderMap.get(a.spaceId) ?? 0 - (orderMap.get(b.spaceId) ?? 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}, [hauptthreadGroup?.id, homeSpaceId, sidebarGroups, spaces]);
|
}, [hauptthreadGroup?.id, homeSpaceId, sidebarGroups, spaces, projectOrder]);
|
||||||
|
|
||||||
|
// DnD handlers for project sidebar reordering
|
||||||
|
const handleProjectDragEnd = useCallback(
|
||||||
|
(event: { active: { id: string | number }; over: { id: string | number } | null }) => {
|
||||||
|
if (!event.over) return;
|
||||||
|
const activeId = String(event.active.id);
|
||||||
|
const overId = String(event.over.id);
|
||||||
|
if (activeId === overId) return;
|
||||||
|
const sorted = projectSidebarGroups as any[];
|
||||||
|
const activeIdx = sorted.findIndex((g) => g.spaceId === activeId);
|
||||||
|
const overIdx = sorted.findIndex((g) => g.spaceId === overId);
|
||||||
|
if (activeIdx === -1 || overIdx === -1) return;
|
||||||
|
const [moved] = sorted.splice(activeIdx, 1);
|
||||||
|
sorted.splice(overIdx, 0, moved);
|
||||||
|
const ids = sorted.map((g: any) => g.spaceId) as string[];
|
||||||
|
handleReorderProjects(ids);
|
||||||
|
},
|
||||||
|
[projectSidebarGroups, handleReorderProjects],
|
||||||
|
);
|
||||||
|
const handleProjectDragStart = useCallback(
|
||||||
|
(event: { active: { id: string | number } }) => {
|
||||||
|
setDraggedProjectId(String(event.active.id));
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const openSpaceChat = useCallback(
|
const openSpaceChat = useCallback(
|
||||||
(spaceId: string, path: string) => {
|
(spaceId: string, path: string) => {
|
||||||
@ -2330,7 +2406,8 @@ export function ShellPage() {
|
|||||||
}, [clearVoiceEntryParam]);
|
}, [clearVoiceEntryParam]);
|
||||||
const loadOlder = useCallback(() => loadOlderMessagesRef.current(), []);
|
const loadOlder = useCallback(() => loadOlderMessagesRef.current(), []);
|
||||||
const jumpToReplyMessage = useCallback((messageId: string) => {
|
const jumpToReplyMessage = useCallback((messageId: string) => {
|
||||||
const existing = document.querySelector(`[data-message-id="${CSS.escape(messageId)}"]`);
|
const escapedId = messageId.replace(/[^\w-]/g, (c) => `\\${c}`);
|
||||||
|
const existing = document.querySelector(`[data-message-id="${escapedId}"]`);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// Cancel any in-flight around-fetch so it cannot overwrite this scroll.
|
// Cancel any in-flight around-fetch so it cannot overwrite this scroll.
|
||||||
jumpGeneration.current += 1;
|
jumpGeneration.current += 1;
|
||||||
@ -3393,9 +3470,7 @@ export function ShellPage() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className="flex min-w-0 items-center gap-1.5 truncate">
|
<span className="flex min-w-0 items-center gap-1.5 truncate">
|
||||||
{group.showLock ? (
|
<Folder strokeWidth={2} aria-hidden="true" className="size-icon-sm" />
|
||||||
<Lock strokeWidth={2} aria-hidden="true" className="size-icon-sm" />
|
|
||||||
) : null}
|
|
||||||
<span className="truncate">{group.title}</span>
|
<span className="truncate">{group.title}</span>
|
||||||
</span>
|
</span>
|
||||||
{group.emptySpaceId ? null : (
|
{group.emptySpaceId ? null : (
|
||||||
@ -3627,11 +3702,23 @@ export function ShellPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{projectSidebarGroups.map((group) => {
|
<DndContext
|
||||||
const collapsed =
|
sensors={sensors}
|
||||||
Boolean(group.title) && collapsedSidebarSections.has(group.key);
|
collisionDetection={closestCenter}
|
||||||
return (
|
onDragEnd={handleProjectDragEnd}
|
||||||
<div key={`proj-${group.key}`} data-sidebar-group={group.key}>
|
onDragStart={handleProjectDragStart}
|
||||||
|
onDragCancel={() => setDraggedProjectId(null)}
|
||||||
|
>
|
||||||
|
<SortableContext
|
||||||
|
items={projectSidebarGroups.filter((g) => g.title).map((g) => g.spaceId)}
|
||||||
|
strategy={verticalListSortingStrategy}
|
||||||
|
>
|
||||||
|
{projectSidebarGroups.map((group) => {
|
||||||
|
const collapsed =
|
||||||
|
Boolean(group.title) && collapsedSidebarSections.has(group.key);
|
||||||
|
return (
|
||||||
|
<SortableGroup key={`proj-${group.key}`} group={group}>
|
||||||
|
<div data-sidebar-group={group.key}>
|
||||||
{group.title ? (
|
{group.title ? (
|
||||||
<div className="flex items-center pt-3 pb-0.5">
|
<div className="flex items-center pt-3 pb-0.5">
|
||||||
<button
|
<button
|
||||||
@ -3691,13 +3778,7 @@ export function ShellPage() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className="flex min-w-0 items-center gap-1.5 truncate">
|
<span className="flex min-w-0 items-center gap-1.5 truncate">
|
||||||
{group.showLock ? (
|
<Folder strokeWidth={2} aria-hidden="true" className="size-icon-sm" />
|
||||||
<Lock
|
|
||||||
strokeWidth={2}
|
|
||||||
aria-hidden="true"
|
|
||||||
className="size-icon-sm"
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<span className="truncate">{group.title}</span>
|
<span className="truncate">{group.title}</span>
|
||||||
</span>
|
</span>
|
||||||
{group.emptySpaceId ? null : (
|
{group.emptySpaceId ? null : (
|
||||||
@ -3795,8 +3876,11 @@ export function ShellPage() {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
</SortableGroup>
|
||||||
})}
|
);
|
||||||
|
})}
|
||||||
|
</SortableContext>
|
||||||
|
</DndContext>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -50,5 +50,10 @@
|
|||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"app-builder-lib@26.15.3": "patches/app-builder-lib@26.15.3.patch"
|
"app-builder-lib@26.15.3": "patches/app-builder-lib@26.15.3.patch"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/core": "6.3.1",
|
||||||
|
"@dnd-kit/sortable": "10.0.0",
|
||||||
|
"@dnd-kit/utilities": "3.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
pnpm-lock.yaml
generated
59
pnpm-lock.yaml
generated
@ -16,6 +16,16 @@ patchedDependencies:
|
|||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
|
dependencies:
|
||||||
|
'@dnd-kit/core':
|
||||||
|
specifier: 6.3.1
|
||||||
|
version: 6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
|
'@dnd-kit/sortable':
|
||||||
|
specifier: 10.0.0
|
||||||
|
version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)
|
||||||
|
'@dnd-kit/utilities':
|
||||||
|
specifier: 3.2.2
|
||||||
|
version: 3.2.2(react@19.2.8)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: 2.5.13
|
specifier: 2.5.13
|
||||||
@ -1881,6 +1891,28 @@ packages:
|
|||||||
'@daytona/toolbox-api-client@0.211.2':
|
'@daytona/toolbox-api-client@0.211.2':
|
||||||
resolution: {integrity: sha512-88CUophLGD1XVO8SJMttImrKw/iu2PC0Zz82S5DZkCJc70zBHpIm+svaepGGxQaLJ0EEtNbm7G1sJnIMQZ7zXw==}
|
resolution: {integrity: sha512-88CUophLGD1XVO8SJMttImrKw/iu2PC0Zz82S5DZkCJc70zBHpIm+svaepGGxQaLJ0EEtNbm7G1sJnIMQZ7zXw==}
|
||||||
|
|
||||||
|
'@dnd-kit/accessibility@3.1.1':
|
||||||
|
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: 19.2.3
|
||||||
|
|
||||||
|
'@dnd-kit/core@6.3.1':
|
||||||
|
resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: 19.2.3
|
||||||
|
react-dom: 19.2.3
|
||||||
|
|
||||||
|
'@dnd-kit/sortable@10.0.0':
|
||||||
|
resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@dnd-kit/core': ^6.3.0
|
||||||
|
react: 19.2.3
|
||||||
|
|
||||||
|
'@dnd-kit/utilities@3.2.2':
|
||||||
|
resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: 19.2.3
|
||||||
|
|
||||||
'@e2b/desktop@2.4.0':
|
'@e2b/desktop@2.4.0':
|
||||||
resolution: {integrity: sha512-eeY4p/lz7kkDJMidREe7sp2nln16P1M1p64Fb+csn4SssxC2EjKBGqP0NEIlVDVd6iCuPbM7cVlkE/qbwJX4jg==}
|
resolution: {integrity: sha512-eeY4p/lz7kkDJMidREe7sp2nln16P1M1p64Fb+csn4SssxC2EjKBGqP0NEIlVDVd6iCuPbM7cVlkE/qbwJX4jg==}
|
||||||
engines: {node: '>=20.18.1 <21 || >=22'}
|
engines: {node: '>=20.18.1 <21 || >=22'}
|
||||||
@ -11228,6 +11260,31 @@ snapshots:
|
|||||||
- debug
|
- debug
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@dnd-kit/accessibility@3.1.1(react@19.2.8)':
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.8
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
|
||||||
|
dependencies:
|
||||||
|
'@dnd-kit/accessibility': 3.1.1(react@19.2.8)
|
||||||
|
'@dnd-kit/utilities': 3.2.2(react@19.2.8)
|
||||||
|
react: 19.2.8
|
||||||
|
react-dom: 19.2.8(react@19.2.8)
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)':
|
||||||
|
dependencies:
|
||||||
|
'@dnd-kit/core': 6.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||||
|
'@dnd-kit/utilities': 3.2.2(react@19.2.8)
|
||||||
|
react: 19.2.8
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@dnd-kit/utilities@3.2.2(react@19.2.8)':
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.8
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@e2b/desktop@2.4.0':
|
'@e2b/desktop@2.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
e2b: 2.49.1
|
e2b: 2.49.1
|
||||||
@ -13481,7 +13538,9 @@ snapshots:
|
|||||||
metro-runtime: 0.84.5
|
metro-runtime: 0.84.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
|
- bufferutil
|
||||||
- supports-color
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
'@react-native/normalize-colors@0.74.89': {}
|
'@react-native/normalize-colors@0.74.89': {}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user