diff --git a/editor.planx.uk/src/lib/featureFlags.ts b/editor.planx.uk/src/lib/featureFlags.ts
index b1e478c760..5fd7349747 100644
--- a/editor.planx.uk/src/lib/featureFlags.ts
+++ b/editor.planx.uk/src/lib/featureFlags.ts
@@ -1,5 +1,5 @@
// add/edit/remove feature flags in array below
-const AVAILABLE_FEATURE_FLAGS = ["SEARCH", "ADD_NEW_EDITOR"] as const;
+const AVAILABLE_FEATURE_FLAGS = [] as const;
type FeatureFlag = (typeof AVAILABLE_FEATURE_FLAGS)[number];
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx
index 51c1522901..bdfa6aba31 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx
@@ -8,7 +8,6 @@ import Link from "@mui/material/Link";
import { styled } from "@mui/material/styles";
import Tabs from "@mui/material/Tabs";
import Tooltip from "@mui/material/Tooltip";
-import { hasFeatureFlag } from "lib/featureFlags";
import React, { useState } from "react";
import { rootFlowPath } from "routes/utils";
import Permission from "ui/editor/Permission";
@@ -175,9 +174,7 @@ const Sidebar: React.FC = React.memo(() => {
- {hasFeatureFlag("SEARCH") && (
-
- )}
+
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/components/MembersTable.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/components/MembersTable.tsx
index cda4de0aad..45d32eed65 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/components/MembersTable.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/components/MembersTable.tsx
@@ -148,18 +148,20 @@ export const MembersTable = ({
))}
{showAddMemberButton && (
-
-
- {
- setInitialValues(undefined);
- setShowAddModal(true);
- }}
- >
- Add a new editor
-
-
-
+
+
+
+ {
+ setInitialValues(undefined);
+ setShowAddModal(true);
+ }}
+ >
+ Add a new editor
+
+
+
+
)}
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.serverSide.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.serverSide.test.tsx
index 22fd4e5db2..7d0fb98a28 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.serverSide.test.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.serverSide.test.tsx
@@ -5,7 +5,7 @@ import { vi } from "vitest";
import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";
import { userTriesToAddNewEditor } from "./helpers/userTriesToAddNewEditor";
import { mockTeamMembersData } from "./mocks/mockTeamMembersData";
-import { alreadyExistingUser } from "./mocks/mockUsers";
+import { alreadyExistingUser, mockPlatformAdminUser } from "./mocks/mockUsers";
let initialState: FullStore;
vi.mock(
@@ -22,6 +22,7 @@ describe("when a user fills in the 'add a new editor' form correctly but there i
beforeEach(async () => {
useStore.setState({
teamMembers: [...mockTeamMembersData, alreadyExistingUser],
+ user: mockPlatformAdminUser,
});
const { user } = await setupTeamMembersScreen();
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.userAlreadyExists.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.userAlreadyExists.test.tsx
index 11f53bc288..d2ac094305 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.userAlreadyExists.test.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.errors.userAlreadyExists.test.tsx
@@ -5,7 +5,7 @@ import { vi } from "vitest";
import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";
import { userTriesToAddNewEditor } from "./helpers/userTriesToAddNewEditor";
import { mockTeamMembersData } from "./mocks/mockTeamMembersData";
-import { alreadyExistingUser } from "./mocks/mockUsers";
+import { alreadyExistingUser, mockPlatformAdminUser } from "./mocks/mockUsers";
vi.mock(
"pages/FlowEditor/components/Team/queries/createAndAddUserToTeam.tsx",
@@ -23,6 +23,7 @@ describe("when a user fills in the 'add a new editor' form correctly but the use
beforeEach(async () => {
useStore.setState({
teamMembers: [...mockTeamMembersData, alreadyExistingUser],
+ user: mockPlatformAdminUser,
});
const { user } = await setupTeamMembersScreen();
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.noExistingMembers.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.noExistingMembers.test.tsx
index c3f5e64a4d..59a9aff7f2 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.noExistingMembers.test.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.noExistingMembers.test.tsx
@@ -3,6 +3,7 @@ import { useStore } from "pages/FlowEditor/lib/store";
import { TeamMember } from "../types";
import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";
+import { mockPlatformAdminUser } from "./mocks/mockUsers";
const mockTeamMembersDataWithNoTeamEditors: TeamMember[] = [
{
@@ -16,7 +17,10 @@ const mockTeamMembersDataWithNoTeamEditors: TeamMember[] = [
describe("when a user views the 'Team members' screen but there are no existing team editors listed", () => {
beforeEach(async () => {
- useStore.setState({ teamMembers: mockTeamMembersDataWithNoTeamEditors });
+ useStore.setState({
+ teamMembers: mockTeamMembersDataWithNoTeamEditors,
+ user: mockPlatformAdminUser,
+ });
const { getByText } = await setupTeamMembersScreen();
getByText("No members found");
});
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx
index c82b41cf71..cbf0765d4f 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx
@@ -11,7 +11,11 @@ import { EditorUpsertModal } from "../components/EditorUpsertModal";
import { setupTeamMembersScreen } from "./helpers/setupTeamMembersScreen";
import { userTriesToAddNewEditor } from "./helpers/userTriesToAddNewEditor";
import { mockTeamMembersData } from "./mocks/mockTeamMembersData";
-import { emptyTeamMemberObj } from "./mocks/mockUsers";
+import {
+ emptyTeamMemberObj,
+ mockPlainUser,
+ mockPlatformAdminUser,
+} from "./mocks/mockUsers";
vi.mock(
"pages/FlowEditor/components/Team/queries/createAndAddUserToTeam.tsx",
@@ -27,7 +31,11 @@ let initialState: FullStore;
describe("when a user presses 'add a new editor'", () => {
beforeEach(async () => {
- useStore.setState({ teamMembers: mockTeamMembersData, teamSlug: "planx" });
+ useStore.setState({
+ teamMembers: mockTeamMembersData,
+ user: mockPlatformAdminUser,
+ teamSlug: "planx",
+ });
const { user } = await setupTeamMembersScreen();
const teamEditorsTable = screen.getByTestId("team-editors");
@@ -45,8 +53,13 @@ describe("when a user presses 'add a new editor'", () => {
describe("when a user fills in the 'add a new editor' form correctly", () => {
afterAll(() => useStore.setState(initialState));
+
beforeEach(async () => {
- useStore.setState({ teamMembers: mockTeamMembersData, teamSlug: "planx" });
+ useStore.setState({
+ teamMembers: mockTeamMembersData,
+ user: mockPlatformAdminUser,
+ teamSlug: "planx",
+ });
const { user } = await setupTeamMembersScreen();
await userTriesToAddNewEditor(user);
});
@@ -97,6 +110,7 @@ describe("'add a new editor' button is hidden from Templates team", () => {
beforeEach(async () => {
useStore.setState({
teamMembers: mockTeamMembersData,
+ user: mockPlatformAdminUser,
teamSlug: "templates",
});
});
@@ -109,3 +123,21 @@ describe("'add a new editor' button is hidden from Templates team", () => {
expect(addEditorButton).not.toBeInTheDocument();
});
});
+
+describe("when a user is not a platform admin", () => {
+ beforeEach(async () => {
+ useStore.setState({
+ teamMembers: mockTeamMembersData,
+ user: mockPlainUser,
+ teamSlug: "templates",
+ });
+ });
+
+ it("hides the button from non-admin users", async () => {
+ const { user: _user } = await setupTeamMembersScreen();
+ const teamEditorsTable = screen.getByTestId("team-editors");
+ const addEditorButton =
+ within(teamEditorsTable).queryByText("Add a new editor");
+ expect(addEditorButton).not.toBeInTheDocument();
+ });
+});
diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx
index 7527470705..77c05d3c5e 100644
--- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx
+++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx
@@ -192,6 +192,7 @@ describe("when a user is not a platform admin", () => {
await setupTeamMembersScreen();
});
+
it("does not show an edit button", async () => {
const teamEditorsTable = screen.getByTestId("team-editors");
const addEditorButton =
diff --git a/editor.planx.uk/src/pages/layout/LoadingLayout.tsx b/editor.planx.uk/src/pages/layout/LoadingLayout.tsx
new file mode 100644
index 0000000000..3198b87999
--- /dev/null
+++ b/editor.planx.uk/src/pages/layout/LoadingLayout.tsx
@@ -0,0 +1,10 @@
+import DelayedLoadingIndicator from "components/DelayedLoadingIndicator";
+import React from "react";
+import { useLoadingRoute, View } from "react-navi";
+
+export const loadingView = () => ;
+
+export const LoadingLayout = () => {
+ const isLoading = useLoadingRoute();
+ return isLoading ? : ;
+};
diff --git a/editor.planx.uk/src/routes/index.tsx b/editor.planx.uk/src/routes/index.tsx
index 831a73be98..c1cad20ee9 100644
--- a/editor.planx.uk/src/routes/index.tsx
+++ b/editor.planx.uk/src/routes/index.tsx
@@ -1,4 +1,5 @@
-import { lazy, map, mount, redirect, route } from "navi";
+import { compose, lazy, map, mount, redirect, route, withView } from "navi";
+import { loadingView } from "pages/layout/LoadingLayout";
import * as React from "react";
import { client } from "../lib/graphql";
@@ -58,27 +59,36 @@ const editorRoutes = mount({
const mountPayRoutes = () =>
map(async () => {
+ compose(withView(loadingView));
return lazy(() => import("./pay"));
});
export default isPreviewOnlyDomain
- ? mount({
- "/:team/:flow/published": lazy(() => import("./published")), // XXX: keeps old URL working, but only for the team listed in the domain.
- "/:flow": lazy(() => import("./published")),
- "/:flow/pay": mountPayRoutes(),
- // XXX: We're not sure where to redirect `/` to so for now we'll just return the default 404
- // "/": redirect("somewhere?"),
- })
- : mount({
- "/:team/:flow/published": lazy(() => import("./published")), // loads current published flow if exists, or throws Not Found if unpublished
- "/canterbury/find-out-if-you-need-planning-permission/preview": map(
- async (req) =>
- redirect(
- `/canterbury/find-out-if-you-need-planning-permission/published${req?.search}`,
- ),
- ), // temporary redirect while Canterbury works with internal IT to update advertised service links
- "/:team/:flow/preview": lazy(() => import("./preview")), // loads current draft flow and latest published external portals, or throws Not Found if any external portal is unpublished
- "/:team/:flow/draft": lazy(() => import("./draft")), // loads current draft flow and draft external portals
- "/:team/:flow/pay": mountPayRoutes(),
- "*": editorRoutes,
- });
+ ? compose(
+ withView(loadingView),
+
+ mount({
+ "/:team/:flow/published": lazy(() => import("./published")), // XXX: keeps old URL working, but only for the team listed in the domain.
+ "/:flow": lazy(() => import("./published")),
+ "/:flow/pay": mountPayRoutes(),
+ // XXX: We're not sure where to redirect `/` to so for now we'll just return the default 404
+ // "/": redirect("somewhere?"),
+ }),
+ )
+ : compose(
+ withView(loadingView),
+
+ mount({
+ "/:team/:flow/published": lazy(() => import("./published")), // loads current published flow if exists, or throws Not Found if unpublished
+ "/canterbury/find-out-if-you-need-planning-permission/preview": map(
+ async (req) =>
+ redirect(
+ `/canterbury/find-out-if-you-need-planning-permission/published${req?.search}`,
+ ),
+ ), // temporary redirect while Canterbury works with internal IT to update advertised service links
+ "/:team/:flow/preview": lazy(() => import("./preview")), // loads current draft flow and latest published external portals, or throws Not Found if any external portal is unpublished
+ "/:team/:flow/draft": lazy(() => import("./draft")), // loads current draft flow and draft external portals
+ "/:team/:flow/pay": mountPayRoutes(),
+ "*": editorRoutes,
+ }),
+ );