mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
fix Windows folder import from project modal (#2863)
Co-authored-by: Lanzhou3 <217479610+Lanzhou3@users.noreply.github.com>
This commit is contained in:
parent
1770789fa0
commit
b5b975769a
4 changed files with 58 additions and 2 deletions
|
|
@ -107,8 +107,11 @@ function normalizeProjectImportResult(input: unknown): OpenDesignHostProjectImpo
|
|||
const rawProjectId = isRecord(project) ? project.id : null;
|
||||
const projectId = typeof rawProjectId === 'string' ? rawProjectId : null;
|
||||
const conversationId = typeof response.conversationId === 'string' ? response.conversationId : null;
|
||||
const entryFile = typeof response.entryFile === 'string' ? response.entryFile : null;
|
||||
if (projectId == null || conversationId == null || entryFile == null) {
|
||||
const entryFile =
|
||||
typeof response.entryFile === 'string' || response.entryFile === null
|
||||
? response.entryFile
|
||||
: undefined;
|
||||
if (projectId == null || conversationId == null || entryFile === undefined) {
|
||||
return failure('daemon import response did not include host project identifiers', response);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,4 +33,12 @@ describe("desktop preload host boundary", () => {
|
|||
expect(source).not.toContain('exposeInMainWorld("__odDesktop"');
|
||||
expect(source).not.toContain("exposeInMainWorld('__odDesktop'");
|
||||
});
|
||||
|
||||
it("mirrors the host import contract by accepting a null entryFile", () => {
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const source = readFileSync(join(here, "../../src/main/preload.cts"), "utf8");
|
||||
|
||||
expect(source).toContain("response.entryFile === null");
|
||||
expect(source).toContain("entryFile === undefined");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import type { ConnectorDetail } from '@open-design/contracts';
|
||||
import type { OpenDesignHostProjectImportSuccess } from '@open-design/host';
|
||||
import type {
|
||||
DesignSystemSummary,
|
||||
MediaProviderCredentials,
|
||||
|
|
@ -35,6 +36,7 @@ interface Props {
|
|||
onCreate: (input: CreateInput & { requestId?: string }) => Promise<boolean> | boolean | void;
|
||||
onImportClaudeDesign?: (file: File) => Promise<void> | void;
|
||||
onImportFolder?: (baseDir: string) => Promise<void> | void;
|
||||
onImportFolderResponse?: (response: OpenDesignHostProjectImportSuccess) => Promise<void> | void;
|
||||
onOpenConnectorsTab?: () => void;
|
||||
onClose: () => void;
|
||||
initialTab?: CreateTab;
|
||||
|
|
@ -55,6 +57,7 @@ export function NewProjectModal({
|
|||
onCreate,
|
||||
onImportClaudeDesign,
|
||||
onImportFolder,
|
||||
onImportFolderResponse,
|
||||
onOpenConnectorsTab,
|
||||
onClose,
|
||||
initialTab,
|
||||
|
|
@ -151,6 +154,7 @@ export function NewProjectModal({
|
|||
}}
|
||||
{...(onImportClaudeDesign ? { onImportClaudeDesign } : {})}
|
||||
{...(onImportFolder ? { onImportFolder } : {})}
|
||||
{...(onImportFolderResponse ? { onImportFolderResponse } : {})}
|
||||
{...(onOpenConnectorsTab ? { onOpenConnectorsTab } : {})}
|
||||
{...(initialTab ? { initialTab } : {})}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
vi.mock('@open-design/host', () => ({
|
||||
isOpenDesignHostAvailable: () => true,
|
||||
pickAndImportHostProject: vi.fn(),
|
||||
}));
|
||||
|
||||
import { pickAndImportHostProject } from '@open-design/host';
|
||||
import { NewProjectModal } from '../../src/components/NewProjectModal';
|
||||
import type {
|
||||
DesignSystemSummary,
|
||||
|
|
@ -56,6 +62,7 @@ class ResizeObserverMock {
|
|||
beforeEach(() => {
|
||||
globalThis.ResizeObserver = ResizeObserverMock as typeof ResizeObserver;
|
||||
Element.prototype.scrollIntoView = vi.fn();
|
||||
vi.mocked(pickAndImportHostProject).mockReset();
|
||||
});
|
||||
|
||||
describe('NewProjectModal layout', () => {
|
||||
|
|
@ -116,6 +123,40 @@ describe('NewProjectModal layout', () => {
|
|||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('forwards the desktop folder import response handler to the inner panel', async () => {
|
||||
const importResult = {
|
||||
conversationId: 'conversation-host',
|
||||
entryFile: 'src/App.tsx',
|
||||
ok: true,
|
||||
projectId: 'project-host',
|
||||
} as const;
|
||||
vi.mocked(pickAndImportHostProject).mockResolvedValue(importResult);
|
||||
const onImportFolderResponse = vi.fn();
|
||||
|
||||
render(
|
||||
<NewProjectModal
|
||||
open
|
||||
skills={skills}
|
||||
designSystems={designSystems}
|
||||
defaultDesignSystemId={null}
|
||||
templates={[]}
|
||||
promptTemplates={[]}
|
||||
onCreate={() => {}}
|
||||
onImportFolderResponse={onImportFolderResponse}
|
||||
onClose={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Open folder' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(pickAndImportHostProject).toHaveBeenCalledWith({ skillId: 'prototype-skill' });
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(onImportFolderResponse).toHaveBeenCalledWith(importResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('NewProjectModal template deletion plumbing', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue