add onboarding pgae

This commit is contained in:
Simon Larsen 2022-09-27 17:36:36 +01:00
parent 18209fe2c3
commit c0e3c758c9
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
13 changed files with 205 additions and 92 deletions

View File

@ -0,0 +1,16 @@
import React, { FunctionComponent, ReactElement } from 'react';
export interface ComponentProps {
onClick: () => void;
logo: string;
}
const SquareLogo: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return <img onClick={() => {
props.onClick && props.onClick();
}} src={props.logo} height={30} />
};
export default SquareLogo;

View File

@ -78,8 +78,13 @@ import ModelAPI, { ListResult } from 'CommonUI/src/Utils/ModelAPI/ModelAPI';
import Project from 'Model/Models/Project';
import HTTPErrorResponse from 'Common/Types/API/HTTPErrorResponse';
import PageNotFound from './Pages/PageNotFound/PageNotFound';
import Welcome from './Pages/Onboarding/Welcome';
const App: FunctionComponent = () => {
Navigation.setNavigateHook(useNavigate());
Navigation.setLocation(useLocation());
Navigation.setParams(useParams());
@ -89,6 +94,7 @@ const App: FunctionComponent = () => {
}
const [isLoading, setLoading] = useState<boolean>(false);
const [showProjectModal, setShowProjectModal] = useState<boolean>(false);
const [error, setError] = useState<string>('');
const [projects, setProjects] = useState<Array<Project>>([]);
@ -132,7 +138,7 @@ const App: FunctionComponent = () => {
} catch (err) {
setError(
(err as HTTPErrorResponse).message ||
'Server Error. Please try again'
'Server Error. Please try again'
);
}
@ -148,10 +154,15 @@ const App: FunctionComponent = () => {
isLoading={isLoading}
projects={projects}
error={error}
selectedProject={selectedProject}
onProjectSelected={onProjectSelected}
onProjectRequestAccepted={() => {
fetchProjects();
}}
showProjectModal={showProjectModal}
onProjectModalClose={() => {
setShowProjectModal(false);
}}
>
<Routes>
<PageRoute
@ -160,6 +171,8 @@ const App: FunctionComponent = () => {
<Init
pageRoute={RouteMap[PageMap.INIT] as Route}
currentProject={selectedProject}
projects={projects}
isLoadingProjects={isLoading}
/>
}
/>
@ -170,6 +183,22 @@ const App: FunctionComponent = () => {
<Init
pageRoute={RouteMap[PageMap.INIT_PROJECT] as Route}
currentProject={selectedProject}
projects={projects}
isLoadingProjects={isLoading}
/>
}
/>
<PageRoute
path={RouteMap[PageMap.WELCOME]?.toString()}
element={
<Welcome
pageRoute={RouteMap[PageMap.WELCOME] as Route}
currentProject={selectedProject}
onClickShowProjectModal={() => {
setShowProjectModal(true);
}}
/>
}
/>
@ -215,7 +244,7 @@ const App: FunctionComponent = () => {
<MonitorInoperational
pageRoute={
RouteMap[
PageMap.MONITORS_INOPERATIONAL
PageMap.MONITORS_INOPERATIONAL
] as Route
}
currentProject={selectedProject}
@ -253,7 +282,7 @@ const App: FunctionComponent = () => {
<MonitorViewStatusTimeline
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_STATUS_TIMELINE
PageMap.MONITOR_VIEW_STATUS_TIMELINE
] as Route
}
currentProject={selectedProject}
@ -267,7 +296,7 @@ const App: FunctionComponent = () => {
<MonitorIncidents
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_INCIDENTS
PageMap.MONITOR_VIEW_INCIDENTS
] as Route
}
currentProject={selectedProject}
@ -317,7 +346,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDelete
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DELETE
PageMap.STATUS_PAGE_VIEW_DELETE
] as Route
}
currentProject={selectedProject}
@ -333,7 +362,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewBranding
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_BRANDING
PageMap.STATUS_PAGE_VIEW_BRANDING
] as Route
}
currentProject={selectedProject}
@ -349,7 +378,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewCustomHtmlCss
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_CUSTOM_HTML_CSS
PageMap.STATUS_PAGE_VIEW_CUSTOM_HTML_CSS
] as Route
}
currentProject={selectedProject}
@ -365,7 +394,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAdvancedOptions
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
] as Route
}
currentProject={selectedProject}
@ -381,7 +410,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmailSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@ -397,7 +426,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewSMSSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@ -413,7 +442,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewWebhookSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@ -429,7 +458,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmbedded
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMBEDDED
PageMap.STATUS_PAGE_VIEW_EMBEDDED
] as Route
}
currentProject={selectedProject}
@ -445,7 +474,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewResources
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_RESOURCES
PageMap.STATUS_PAGE_VIEW_RESOURCES
] as Route
}
currentProject={selectedProject}
@ -461,7 +490,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDomains
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DOMAINS
PageMap.STATUS_PAGE_VIEW_DOMAINS
] as Route
}
currentProject={selectedProject}
@ -475,7 +504,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewGroups
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_GROUPS
PageMap.STATUS_PAGE_VIEW_GROUPS
] as Route
}
currentProject={selectedProject}
@ -491,7 +520,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAnnouncement
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
] as Route
}
currentProject={selectedProject}
@ -553,7 +582,7 @@ const App: FunctionComponent = () => {
<IncidentViewStateTimeline
pageRoute={
RouteMap[
PageMap.INCIDENT_VIEW_STATE_TIMELINE
PageMap.INCIDENT_VIEW_STATE_TIMELINE
] as Route
}
currentProject={selectedProject}
@ -567,7 +596,7 @@ const App: FunctionComponent = () => {
<IncidentInternalNote
pageRoute={
RouteMap[
PageMap.INCIDENT_INTERNAL_NOTE
PageMap.INCIDENT_INTERNAL_NOTE
] as Route
}
currentProject={selectedProject}
@ -631,7 +660,7 @@ const App: FunctionComponent = () => {
<SettingsMonitors
pageRoute={
RouteMap[
PageMap.SETTINGS_MONITORS_STATUS
PageMap.SETTINGS_MONITORS_STATUS
] as Route
}
currentProject={selectedProject}
@ -647,7 +676,7 @@ const App: FunctionComponent = () => {
<SettingsIncidents
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_STATE
PageMap.SETTINGS_INCIDENTS_STATE
] as Route
}
currentProject={selectedProject}
@ -663,7 +692,7 @@ const App: FunctionComponent = () => {
<SettingsIncidentSeverity
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_SEVERITY
PageMap.SETTINGS_INCIDENTS_SEVERITY
] as Route
}
currentProject={selectedProject}

View File

@ -1,10 +1,9 @@
import React, { FunctionComponent, ReactElement, useState } from 'react';
import SearchBox from 'CommonUI/src/Components/Header/SearchBox';
import SearchBox from './SearchBox';
import Notifications from './Notifications';
import Help from './Help';
import UserProfile from './UserProfile';
import ProjectPicker from './ProjectPicker';
// import ObjectID from 'Common/Types/ObjectID';
import Header from 'CommonUI/src/Components/Header/Header';
import Project from 'Model/Models/Project';
@ -15,11 +14,15 @@ import User from 'CommonUI/src/Utils/User';
import ProjectInvitationsModal from './ProjectInvitationsModal';
import ActiveIncidentsModal from './ActiveIncidentsModal';
import Incident from 'Model/Models/Incident';
import Logo from './SquareLogo';
export interface ComponentProps {
projects: Array<Project>;
onProjectSelected: (project: Project) => void;
onProjectRequestAccepted: () => void;
selectedProject: Project | null;
showProjectModal: boolean;
onProjectModalClose: () => void;
}
const DashboardHeader: FunctionComponent<ComponentProps> = (
@ -36,11 +39,14 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
<Header
leftComponents={
<>
{props.projects.length === 0 && <Logo onClick={()=>{}}/>}
<ProjectPicker
showProjectModal={props.showProjectModal}
onProjectModalClose={props.onProjectModalClose}
projects={props.projects}
onProjectSelected={props.onProjectSelected}
/>
<SearchBox key={2} onChange={(_value: string) => {}} />
<SearchBox key={2} selectedProject={props.selectedProject} onChange={(_value: string) => {}} />
<div
style={{
marginLeft: '15px',

View File

@ -15,16 +15,25 @@ import ProjectUtil from 'CommonUI/src/Utils/Project';
export interface ComponentProps {
projects: Array<Project>;
onProjectSelected: (project: Project) => void;
showProjectModal: boolean;
onProjectModalClose: () => void;
}
const DashboardProjectPicker: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
const [showModel, setShowModel] = useState<boolean>(false);
const [selectedProject, setSelectedProject] = useState<Project | null>(
null
);
useEffect(() => {
if (props.showProjectModal) {
setShowModel(true);
}
}, [props.showProjectModal]);
useEffect(() => {
const currentProject: Project | null = ProjectUtil.getCurrentProject();
setSelectedProject(currentProject);
@ -70,25 +79,28 @@ const DashboardProjectPicker: FunctionComponent<ComponentProps> = (
}
}, [props.projects]);
return (
<>
<ProjectPicker
{props.projects.length !== 0 && <ProjectPicker
selectedProjectName={selectedProject?.name || ''}
selectedProjectIcon={IconProp.Folder}
projects={props.projects}
onCreateProjectButtonClicked={() => {
setShowModel(true);
props.onProjectModalClose();
}}
onProjectSelected={(project: Project) => {
setSelectedProject(project);
}}
/>
/>}
{showModel ? (
<ModelFormModal<Project>
modelType={Project}
title="Create New Project"
onClose={() => {
setShowModel(false);
props.onProjectModalClose();
}}
submitButtonText="Create Project"
onSuccess={(project: Project) => {
@ -97,6 +109,7 @@ const DashboardProjectPicker: FunctionComponent<ComponentProps> = (
props.onProjectSelected(project);
}
setShowModel(false);
props.onProjectModalClose();
}}
formProps={{
saveRequestOptions: {

View File

@ -0,0 +1,22 @@
import React, { FunctionComponent, ReactElement } from 'react';
import SearchBox from 'CommonUI/src/Components/Header/SearchBox';
import Project from 'Model/Models/Project';
export interface ComponentProps {
onChange: (search: string) => void;
selectedProject: Project | null;
}
const Search: FunctionComponent<ComponentProps> = (props: ComponentProps): ReactElement => {
if (!props.selectedProject) {
return <></>
}
return (
<SearchBox key={2} onChange={props.onChange} />
);
};
export default Search;

View File

@ -0,0 +1,17 @@
import React, { FunctionComponent, ReactElement } from 'react';
import SquareLogo from "CommonUI/src/Components/Header/SquareLogo";
import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png';
export interface ComponentProps {
onClick: () => void;
}
const Logo: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return <SquareLogo onClick={() => {
props.onClick && props.onClick();
}} logo={`/dashboard/public/${OneUptimeLogo}`} />
};
export default Logo;

View File

@ -12,6 +12,9 @@ export interface ComponentProps {
error: string;
onProjectSelected: (project: Project) => void;
onProjectRequestAccepted: () => void;
selectedProject: Project | null;
showProjectModal: boolean;
onProjectModalClose: () => void;
}
const DashboardMasterPage: FunctionComponent<ComponentProps> = (
@ -25,9 +28,12 @@ const DashboardMasterPage: FunctionComponent<ComponentProps> = (
projects={props.projects}
onProjectSelected={props.onProjectSelected}
onProjectRequestAccepted={props.onProjectRequestAccepted}
selectedProject={props.selectedProject}
showProjectModal={props.showProjectModal}
onProjectModalClose={props.onProjectModalClose}
/>
}
navBar={<NavBar />}
navBar={<NavBar show={props.projects.length > 0} />}
isLoading={props.isLoading}
error={props.error}
>

View File

@ -1,4 +1,4 @@
import React, { FunctionComponent } from 'react';
import React, { FunctionComponent, ReactElement } from 'react';
import NavBar from 'CommonUI/src/Components/Navbar/NavBar';
import NavBarMenu from 'CommonUI/src/Components/Navbar/NavBarMenu';
import NavBarItem from 'CommonUI/src/Components/Navbar/NavBarItem';
@ -9,7 +9,16 @@ import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
import PageMap from '../../Utils/PageMap';
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
const DashboardNavbar: FunctionComponent = () => {
export interface ComponentProps {
show: boolean;
}
const DashboardNavbar: FunctionComponent<ComponentProps> = (props: ComponentProps): ReactElement => {
if (!props.show) {
return <></>;
}
return (
<NavBar
rightContent={

View File

@ -2,11 +2,19 @@ import Route from 'Common/Types/API/Route';
import PageLoader from 'CommonUI/src/Components/Loader/PageLoader';
import Page from 'CommonUI/src/Components/Page/Page';
import Navigation from 'CommonUI/src/Utils/Navigation';
import Project from 'Model/Models/Project';
import React, { FunctionComponent, ReactElement, useEffect } from 'react';
import PageMap from '../../Utils/PageMap';
import RouteMap from '../../Utils/RouteMap';
import PageComponentProps from '../PageComponentProps';
const Init: FunctionComponent<PageComponentProps> = (
props: PageComponentProps
export interface ComponentProps extends PageComponentProps {
isLoadingProjects: boolean;
projects: Array<Project>
}
const Init: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
useEffect(() => {
// set slug to latest project and redirect to home.
@ -18,6 +26,16 @@ const Init: FunctionComponent<PageComponentProps> = (
}
}, [props.currentProject]);
useEffect(() => {
// set slug to latest project and redirect to home.
if (!props.isLoadingProjects && props.projects.length === 0) {
Navigation.navigate(
RouteMap[PageMap.WELCOME] as Route
);
}
}, [props.projects]);
return (
<Page title={''} breadcrumbLinks={[]}>
<PageLoader isVisible={true} />

View File

@ -0,0 +1,29 @@
import React, { FunctionComponent, ReactElement } from 'react';
import PageComponentProps from '../PageComponentProps';
import Page from 'CommonUI/src/Components/Page/Page';
import Button, { ButtonSize, ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
export interface ComponentProps extends PageComponentProps {
onClickShowProjectModal: () => void;
}
const Welcome: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return (
<Page
title={'Welcome to OneUptime'}
breadcrumbLinks={[
]}
>
<p>Welcome to OneUptime. Thank you for signing up! TO get started please create a new project.</p>
<Button onClick={() => {
props.onClickShowProjectModal();
}} title="Create New Project" buttonSize={ButtonSize.Normal} buttonStyle={ButtonStyleType.PRIMARY} />
</Page>
);
};
export default Welcome;

View File

@ -2,6 +2,9 @@ enum PageMap {
INIT = 'INIT',
INIT_PROJECT = 'INIT_PROJECT',
// ONBOARDING
WELCOME = 'WELCOME',
HOME = 'HOME',
HOME_NOT_OPERATIONAL_MONITORS = 'HOME_NOT_OPERATIONAL_MONITORS',

View File

@ -6,9 +6,12 @@ import PageMap from './PageMap';
import RouteParams from './RouteParams';
import ObjectID from 'Common/Types/ObjectID';
const RouteMap: Dictionary<Route> = {
[PageMap.INIT]: new Route(`/dashboard`),
[PageMap.WELCOME]: new Route(`/dashboard/welcome`),
[PageMap.INIT_PROJECT]: new Route(`/dashboard/${RouteParams.ProjectID}`),
[PageMap.HOME]: new Route(`/dashboard/${RouteParams.ProjectID}/home/`),

View File

@ -46,7 +46,7 @@ services:
depends_on:
- redis
- haraka
- script-runner
identity:
ports:
- '3087:3087'
@ -168,20 +168,7 @@ services:
environment: *common-variables
image: oneuptime/licensing:latest
data-ingestor:
ports:
- '3200:3200'
image: oneuptime/data-ingestor:latest
env_file:
- ./Common/.env
- ./CommonServer/.env
- ./DataIngestor/.env
environment: *common-variables
depends_on:
- script-runner
- dashboard-api
- realtime
realtime:
ports:
- '3300:3300'
@ -226,7 +213,6 @@ services:
PROBE_KEY: test-key
depends_on:
- dashboard-api
- data-ingestor
probe2:
image: oneuptime/probe:latest
@ -240,7 +226,6 @@ services:
PROBE_KEY: test-key
depends_on:
- dashboard-api
- data-ingestor
api-docs:
ports:
@ -259,15 +244,7 @@ services:
env_file:
- ./Haraka/.env
script-runner:
ports:
- '3009:3009'
image: oneuptime/script-runner:latest
env_file:
- ./Common/.env
- ./CommonServer/.env
- ./ScriptRunner/.env
environment: *common-variables
mail:
ports:
@ -282,41 +259,6 @@ services:
- haraka
- postgres
application-scanner:
ports:
- '3005:3005'
image: oneuptime/application-scanner:latest
env_file:
- ./Common/.env
- ./CommonServer/.env
- ./ApplicationScanner/.env
environment: *common-variables
depends_on:
- dashboard-api
container-scanner:
ports:
- '3055:3055'
image: oneuptime/container-scanner:latest
env_file:
- ./Common/.env
- ./CommonServer/.env
- ./ContainerScanner/.env
environment: *common-variables
depends_on:
- dashboard-api
lighthouse-runner:
ports:
- '3015:3015'
image: oneuptime/lighthouse-runner:latest
env_file:
- ./Common/.env
- ./CommonServer/.env
- ./LighthouseRunner/.env
environment: *common-variables
depends_on:
- dashboard-api
nginx:
depends_on:
- dashboard-api