diff --git a/frontend/package.json b/frontend/package.json
index 847b3a79a2..7fa4bbd3e8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -51,8 +51,8 @@
"@types/jest": "27.4.1",
"@types/lodash.clonedeep": "4.5.6",
"@types/node": "17.0.18",
- "@types/react": "17.0.40",
- "@types/react-dom": "17.0.13",
+ "@types/react": "17.0.41",
+ "@types/react-dom": "17.0.14",
"@types/react-router-dom": "5.3.3",
"@types/react-test-renderer": "17.0.1",
"@types/react-timeago": "4.1.3",
diff --git a/frontend/src/component/App.tsx b/frontend/src/component/App.tsx
index 3b2094721d..64b200ea02 100644
--- a/frontend/src/component/App.tsx
+++ b/frontend/src/component/App.tsx
@@ -1,5 +1,4 @@
import ConditionallyRender from './common/ConditionallyRender';
-import EnvironmentSplash from './common/EnvironmentSplash/EnvironmentSplash';
import Feedback from './common/Feedback/Feedback';
import LayoutPicker from './layout/LayoutPicker/LayoutPicker';
import Loader from './common/Loader/Loader';
@@ -10,28 +9,15 @@ import ToastRenderer from './common/ToastRenderer/ToastRenderer';
import styles from './styles.module.scss';
import { Redirect, Route, Switch } from 'react-router-dom';
import { routes } from './menu/routes';
-import { useAuthDetails } from '../hooks/api/getters/useAuth/useAuthDetails';
-import { useAuthUser } from '../hooks/api/getters/useAuth/useAuthUser';
-import { useAuthSplash } from '../hooks/api/getters/useAuth/useAuthSplash';
+import { useAuthDetails } from 'hooks/api/getters/useAuth/useAuthDetails';
+import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
+import { SplashPageRedirect } from 'component/splash/SplashPageRedirect/SplashPageRedirect';
export const App = () => {
- const { splash, refetchSplash } = useAuthSplash();
const { authDetails } = useAuthDetails();
const { user } = useAuthUser();
-
const isLoggedIn = Boolean(user?.id);
const hasFetchedAuth = Boolean(authDetails || user);
- const showEnvSplash = isLoggedIn && splash?.environment === false;
-
- const renderMainLayoutRoutes = () => {
- return routes.filter(route => route.layout === 'main').map(renderRoute);
- };
-
- const renderStandaloneRoutes = () => {
- return routes
- .filter(route => route.layout === 'standalone')
- .map(renderRoute);
- };
const isUnauthorized = (): boolean => {
return !isLoggedIn;
@@ -73,34 +59,22 @@ export const App = () => {
elseShow={
-
-
- }
- elseShow={
-
-
-
- {renderMainLayoutRoutes()}
- {renderStandaloneRoutes()}
-
-
-
-
-
- }
- />
+
+
+
+ {routes.map(renderRoute)}
+
+
+
+
+
+
}
/>
diff --git a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ConstraintAccordionEditBody.tsx b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ConstraintAccordionEditBody.tsx
index dc8612f926..5882a4aff7 100644
--- a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ConstraintAccordionEditBody.tsx
+++ b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ConstraintAccordionEditBody.tsx
@@ -5,10 +5,10 @@ import { CANCEL } from '../ConstraintAccordionEdit';
import { ConstraintFormHeader } from './ConstraintFormHeader/ConstraintFormHeader';
import { useStyles } from './ConstraintAccordionEditBody.styles';
import React from 'react';
-import { Alert } from '@material-ui/lab';
import { newOperators } from 'constants/operators';
import ConditionallyRender from 'component/common/ConditionallyRender/ConditionallyRender';
import { oneOf } from 'utils/one-of';
+import { OperatorUpgradeAlert } from 'component/common/OperatorUpgradeAlert/OperatorUpgradeAlert';
interface IConstraintAccordionBody {
localConstraint: IConstraint;
@@ -37,12 +37,7 @@ export const ConstraintAccordionEditBody: React.FC<
<>
- In order to use this constraint operator, you need to
- update your SDK to the latest version.
-
- }
+ show={}
/>
diff --git a/frontend/src/component/common/FormTemplate/FormTemplate.tsx b/frontend/src/component/common/FormTemplate/FormTemplate.tsx
index 08ff624225..dad1035223 100644
--- a/frontend/src/component/common/FormTemplate/FormTemplate.tsx
+++ b/frontend/src/component/common/FormTemplate/FormTemplate.tsx
@@ -38,7 +38,7 @@ const FormTemplate: React.FC
= ({
const { setToastData } = useToast();
const styles = useStyles();
const commonStyles = useCommonStyles();
- const smallScreen = useMediaQuery(`(max-width:${900}px)`);
+ const smallScreen = useMediaQuery(`(max-width:${899}px)`);
const copyCommand = () => {
if (copy(formatApiCode())) {
diff --git a/frontend/src/component/common/OperatorUpgradeAlert/OperatorUpgradeAlert.tsx b/frontend/src/component/common/OperatorUpgradeAlert/OperatorUpgradeAlert.tsx
new file mode 100644
index 0000000000..8be54f080b
--- /dev/null
+++ b/frontend/src/component/common/OperatorUpgradeAlert/OperatorUpgradeAlert.tsx
@@ -0,0 +1,23 @@
+import { Alert } from '@material-ui/lab';
+
+export const OperatorUpgradeAlert = () => {
+ return (
+
+ Remember to update your Unleash client! New operators require new
+ SDK versions. .
+
+ );
+};
+
+const OperatorDocsLink = () => {
+ return (
+
+ Read more
+
+ );
+};
diff --git a/frontend/src/component/layout/LayoutPicker/LayoutPicker.jsx b/frontend/src/component/layout/LayoutPicker/LayoutPicker.jsx
index 68b6172b91..ebf4b8754d 100644
--- a/frontend/src/component/layout/LayoutPicker/LayoutPicker.jsx
+++ b/frontend/src/component/layout/LayoutPicker/LayoutPicker.jsx
@@ -17,10 +17,12 @@ const LayoutPicker = ({ children }) => {
const isResetPasswordSuccessPage = matchPath(pathname, {
path: '/reset-password-success',
});
-
const isForgottenPasswordPage = matchPath(pathname, {
path: '/forgotten-password',
});
+ const isSplashPage = matchPath(pathname, {
+ path: '/splash/:id',
+ });
const is404 = matchPath(pathname, { path: '/404' });
@@ -30,6 +32,7 @@ const LayoutPicker = ({ children }) => {
isChangePasswordPage ||
isResetPasswordSuccessPage ||
isForgottenPasswordPage ||
+ isSplashPage ||
is404
);
};
diff --git a/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap
index 2e2f0bce48..c0b21e9ab4 100644
--- a/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap
+++ b/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap
@@ -4,7 +4,13 @@ exports[`returns all baseRoutes 1`] = `
Array [
Object {
"component": [Function],
- "layout": "main",
+ "menu": Object {},
+ "path": "/splash/:splashId",
+ "title": "Unleash",
+ "type": "protected",
+ },
+ Object {
+ "component": [Function],
"menu": Object {},
"parent": "/projects",
"path": "/projects/create",
@@ -13,7 +19,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:id/edit",
@@ -22,7 +27,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/archive",
"path": "/projects/:id/archived",
@@ -31,7 +35,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/projects/:id/features/:name/:activeTab",
"path": "/projects/:id/features/:name/:activeTab/copy",
@@ -40,7 +43,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:projectId/features/:featureId/edit",
@@ -50,7 +52,6 @@ Array [
Object {
"component": [Function],
"flags": "E",
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:projectId/features/:featureId",
@@ -59,7 +60,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:id/features/:name/:activeTab",
@@ -68,7 +68,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/projects/:id/features",
"path": "/projects/:projectId/create-toggle",
@@ -77,7 +76,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/features",
"path": "/projects/:projectId/features2/:name",
@@ -87,7 +85,6 @@ Array [
Object {
"component": [Function],
"flag": "P",
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:id/:activeTab",
@@ -97,7 +94,6 @@ Array [
Object {
"component": [Function],
"flag": "P",
- "layout": "main",
"menu": Object {},
"parent": "/projects",
"path": "/projects/:id",
@@ -106,7 +102,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"mobile": true,
},
@@ -116,7 +111,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/features",
"path": "/features/:activeTab/:name",
@@ -125,7 +119,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"mobile": true,
},
@@ -135,7 +128,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/applications",
"path": "/applications/:name",
@@ -144,7 +136,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -156,7 +147,6 @@ Array [
Object {
"component": [Function],
"flag": "C",
- "layout": "main",
"menu": Object {},
"parent": "/context",
"path": "/context/create",
@@ -166,7 +156,6 @@ Array [
Object {
"component": [Function],
"flag": "C",
- "layout": "main",
"menu": Object {},
"parent": "/context",
"path": "/context/edit/:name",
@@ -176,7 +165,6 @@ Array [
Object {
"component": [Function],
"flag": "C",
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -187,7 +175,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/strategies",
"path": "/strategies/create",
@@ -196,7 +183,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/strategies",
"path": "/strategies/:name/edit",
@@ -205,7 +191,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/strategies",
"path": "/strategies/:name",
@@ -214,7 +199,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -225,7 +209,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/environments",
"path": "/environments/create",
@@ -234,7 +217,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"path": "/environments/:id",
"title": "Edit",
@@ -243,7 +225,6 @@ Array [
Object {
"component": [Function],
"flag": "EEA",
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -254,7 +235,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/tag-types",
"path": "/tag-types/create",
@@ -263,7 +243,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/tag-types",
"path": "/tag-types/edit/:name",
@@ -272,7 +251,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -283,7 +261,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/addons",
"path": "/addons/create/:providerId",
@@ -292,7 +269,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/addons",
"path": "/addons/edit/:addonId",
@@ -302,7 +278,6 @@ Array [
Object {
"component": [Function],
"hidden": false,
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -315,7 +290,6 @@ Array [
"component": [Function],
"flag": "SE",
"hidden": false,
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -326,7 +300,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/history",
"path": "/history/:toggleName",
@@ -335,7 +308,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"adminSettings": true,
},
@@ -345,7 +317,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"path": "/archive",
"title": "Archived Toggles",
@@ -353,7 +324,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/admin",
"path": "/admin/api/create-token",
@@ -363,7 +333,6 @@ Array [
Object {
"component": [Function],
"flag": "RE",
- "layout": "main",
"menu": Object {},
"path": "/admin/create-project-role",
"title": "Create",
@@ -372,7 +341,6 @@ Array [
Object {
"component": [Function],
"flag": "RE",
- "layout": "main",
"menu": Object {},
"path": "/admin/roles/:id/edit",
"title": "Edit",
@@ -380,7 +348,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"advanced": true,
"mobile": true,
@@ -392,7 +359,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"adminSettings": true,
},
@@ -403,7 +369,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {},
"parent": "/admin",
"path": "/admin/create-user",
@@ -412,7 +377,6 @@ Array [
},
Object {
"component": [Function],
- "layout": "main",
"menu": Object {
"adminSettings": true,
},
@@ -424,7 +388,6 @@ Array [
Object {
"component": [Function],
"flag": "RE",
- "layout": "main",
"menu": Object {
"adminSettings": true,
},
@@ -436,7 +399,6 @@ Array [
Object {
"component": [Function],
"hidden": false,
- "layout": "main",
"menu": Object {},
"path": "/admin",
"title": "Admin",
diff --git a/frontend/src/component/menu/routes.js b/frontend/src/component/menu/routes.js
index a352a18d82..bd96b0533c 100644
--- a/frontend/src/component/menu/routes.js
+++ b/frontend/src/component/menu/routes.js
@@ -46,18 +46,26 @@ import { EventHistoryPage } from '../history/EventHistoryPage/EventHistoryPage';
import { FeatureEventHistoryPage } from '../history/FeatureEventHistoryPage/FeatureEventHistoryPage';
import { CreateStrategy } from '../strategies/CreateStrategy/CreateStrategy';
import { EditStrategy } from '../strategies/EditStrategy/EditStrategy';
-import { SegmentsList } from 'component/segments/SegmentList/SegmentList';
+import { SegmentsList } from '../segments/SegmentList/SegmentList';
+import { SplashPage } from '../splash/SplashPage/SplashPage';
export const routes = [
- // Project
+ // Splash
+ {
+ path: '/splash/:splashId',
+ title: 'Unleash',
+ component: SplashPage,
+ type: 'protected',
+ menu: {},
+ },
+ // Project
{
path: '/projects/create',
parent: '/projects',
title: 'Create',
component: CreateProject,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -66,7 +74,6 @@ export const routes = [
title: ':id',
component: EditProject,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -75,7 +82,6 @@ export const routes = [
parent: '/archive',
component: RedirectArchive,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -84,7 +90,6 @@ export const routes = [
title: 'Copy',
component: CopyFeatureToggle,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -93,7 +98,6 @@ export const routes = [
title: 'Edit Feature',
component: EditFeature,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -102,7 +106,6 @@ export const routes = [
title: 'FeatureView',
component: FeatureView,
type: 'protected',
- layout: 'main',
flags: E,
menu: {},
},
@@ -112,7 +115,6 @@ export const routes = [
title: ':name',
component: FeatureView,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -121,7 +123,6 @@ export const routes = [
title: 'Create feature toggle',
component: CreateFeature,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -130,7 +131,6 @@ export const routes = [
title: ':name',
component: RedirectFeatureView,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -140,7 +140,6 @@ export const routes = [
component: Project,
flag: P,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -150,7 +149,6 @@ export const routes = [
component: Project,
flag: P,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -158,7 +156,6 @@ export const routes = [
title: 'Projects',
component: ProjectListNew,
type: 'protected',
- layout: 'main',
menu: { mobile: true },
},
@@ -169,7 +166,6 @@ export const routes = [
title: ':name',
component: RedirectFeatureView,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -177,7 +173,6 @@ export const routes = [
title: 'Feature Toggles',
component: FeatureToggleListContainer,
type: 'protected',
- layout: 'main',
menu: { mobile: true },
},
@@ -188,7 +183,6 @@ export const routes = [
parent: '/applications',
component: ApplicationEdit,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -196,7 +190,6 @@ export const routes = [
title: 'Applications',
component: ApplicationList,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
},
@@ -207,7 +200,6 @@ export const routes = [
title: 'Create',
component: CreateContext,
type: 'protected',
- layout: 'main',
flag: C,
menu: {},
},
@@ -217,7 +209,6 @@ export const routes = [
title: ':name',
component: EditContext,
type: 'protected',
- layout: 'main',
flag: C,
menu: {},
},
@@ -227,7 +218,6 @@ export const routes = [
component: ContextList,
type: 'protected',
flag: C,
- layout: 'main',
menu: { mobile: true, advanced: true },
},
@@ -238,7 +228,6 @@ export const routes = [
parent: '/strategies',
component: CreateStrategy,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -247,7 +236,6 @@ export const routes = [
parent: '/strategies',
component: EditStrategy,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -256,7 +244,6 @@ export const routes = [
parent: '/strategies',
component: StrategyView,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -264,7 +251,6 @@ export const routes = [
title: 'Strategies',
component: StrategiesList,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
},
{
@@ -273,7 +259,6 @@ export const routes = [
component: CreateEnvironment,
parent: '/environments',
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -281,7 +266,6 @@ export const routes = [
title: 'Edit',
component: EditEnvironment,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -289,7 +273,6 @@ export const routes = [
title: 'Environments',
component: EnvironmentList,
type: 'protected',
- layout: 'main',
flag: EEA,
menu: { mobile: true, advanced: true },
},
@@ -301,7 +284,6 @@ export const routes = [
title: 'Create',
component: CreateTagType,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -310,7 +292,6 @@ export const routes = [
title: ':name',
component: EditTagType,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -318,7 +299,6 @@ export const routes = [
title: 'Tag types',
component: TagTypeList,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
},
@@ -329,7 +309,6 @@ export const routes = [
title: 'Create',
component: CreateAddon,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -338,7 +317,6 @@ export const routes = [
title: 'Edit',
component: EditAddon,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -347,7 +325,6 @@ export const routes = [
component: AddonList,
hidden: false,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
},
@@ -359,7 +336,6 @@ export const routes = [
component: SegmentsList,
hidden: false,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
flag: SE,
},
@@ -371,7 +347,6 @@ export const routes = [
parent: '/history',
component: FeatureEventHistoryPage,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -379,7 +354,6 @@ export const routes = [
title: 'Event History',
component: EventHistoryPage,
type: 'protected',
- layout: 'main',
menu: { adminSettings: true },
},
@@ -389,7 +363,6 @@ export const routes = [
title: 'Archived Toggles',
component: ArchiveListContainer,
type: 'protected',
- layout: 'main',
menu: {},
},
@@ -400,7 +373,6 @@ export const routes = [
title: 'API access',
component: CreateApiToken,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -408,7 +380,6 @@ export const routes = [
title: 'Create',
component: CreateProjectRole,
type: 'protected',
- layout: 'main',
menu: {},
flag: RE,
},
@@ -417,7 +388,6 @@ export const routes = [
title: 'Edit',
component: EditProjectRole,
type: 'protected',
- layout: 'main',
menu: {},
flag: RE,
},
@@ -426,7 +396,6 @@ export const routes = [
title: 'Edit',
component: EditUser,
type: 'protected',
- layout: 'main',
menu: {},
hidden: true,
},
@@ -436,7 +405,6 @@ export const routes = [
title: 'API access',
component: AdminApi,
type: 'protected',
- layout: 'main',
menu: { mobile: true, advanced: true },
},
{
@@ -445,7 +413,6 @@ export const routes = [
title: 'Users',
component: AdminUsers,
type: 'protected',
- layout: 'main',
menu: { adminSettings: true },
},
{
@@ -454,7 +421,6 @@ export const routes = [
title: 'Users',
component: CreateUser,
type: 'protected',
- layout: 'main',
menu: {},
},
{
@@ -463,7 +429,6 @@ export const routes = [
title: 'Single Sign-On',
component: AuthSettings,
type: 'protected',
- layout: 'main',
menu: { adminSettings: true },
},
{
@@ -472,7 +437,6 @@ export const routes = [
component: AdminInvoice,
hidden: true,
type: 'protected',
- layout: 'main',
menu: { adminSettings: true },
},
{
@@ -481,7 +445,6 @@ export const routes = [
title: 'Project Roles',
component: ProjectRoles,
type: 'protected',
- layout: 'main',
flag: RE,
menu: { adminSettings: true },
},
@@ -491,7 +454,6 @@ export const routes = [
component: Admin,
hidden: false,
type: 'protected',
- layout: 'main',
menu: {},
},
/* If you update this route path, make sure you update the path in SWRProvider.tsx */
@@ -502,7 +464,6 @@ export const routes = [
component: Login,
type: 'unprotected',
hidden: true,
- layout: 'standalone',
menu: {},
},
/* If you update this route path, make sure you update the path in SWRProvider.tsx */
@@ -512,7 +473,6 @@ export const routes = [
hidden: true,
component: NewUser,
type: 'unprotected',
- layout: 'standalone',
menu: {},
},
/* If you update this route path, make sure you update the path in SWRProvider.tsx */
@@ -522,7 +482,6 @@ export const routes = [
hidden: true,
component: ResetPassword,
type: 'unprotected',
- layout: 'standalone',
menu: {},
},
{
@@ -531,7 +490,6 @@ export const routes = [
hidden: true,
component: ForgottenPassword,
type: 'unprotected',
- layout: 'standalone',
menu: {},
},
];
diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
index 5482d29b24..8a94309fe8 100644
--- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
+++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
@@ -22,7 +22,7 @@ interface IProjectInfoProps {
memberCount: number;
featureCount: number;
health: number;
- description: string;
+ description?: string;
}
const ProjectInfo = ({
@@ -42,10 +42,11 @@ const ProjectInfo = ({
}
const LONG_DESCRIPTION = 100;
+ const isShortDescription =
+ !description || description.length < LONG_DESCRIPTION;
const permissionButtonClass = classnames({
- [styles.permissionButtonShortDesc]:
- description.length < LONG_DESCRIPTION,
+ [styles.permissionButtonShortDesc]: isShortDescription,
});
const permissionButton = (
diff --git a/frontend/src/component/splash/SplashPage/SplashPage.tsx b/frontend/src/component/splash/SplashPage/SplashPage.tsx
new file mode 100644
index 0000000000..96c20f6ed3
--- /dev/null
+++ b/frontend/src/component/splash/SplashPage/SplashPage.tsx
@@ -0,0 +1,72 @@
+import { Switch, Route, useHistory, Redirect } from 'react-router-dom';
+import { SplashPageEnvironments } from '../SplashPageEnvironments/SplashPageEnvironments';
+import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
+import useSplashApi from 'hooks/api/actions/useSplashApi/useSplashApi';
+import { SplashPageOperators } from 'component/splash/SplashPageOperators/SplashPageOperators';
+import { useEffect } from 'react';
+import { useAuthSplash } from 'hooks/api/getters/useAuth/useAuthSplash';
+
+// All known splash IDs.
+export const splashIds = ['environments', 'operators'] as const;
+
+// Active splash IDs that may be shown to the user.
+export const activeSplashIds: SplashId[] = ['operators'];
+
+export type SplashId = typeof splashIds[number];
+
+export const SplashPage = () => {
+ const splashId = useRequiredPathParam('splashId');
+ const isKnownId = isKnownSplashId(splashId);
+ const { refetchSplash } = useAuthSplash();
+ const { setSplashSeen } = useSplashApi();
+
+ // Close the splash "modal" on escape.
+ useNavigationOnKeydown('Escape', '/');
+
+ // Mark the splash ID as seen.
+ useEffect(() => {
+ if (splashId && isKnownId) {
+ setSplashSeen(splashId)
+ .then(() => refetchSplash())
+ .catch(console.warn);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [splashId, isKnownId]);
+
+ if (!isKnownId) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const useNavigationOnKeydown = (key: string, path: string) => {
+ const { push } = useHistory();
+
+ useEffect(() => {
+ const handler = (event: KeyboardEvent) => {
+ if (event.code === key) {
+ push(path);
+ }
+ };
+
+ window.addEventListener('keydown', handler);
+ return () => window.removeEventListener('keydown', handler);
+ }, [key, path, push]);
+};
+
+const isKnownSplashId = (value: string): value is SplashId => {
+ return (splashIds as Readonly).includes(value);
+};
diff --git a/frontend/src/component/common/EnvironmentSplash/EnvironmentSplash.styles.ts b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironments.styles.ts
similarity index 100%
rename from frontend/src/component/common/EnvironmentSplash/EnvironmentSplash.styles.ts
rename to frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironments.styles.ts
diff --git a/frontend/src/component/common/EnvironmentSplash/EnvironmentSplash.tsx b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironments.tsx
similarity index 89%
rename from frontend/src/component/common/EnvironmentSplash/EnvironmentSplash.tsx
rename to frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironments.tsx
index 9490398d42..5bb5ae304e 100644
--- a/frontend/src/component/common/EnvironmentSplash/EnvironmentSplash.tsx
+++ b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironments.tsx
@@ -1,33 +1,25 @@
-import Splash from '../Splash/Splash';
-import EnvironmentSplashPage from './EnvironmentSplashPage/EnvironmentSplashPage';
+import { SplashPageEnvironmentsContent } from 'component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent';
+import { SplashPageEnvironmentsContainer } from 'component/splash/SplashPageEnvironments/SplashPageEnvironmentsContainer/SplashPageEnvironmentsContainer';
import { VpnKey, CloudCircle } from '@material-ui/icons';
-import { useStyles } from './EnvironmentSplash.styles';
-import { ReactComponent as Logo1 } from '../../../assets/img/splash_env1.svg';
-import { ReactComponent as Logo2 } from '../../../assets/img/splash_env2.svg';
-import { useEffect } from 'react';
-import useSplashApi from '../../../hooks/api/actions/useSplashApi/useSplashApi';
+import { useStyles } from 'component/splash/SplashPageEnvironments/SplashPageEnvironments.styles';
+import { ReactComponent as Logo1 } from 'assets/img/splash_env1.svg';
+import { ReactComponent as Logo2 } from 'assets/img/splash_env2.svg';
+import { useHistory } from 'react-router-dom';
-interface IEnvironmentSplashProps {
- onFinish: (status: boolean) => void;
-}
-
-const ENVIRONMENT_SPLASH_ID = 'environment';
-
-const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
+export const SplashPageEnvironments = () => {
const styles = useStyles();
- const { setSplashSeen } = useSplashApi();
+ const { push } = useHistory();
- useEffect(() => {
- setSplashSeen(ENVIRONMENT_SPLASH_ID);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ const onFinish = () => {
+ push('/');
+ };
return (
<>
-
@@ -61,7 +53,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
}
image={}
/>,
-
@@ -79,7 +71,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
}
image={}
/>,
-
@@ -99,7 +91,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
}
image={}
/>,
-
@@ -125,7 +117,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
}
image={}
/>,
- Want to know more?
@@ -202,5 +194,3 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => {
>
);
};
-
-export default EnvironmentSplash;
diff --git a/frontend/src/component/common/EnvironmentSplash/EnvironmentSplashPage/EnvironmentSplashPage.tsx b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContainer/SplashPageEnvironmentsContainer.tsx
similarity index 72%
rename from frontend/src/component/common/EnvironmentSplash/EnvironmentSplashPage/EnvironmentSplashPage.tsx
rename to frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContainer/SplashPageEnvironmentsContainer.tsx
index 026ad2d32d..0641bd1a6e 100644
--- a/frontend/src/component/common/EnvironmentSplash/EnvironmentSplashPage/EnvironmentSplashPage.tsx
+++ b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContainer/SplashPageEnvironmentsContainer.tsx
@@ -1,18 +1,18 @@
import React from 'react';
-interface EnvironmentSplashPageProps {
+interface ISplashPageEnvironmentsContainerProps {
title: React.ReactNode;
topDescription: React.ReactNode;
image?: React.ReactNode;
bottomDescription?: React.ReactNode;
}
-const EnvironmentSplashPage = ({
+export const SplashPageEnvironmentsContainer = ({
title,
topDescription,
image,
bottomDescription,
-}: EnvironmentSplashPageProps) => {
+}: ISplashPageEnvironmentsContainerProps) => {
return (
{title}
@@ -22,5 +22,3 @@ const EnvironmentSplashPage = ({
);
};
-
-export default EnvironmentSplashPage;
diff --git a/frontend/src/component/common/Splash/Splash.styles.ts b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.styles.ts
similarity index 98%
rename from frontend/src/component/common/Splash/Splash.styles.ts
rename to frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.styles.ts
index 2a64b56ccd..539536cc30 100644
--- a/frontend/src/component/common/Splash/Splash.styles.ts
+++ b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.styles.ts
@@ -4,6 +4,7 @@ export const useStyles = makeStyles(theme => ({
splashMainContainer: {
backgroundColor: theme.palette.primary.light,
width: '100%',
+ minHeight: '100vh',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
diff --git a/frontend/src/component/common/Splash/Splash.tsx b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.tsx
similarity index 86%
rename from frontend/src/component/common/Splash/Splash.tsx
rename to frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.tsx
index 455270845f..f9f48f2484 100644
--- a/frontend/src/component/common/Splash/Splash.tsx
+++ b/frontend/src/component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.tsx
@@ -1,23 +1,22 @@
import React, { Fragment, useState } from 'react';
import { Button, IconButton } from '@material-ui/core';
-import { useStyles } from './Splash.styles';
+import { useStyles } from 'component/splash/SplashPageEnvironments/SplashPageEnvironmentsContent/SplashPageEnvironmentsContent.styles';
import {
CloseOutlined,
FiberManualRecord,
FiberManualRecordOutlined,
} from '@material-ui/icons';
-import ConditionallyRender from '../ConditionallyRender';
-import { CLOSE_SPLASH } from '../../../testIds';
+import ConditionallyRender from 'component/common/ConditionallyRender';
+import { CLOSE_SPLASH } from 'testIds';
-interface ISplashProps {
+interface ISplashPageEnvironmentsContentProps {
components: React.ReactNode[];
onFinish: (status: boolean) => void;
}
-const Splash: React.FC = ({
- components,
- onFinish,
-}: ISplashProps) => {
+export const SplashPageEnvironmentsContent: React.FC<
+ ISplashPageEnvironmentsContentProps
+> = ({ components, onFinish }: ISplashPageEnvironmentsContentProps) => {
const styles = useStyles();
const [counter, setCounter] = useState(0);
@@ -76,7 +75,7 @@ const Splash: React.FC = ({
onClick={onClose}
data-test={CLOSE_SPLASH}
>
-
+
{components[counter]}
@@ -109,5 +108,3 @@ const Splash: React.FC = ({
);
};
-
-export default Splash;
diff --git a/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.styles.tsx b/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.styles.tsx
new file mode 100644
index 0000000000..404b6a858d
--- /dev/null
+++ b/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.styles.tsx
@@ -0,0 +1,78 @@
+import { makeStyles } from '@material-ui/core/styles';
+
+export const useStyles = makeStyles(theme => ({
+ container: {
+ backgroundColor: theme.palette.primary.light,
+ minHeight: '100vh',
+ padding: '1rem',
+ display: 'grid',
+ gap: '1rem',
+ alignItems: 'center',
+ alignContent: 'center',
+ justifyContent: 'center',
+ gridTemplateColumns: 'minmax(0,auto)',
+ fontWeight: theme.fontWeight.thin,
+ },
+ content: {
+ position: 'relative',
+ padding: '2rem',
+ borderRadius: '0.5rem',
+ backgroundColor: theme.palette.primary.main,
+ color: 'white',
+ [theme.breakpoints.up('md')]: {
+ padding: '4rem',
+ },
+ },
+ header: {
+ textAlign: 'center',
+ },
+ footer: {
+ display: 'grid',
+ gap: '2rem',
+ textAlign: 'center',
+ justifyItems: 'center',
+ },
+ body: {
+ margin: '2rem 0',
+ padding: '2rem 0',
+ borderTop: '1px solid',
+ borderBottom: '1px solid',
+ borderTopColor: theme.palette.primary.light,
+ borderBottomColor: theme.palette.primary.light,
+ },
+ close: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ color: 'inherit',
+ },
+ title: {
+ fontWeight: 'inherit',
+ },
+ ingress: {
+ maxWidth: '32rem',
+ margin: '1.5rem auto 0 auto',
+ },
+ list: {
+ padding: '1rem 0',
+ [theme.breakpoints.up('md')]: {
+ padding: '1rem 2rem',
+ },
+ '& li + li': {
+ marginTop: '0.25rem',
+ },
+ '& strong': {
+ padding: '0 .2rem',
+ fontSize: theme.fontSizes.smallBody,
+ fontWeight: 'inherit',
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
+ },
+ },
+ link: {
+ color: 'inherit',
+ },
+ button: {
+ background: 'white',
+ color: theme.palette.primary.main,
+ },
+}));
diff --git a/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.tsx b/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.tsx
new file mode 100644
index 0000000000..67492ce004
--- /dev/null
+++ b/frontend/src/component/splash/SplashPageOperators/SplashPageOperators.tsx
@@ -0,0 +1,91 @@
+import { useStyles } from 'component/splash/SplashPageOperators/SplashPageOperators.styles';
+import { Link, useHistory } from 'react-router-dom';
+import { Button, IconButton } from '@material-ui/core';
+import { CloseOutlined } from '@material-ui/icons';
+import { OperatorUpgradeAlert } from 'component/common/OperatorUpgradeAlert/OperatorUpgradeAlert';
+
+export const SplashPageOperators = () => {
+ const { push } = useHistory();
+ const styles = useStyles();
+
+ return (
+
+
+
+
+
For example:
+
+ -
+ Toggle features at dates:
+
+ DATE_BEFORE{' '}
+ DATE_AFTER
+
+
+ -
+ Toggle features for versions:
+
+ SEMVER_EQ{' '}
+ SEMVER_GT{' '}
+ SEMVER_LT
+
+
+ -
+ Toggle features for strings:
+
+ STR_CONTAINS{' '}
+ STR_ENDS_WITH{' '}
+ STR_STARTS_WITH
+
+
+ -
+ Toggle features for numbers:
+
+ NUM_GT NUM_GTE{' '}
+ NUM_LT NUM_LTE
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/frontend/src/component/splash/SplashPageRedirect/SplashPageRedirect.tsx b/frontend/src/component/splash/SplashPageRedirect/SplashPageRedirect.tsx
new file mode 100644
index 0000000000..902876904f
--- /dev/null
+++ b/frontend/src/component/splash/SplashPageRedirect/SplashPageRedirect.tsx
@@ -0,0 +1,52 @@
+import { useAuthSplash } from 'hooks/api/getters/useAuth/useAuthSplash';
+import { useLocation, Redirect } from 'react-router-dom';
+import { matchPath } from 'react-router';
+import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
+import { IFlags } from 'interfaces/uiConfig';
+import { IAuthSplash } from 'hooks/api/getters/useAuth/useAuthEndpoint';
+import {
+ activeSplashIds,
+ SplashId,
+} from 'component/splash/SplashPage/SplashPage';
+
+export const SplashPageRedirect = () => {
+ const { pathname } = useLocation();
+ const { splash } = useAuthSplash();
+ const { uiConfig, loading } = useUiConfig();
+
+ if (!splash || !uiConfig || loading) {
+ // Wait for everything to load.
+ return null;
+ }
+
+ if (matchPath(pathname, { path: '/splash/:splashId' })) {
+ // We've already redirected to the splash page.
+ return null;
+ }
+
+ // Find the splash page to show (if any).
+ const showSplashId = activeSplashIds.find(splashId => {
+ return (
+ isSplashRelevant(splashId, uiConfig.flags) &&
+ !hasSeenSplashId(splashId, splash)
+ );
+ });
+
+ if (!showSplashId) {
+ return null;
+ }
+
+ return ;
+};
+
+const hasSeenSplashId = (splashId: SplashId, splash: IAuthSplash): boolean => {
+ return Boolean(splash[splashId]);
+};
+
+const isSplashRelevant = (splashId: SplashId, flags: IFlags): boolean => {
+ if (splashId === 'operators') {
+ return Boolean(flags.C || flags.CO);
+ }
+
+ return true;
+};
diff --git a/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx b/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
index 9d7bbe51b8..21e8920f8c 100644
--- a/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
+++ b/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
@@ -163,12 +163,14 @@ export const StrategiesList = () => {
const reactivateButton = (strategy: ICustomStrategy) => (
- onReactivateStrategy(strategy)}
- permission={UPDATE_STRATEGY}
- >
-
-
+
+
onReactivateStrategy(strategy)}
+ permission={UPDATE_STRATEGY}
+ >
+
+
+
);
@@ -179,7 +181,7 @@ export const StrategiesList = () => {
-
+
@@ -190,7 +192,7 @@ export const StrategiesList = () => {
onClick={() => onDeprecateStrategy(strategy)}
permission={UPDATE_STRATEGY}
>
-
+
}
diff --git a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap
index d1f70d522a..3936770715 100644
--- a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap
+++ b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap
@@ -159,14 +159,17 @@ exports[`renders correctly with one strategy 1`] = `
className="MuiIconButton-label"
>
=16.9.0":
+"@types/react-dom@17.0.14":
+ version "17.0.14"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.14.tgz#c8f917156b652ddf807711f5becbd2ab018dea9f"
+ integrity sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react-dom@>=16.9.0":
version "17.0.13"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.13.tgz#a3323b974ee4280070982b3112351bb1952a7809"
integrity sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ==
@@ -2103,7 +2110,16 @@
"@types/scheduler" "*"
csstype "^3.0.2"
-"@types/react@17.0.40", "@types/react@>=16.9.0":
+"@types/react@17.0.41":
+ version "17.0.41"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.41.tgz#6e179590d276394de1e357b3f89d05d7d3da8b85"
+ integrity sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA==
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
+"@types/react@>=16.9.0":
version "17.0.40"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad"
integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ==