chore: redirect to the correct template page routes (#14230)

This commit is contained in:
Kayla Washburn-Love
2024-08-12 13:12:28 -06:00
committed by GitHub
parent 59a80d70dc
commit 4c7132f08b
3 changed files with 115 additions and 19 deletions
@@ -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
View File
@@ -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>