mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
chore: redirect to the correct template page routes (#14230)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { waitFor } from "@testing-library/react";
|
||||
import { API } from "api/api";
|
||||
import * as M from "testHelpers/entities";
|
||||
import { renderWithAuth } from "testHelpers/renderHelpers";
|
||||
import { TemplateRedirectController } from "./TemplateRedirectController";
|
||||
|
||||
const renderTemplateRedirectController = (route: string) => {
|
||||
return renderWithAuth(<TemplateRedirectController />, {
|
||||
route,
|
||||
path: "/templates/:organization?/:template",
|
||||
});
|
||||
};
|
||||
|
||||
it("redirects from multi-org to single-org", async () => {
|
||||
const { router } = renderTemplateRedirectController(
|
||||
`/templates/${M.MockTemplate.organization_name}/${M.MockTemplate.name}`,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(router.state.location.pathname).toEqual(
|
||||
`/templates/${M.MockTemplate.name}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("redirects from single-org to multi-org", async () => {
|
||||
jest
|
||||
.spyOn(API, "getOrganizations")
|
||||
.mockResolvedValueOnce([M.MockDefaultOrganization, M.MockOrganization2]);
|
||||
|
||||
const { router } = renderTemplateRedirectController(
|
||||
`/templates/${M.MockTemplate.name}`,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(router.state.location.pathname).toEqual(
|
||||
`/templates/${M.MockDefaultOrganization.name}/${M.MockTemplate.name}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { FC } from "react";
|
||||
import { Navigate, Outlet, useLocation, useParams } from "react-router-dom";
|
||||
import type { Organization } from "api/typesGenerated";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
|
||||
export const TemplateRedirectController: FC = () => {
|
||||
const { organizations, showOrganizations } = useDashboard();
|
||||
const { organization, template } = useParams() as {
|
||||
organization?: string;
|
||||
template: string;
|
||||
};
|
||||
const location = useLocation();
|
||||
|
||||
// We redirect templates without an organization to the default organization,
|
||||
// as that's likely what any links floating around expect.
|
||||
if (showOrganizations && !organization) {
|
||||
const extraPath = removePrefix(location.pathname, `/templates/${template}`);
|
||||
|
||||
return (
|
||||
<Navigate
|
||||
to={`/templates/${getOrganizationNameByDefault(
|
||||
organizations,
|
||||
)}/${template}${extraPath}${location.search}`}
|
||||
replace
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// `showOrganizations` can only be false when there is a single organization,
|
||||
// so it's safe to throw away the organization name.
|
||||
if (!showOrganizations && organization) {
|
||||
const extraPath = removePrefix(
|
||||
location.pathname,
|
||||
`/templates/${organization}/${template}`,
|
||||
);
|
||||
|
||||
return (
|
||||
<Navigate
|
||||
to={`/templates/${template}${extraPath}${location.search}`}
|
||||
replace
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <Outlet />;
|
||||
};
|
||||
|
||||
const getOrganizationNameByDefault = (organizations: Organization[]) =>
|
||||
organizations.find((org) => org.is_default)?.name;
|
||||
|
||||
// I really hate doing it this way, but React Router does not provide a better way.
|
||||
const removePrefix = (self: string, prefix: string) =>
|
||||
self.startsWith(prefix) ? self.slice(prefix.length) : self;
|
||||
+22
-19
@@ -1,4 +1,4 @@
|
||||
import { Suspense, lazy } from "react";
|
||||
import { lazy, Suspense } from "react";
|
||||
import {
|
||||
createBrowserRouter,
|
||||
createRoutesFromChildren,
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Outlet,
|
||||
Route,
|
||||
} from "react-router-dom";
|
||||
import { TemplateRedirectController } from "pages/TemplatePage/TemplateRedirectController";
|
||||
import { Loader } from "./components/Loader/Loader";
|
||||
import { RequireAuth } from "./contexts/auth/RequireAuth";
|
||||
import { DashboardLayout } from "./modules/dashboard/DashboardLayout";
|
||||
@@ -289,27 +290,29 @@ const RoutesWithSuspense = () => {
|
||||
const templateRouter = () => {
|
||||
return (
|
||||
<Route path=":template">
|
||||
<Route element={<TemplateLayout />}>
|
||||
<Route index element={<TemplateSummaryPage />} />
|
||||
<Route path="docs" element={<TemplateDocsPage />} />
|
||||
<Route path="files" element={<TemplateFilesPage />} />
|
||||
<Route path="versions" element={<TemplateVersionsPage />} />
|
||||
<Route path="embed" element={<TemplateEmbedPage />} />
|
||||
<Route path="insights" element={<TemplateInsightsPage />} />
|
||||
</Route>
|
||||
<Route element={<TemplateRedirectController />}>
|
||||
<Route element={<TemplateLayout />}>
|
||||
<Route index element={<TemplateSummaryPage />} />
|
||||
<Route path="docs" element={<TemplateDocsPage />} />
|
||||
<Route path="files" element={<TemplateFilesPage />} />
|
||||
<Route path="versions" element={<TemplateVersionsPage />} />
|
||||
<Route path="embed" element={<TemplateEmbedPage />} />
|
||||
<Route path="insights" element={<TemplateInsightsPage />} />
|
||||
</Route>
|
||||
|
||||
<Route path="workspace" element={<CreateWorkspacePage />} />
|
||||
<Route path="workspace" element={<CreateWorkspacePage />} />
|
||||
|
||||
<Route path="settings" element={<TemplateSettingsLayout />}>
|
||||
<Route index element={<TemplateSettingsPage />} />
|
||||
<Route path="permissions" element={<TemplatePermissionsPage />} />
|
||||
<Route path="variables" element={<TemplateVariablesPage />} />
|
||||
<Route path="schedule" element={<TemplateSchedulePage />} />
|
||||
</Route>
|
||||
<Route path="settings" element={<TemplateSettingsLayout />}>
|
||||
<Route index element={<TemplateSettingsPage />} />
|
||||
<Route path="permissions" element={<TemplatePermissionsPage />} />
|
||||
<Route path="variables" element={<TemplateVariablesPage />} />
|
||||
<Route path="schedule" element={<TemplateSchedulePage />} />
|
||||
</Route>
|
||||
|
||||
<Route path="versions">
|
||||
<Route path=":version">
|
||||
<Route index element={<TemplateVersionPage />} />
|
||||
<Route path="versions">
|
||||
<Route path=":version">
|
||||
<Route index element={<TemplateVersionPage />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
Reference in New Issue
Block a user