feat: move plugin workspace into project settings

This commit is contained in:
inman
2026-09-07 10:06:37 +08:00
parent f8eee430f4
commit be1764e016
19 changed files with 363 additions and 76 deletions

View File

@@ -208,10 +208,10 @@ function PluginsRouteHarness() {
<>
<Plugins />
<div data-testid="plugins-location">{location.pathname}{location.search}</div>
<button type="button" onClick={() => navigate('/plugins')}>打开裸插件地址</button>
<button type="button" onClick={() => navigate('/project-config/plugins')}>打开裸插件地址</button>
<button
type="button"
onClick={() => navigate('/plugins?scope=illegal&source=remote&state=broken')}
onClick={() => navigate('/project-config/plugins?scope=illegal&source=remote&state=broken')}
>打开非法插件地址</button>
</>
);
@@ -249,16 +249,24 @@ function preparePluginsRouteState() {
}
describe('PluginsView', () => {
it('renders as project-configuration drawer content without a duplicate standalone header', () => {
render(<MemoryRouter><PluginsView {...props()} embedded /></MemoryRouter>);
expect(screen.getByTestId('plugins-page')).toBeVisible();
expect(screen.getByRole('button', { name: '刷新全部来源' })).toBeVisible();
expect(screen.queryByRole('heading', { name: '插件', level: 1 })).not.toBeInTheDocument();
});
it('keeps the production URL, scope control, and fallback notice aligned across in-place changes', async () => {
preparePluginsRouteState();
render(
<MemoryRouter initialEntries={['/plugins?scope=project']}>
<MemoryRouter initialEntries={['/project-config/plugins?scope=project']}>
<PluginsRouteHarness />
</MemoryRouter>,
);
await waitFor(() => expect(screen.getByTestId('plugins-location')).toHaveTextContent(
'/plugins?scope=all&source=all&state=all',
'/project-config/plugins?scope=all&source=all&state=all',
));
expect(screen.getByLabelText('范围')).toHaveValue('all');
expect(screen.getByText('当前没有打开的项目,已显示全部插件。')).toBeVisible();
@@ -273,19 +281,19 @@ describe('PluginsView', () => {
act(() => codingWorkspaceStore.setState({ activeProjectId: activeProject.id, activeProject }));
fireEvent.click(screen.getByRole('button', { name: '打开裸插件地址' }));
await waitFor(() => expect(screen.getByTestId('plugins-location')).toHaveTextContent(
'/plugins?scope=project&source=all&state=all',
'/project-config/plugins?scope=project&source=all&state=all',
));
expect(screen.getByLabelText('范围')).toHaveValue('project');
fireEvent.click(screen.getByRole('button', { name: '打开非法插件地址' }));
await waitFor(() => expect(screen.getByTestId('plugins-location')).toHaveTextContent(
'/plugins?scope=project&source=all&state=all',
'/project-config/plugins?scope=project&source=all&state=all',
));
expect(screen.getByLabelText('范围')).toHaveValue('project');
act(() => codingWorkspaceStore.setState({ activeProjectId: null, activeProject: null }));
await waitFor(() => expect(screen.getByTestId('plugins-location')).toHaveTextContent(
'/plugins?scope=all&source=all&state=all',
'/project-config/plugins?scope=all&source=all&state=all',
));
expect(screen.getByLabelText('范围')).toHaveValue('all');
expect(screen.getByText('当前没有打开的项目,已显示全部插件。')).toBeVisible();
@@ -339,7 +347,7 @@ describe('PluginsView', () => {
vi.spyOn(devicePackageStore.getState(), 'load').mockResolvedValue(undefined);
vi.spyOn(codingPluginsStore.getState(), 'load').mockResolvedValue(undefined);
render(<MemoryRouter initialEntries={['/plugins?scope=project&source=all&state=all']}><Plugins /></MemoryRouter>);
render(<MemoryRouter initialEntries={['/project-config/plugins?scope=project&source=all&state=all']}><Plugins /></MemoryRouter>);
for (const name of ['开发数据服务', 'Pi Web Search', 'makelore.retained']) {
const heading = await screen.findByRole('heading', { name });
@@ -388,7 +396,7 @@ describe('PluginsView', () => {
render(
<MemoryRouter initialEntries={[
'/plugins?scope=all&source=all&state=all&plugin=official%3Amakelore.notes',
'/project-config/plugins?scope=all&source=all&state=all&plugin=official%3Amakelore.notes',
]}>
<Plugins />
</MemoryRouter>,