mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: add operators splash page (#802)
* refactor: fix crash on null-valued project description * refactor: remove unused layout prop * refactor: use routes for splash components * feat: add operators splash page * refactor: fix styling issues * refactor: add some comments
This commit is contained in:
		
							parent
							
								
									3ccba76d75
								
							
						
					
					
						commit
						2a307523d6
					
				| @ -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={ | ||||
|                     <div className={styles.container}> | ||||
|                         <ToastRenderer /> | ||||
| 
 | ||||
|                         <ConditionallyRender | ||||
|                             condition={showEnvSplash} | ||||
|                             show={ | ||||
|                                 <EnvironmentSplash onFinish={refetchSplash} /> | ||||
|                             } | ||||
|                             elseShow={ | ||||
|                                 <LayoutPicker> | ||||
|                                     <Switch> | ||||
|                                         <ProtectedRoute | ||||
|                                             exact | ||||
|                                             path="/" | ||||
|                                             unauthorized={isUnauthorized()} | ||||
|                                             component={Redirect} | ||||
|                                             renderProps={{ to: '/features' }} | ||||
|                                         /> | ||||
|                                         {renderMainLayoutRoutes()} | ||||
|                                         {renderStandaloneRoutes()} | ||||
|                                         <Route | ||||
|                                             path="/404" | ||||
|                                             component={NotFound} | ||||
|                                         /> | ||||
|                                         <Redirect to="/404" /> | ||||
|                                     </Switch> | ||||
|                                     <Feedback openUrl="http://feedback.unleash.run" /> | ||||
|                                 </LayoutPicker> | ||||
|                             } | ||||
|                         /> | ||||
|                         <LayoutPicker> | ||||
|                             <Switch> | ||||
|                                 <ProtectedRoute | ||||
|                                     exact | ||||
|                                     path="/" | ||||
|                                     unauthorized={isUnauthorized()} | ||||
|                                     component={Redirect} | ||||
|                                     renderProps={{ to: '/features' }} | ||||
|                                 /> | ||||
|                                 {routes.map(renderRoute)} | ||||
|                                 <Route path="/404" component={NotFound} /> | ||||
|                                 <Redirect to="/404" /> | ||||
|                             </Switch> | ||||
|                             <Feedback openUrl="http://feedback.unleash.run" /> | ||||
|                             <SplashPageRedirect /> | ||||
|                         </LayoutPicker> | ||||
|                     </div> | ||||
|                 } | ||||
|             /> | ||||
|  | ||||
| @ -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< | ||||
|         <> | ||||
|             <ConditionallyRender | ||||
|                 condition={oneOf(newOperators, localConstraint.operator)} | ||||
|                 show={ | ||||
|                     <Alert severity="warning"> | ||||
|                         In order to use this constraint operator, you need to | ||||
|                         update your SDK to the latest version. | ||||
|                     </Alert> | ||||
|                 } | ||||
|                 show={<OperatorUpgradeAlert />} | ||||
|             /> | ||||
| 
 | ||||
|             <div className={styles.inputContainer}> | ||||
|  | ||||
| @ -0,0 +1,23 @@ | ||||
| import { Alert } from '@material-ui/lab'; | ||||
| 
 | ||||
| export const OperatorUpgradeAlert = () => { | ||||
|     return ( | ||||
|         <Alert severity="warning"> | ||||
|             Remember to update your Unleash client! New operators require new | ||||
|             SDK versions. <OperatorDocsLink />. | ||||
|         </Alert> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| const OperatorDocsLink = () => { | ||||
|     return ( | ||||
|         <a | ||||
|             href="https://docs.getunleash.io/advanced/strategy_constraints#strategy-constraint-operators" | ||||
|             target="_blank" | ||||
|             rel="noreferrer" | ||||
|             style={{ color: 'inherit' }} | ||||
|         > | ||||
|             Read more | ||||
|         </a> | ||||
|     ); | ||||
| }; | ||||
| @ -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 | ||||
|         ); | ||||
|     }; | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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: {}, | ||||
|     }, | ||||
| ]; | ||||
|  | ||||
| @ -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 = ( | ||||
|         <PermissionIconButton | ||||
| @ -70,9 +71,7 @@ const ProjectInfo = ({ | ||||
|                             condition={Boolean(description)} | ||||
|                             show={ | ||||
|                                 <ConditionallyRender | ||||
|                                     condition={ | ||||
|                                         description.length < LONG_DESCRIPTION | ||||
|                                     } | ||||
|                                     condition={isShortDescription} | ||||
|                                     show={ | ||||
|                                         <p | ||||
|                                             data-loading | ||||
| @ -113,7 +112,7 @@ const ProjectInfo = ({ | ||||
|                             } | ||||
|                         /> | ||||
|                         <ConditionallyRender | ||||
|                             condition={description.length < LONG_DESCRIPTION} | ||||
|                             condition={isShortDescription} | ||||
|                             show={permissionButton} | ||||
|                         /> | ||||
|                     </div> | ||||
|  | ||||
							
								
								
									
										72
									
								
								frontend/src/component/splash/SplashPage/SplashPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								frontend/src/component/splash/SplashPage/SplashPage.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -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 ( | ||||
|         <Switch> | ||||
|             <Route path="/splash/environments"> | ||||
|                 <SplashPageEnvironments /> | ||||
|             </Route> | ||||
|             <Route path="/splash/operators"> | ||||
|                 <SplashPageOperators /> | ||||
|             </Route> | ||||
|             <Route> | ||||
|                 <Redirect to="/" /> | ||||
|             </Route> | ||||
|         </Switch> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| 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<string[]>).includes(value); | ||||
| }; | ||||
| @ -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 ( | ||||
|         <> | ||||
|             <Splash | ||||
|             <SplashPageEnvironmentsContent | ||||
|                 onFinish={onFinish} | ||||
|                 components={[ | ||||
|                     <EnvironmentSplashPage | ||||
|                     <SplashPageEnvironmentsContainer | ||||
|                         key={1} | ||||
|                         title={ | ||||
|                             <h2 className={styles.title}> | ||||
| @ -61,7 +53,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => { | ||||
|                         } | ||||
|                         image={<CloudCircle className={styles.icon} />} | ||||
|                     />, | ||||
|                     <EnvironmentSplashPage | ||||
|                     <SplashPageEnvironmentsContainer | ||||
|                         key={2} | ||||
|                         title={ | ||||
|                             <h2 className={styles.title}> | ||||
| @ -79,7 +71,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => { | ||||
|                         } | ||||
|                         image={<Logo1 className={styles.logo} />} | ||||
|                     />, | ||||
|                     <EnvironmentSplashPage | ||||
|                     <SplashPageEnvironmentsContainer | ||||
|                         key={3} | ||||
|                         title={ | ||||
|                             <h2 className={styles.title}> | ||||
| @ -99,7 +91,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => { | ||||
|                         } | ||||
|                         image={<Logo2 className={styles.logo} />} | ||||
|                     />, | ||||
|                     <EnvironmentSplashPage | ||||
|                     <SplashPageEnvironmentsContainer | ||||
|                         key={4} | ||||
|                         title={ | ||||
|                             <h2 className={styles.title}> | ||||
| @ -125,7 +117,7 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => { | ||||
|                         } | ||||
|                         image={<VpnKey className={styles.icon} />} | ||||
|                     />, | ||||
|                     <EnvironmentSplashPage | ||||
|                     <SplashPageEnvironmentsContainer | ||||
|                         key={5} | ||||
|                         title={ | ||||
|                             <h2 className={styles.title}>Want to know more?</h2> | ||||
| @ -202,5 +194,3 @@ const EnvironmentSplash = ({ onFinish }: IEnvironmentSplashProps) => { | ||||
|         </> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| export default EnvironmentSplash; | ||||
| @ -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 ( | ||||
|         <div> | ||||
|             {title} | ||||
| @ -22,5 +22,3 @@ const EnvironmentSplashPage = ({ | ||||
|         </div> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| export default EnvironmentSplashPage; | ||||
| @ -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', | ||||
| @ -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<ISplashProps> = ({ | ||||
|     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<ISplashProps> = ({ | ||||
|                         onClick={onClose} | ||||
|                         data-test={CLOSE_SPLASH} | ||||
|                     > | ||||
|                         <CloseOutlined /> | ||||
|                         <CloseOutlined titleAccess="Close" /> | ||||
|                     </IconButton> | ||||
|                 </div> | ||||
|                 {components[counter]} | ||||
| @ -109,5 +108,3 @@ const Splash: React.FC<ISplashProps> = ({ | ||||
|         </div> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| export default Splash; | ||||
| @ -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, | ||||
|     }, | ||||
| })); | ||||
| @ -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 ( | ||||
|         <section className={styles.container}> | ||||
|             <div className={styles.content}> | ||||
|                 <header className={styles.header}> | ||||
|                     <h1 className={styles.title}>New strategy operators</h1> | ||||
|                     <IconButton | ||||
|                         className={styles.close} | ||||
|                         onClick={() => push('/')} | ||||
|                     > | ||||
|                         <CloseOutlined titleAccess="Close" /> | ||||
|                     </IconButton> | ||||
|                     <p className={styles.ingress}> | ||||
|                         We've added some new feature strategy constraint | ||||
|                         operators. Fine-tune your feature targeting like never | ||||
|                         before. | ||||
|                     </p> | ||||
|                 </header> | ||||
|                 <div className={styles.body}> | ||||
|                     <p>For example:</p> | ||||
|                     <ul className={styles.list}> | ||||
|                         <li> | ||||
|                             <span>Toggle features at dates: </span> | ||||
|                             <span> | ||||
|                                 <strong>DATE_BEFORE</strong>{' '} | ||||
|                                 <strong>DATE_AFTER</strong> | ||||
|                             </span> | ||||
|                         </li> | ||||
|                         <li> | ||||
|                             <span>Toggle features for versions: </span> | ||||
|                             <span> | ||||
|                                 <strong>SEMVER_EQ</strong>{' '} | ||||
|                                 <strong>SEMVER_GT</strong>{' '} | ||||
|                                 <strong>SEMVER_LT</strong> | ||||
|                             </span> | ||||
|                         </li> | ||||
|                         <li> | ||||
|                             <span>Toggle features for strings: </span> | ||||
|                             <span> | ||||
|                                 <strong>STR_CONTAINS</strong>{' '} | ||||
|                                 <strong>STR_ENDS_WITH</strong>{' '} | ||||
|                                 <strong>STR_STARTS_WITH</strong> | ||||
|                             </span> | ||||
|                         </li> | ||||
|                         <li> | ||||
|                             <span>Toggle features for numbers: </span> | ||||
|                             <span> | ||||
|                                 <strong>NUM_GT</strong> <strong>NUM_GTE</strong>{' '} | ||||
|                                 <strong>NUM_LT</strong> <strong>NUM_LTE</strong> | ||||
|                             </span> | ||||
|                         </li> | ||||
|                     </ul> | ||||
|                 </div> | ||||
|                 <footer className={styles.footer}> | ||||
|                     <p> | ||||
|                         <a | ||||
|                             href="https://docs.getunleash.io/advanced/strategy_constraints#numeric-operators" | ||||
|                             target="_blank" | ||||
|                             rel="noreferrer" | ||||
|                             className={styles.link} | ||||
|                         > | ||||
|                             Read all about operators in our in-depth{' '} | ||||
|                             <strong>docs</strong> | ||||
|                         </a> | ||||
|                         . | ||||
|                     </p> | ||||
|                     <p> | ||||
|                         <Button | ||||
|                             className={styles.button} | ||||
|                             variant="contained" | ||||
|                             component={Link} | ||||
|                             to="/" | ||||
|                         > | ||||
|                             Fine, whatever, I have work to do! | ||||
|                         </Button> | ||||
|                     </p> | ||||
|                 </footer> | ||||
|             </div> | ||||
|             <OperatorUpgradeAlert /> | ||||
|         </section> | ||||
|     ); | ||||
| }; | ||||
| @ -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 <Redirect to={`/splash/${showSplashId}`} />; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| }; | ||||
| @ -15,7 +15,7 @@ export interface IProject { | ||||
|     members: number; | ||||
|     version: string; | ||||
|     name: string; | ||||
|     description: string; | ||||
|     description?: string; | ||||
|     environments: string[]; | ||||
|     health: number; | ||||
|     features: IFeatureToggleListItem[]; | ||||
|  | ||||
| @ -6,7 +6,6 @@ interface IRoute { | ||||
|     title?: string; | ||||
|     component: React.ComponentType; | ||||
|     type: string; | ||||
|     layout: string; | ||||
|     hidden?: boolean; | ||||
|     flag?: string; | ||||
|     parent?: string; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user