This commit is contained in:
Simon Larsen 2023-08-25 15:47:51 +01:00
parent b609742b7a
commit d3216b0d5f
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
16 changed files with 1119 additions and 6 deletions

View File

@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react';
import Route from 'Common/Types/API/Route';
import React from 'react';
import {
Routes,
Route as PageRoute,
@ -11,6 +10,10 @@ import Navigation from 'CommonUI/src/Utils/Navigation';
import User from 'CommonUI/src/Utils/User';
import URL from 'Common/Types/API/URL';
import { ACCOUNTS_URL } from 'CommonUI/src/Config';
import MasterPage from './Components/MasterPage/MasterPage';
import RouteMap from './Utils/RouteMap';
import PageMap from './Utils/PageMap';
import Init from './Pages/Init/Init';
const App: () => JSX.Element = () => {
Navigation.setNavigateHook(useNavigate());
@ -30,11 +33,15 @@ const App: () => JSX.Element = () => {
}
}
return (
<></>
<MasterPage>
<Routes>
<PageRoute
path={RouteMap[PageMap.INIT]?.toString() || ''}
element={<Init />}
/>
</Routes>
</MasterPage>
);
};

View File

@ -0,0 +1,129 @@
import React from 'react';
import Footer from 'CommonUI/src/Components/Footer/Footer';
import URL from 'Common/Types/API/URL';
import API from 'Common/Utils/API';
import { DOMAIN, HTTP_PROTOCOL } from 'CommonUI/src/Config';
import { JSONObject } from 'Common/Types/JSON';
import BadDataException from 'Common/Types/Exception/BadDataException';
import ConfirmModal from 'CommonUI/src/Components/Modal/ConfirmModal';
import Dictionary from 'Common/Types/Dictionary';
import HTTPResponse from 'Common/Types/API/HTTPResponse';
const DashboardFooter: () => JSX.Element = () => {
const [showAboutModal, setShowAboutModal] = React.useState<boolean>(false);
const [isAboutModalLoading, setIsAboutModalLoading] =
React.useState<boolean>(false);
const [versionText, setVersionText] = React.useState<Dictionary<string>>(
{}
);
const fetchVersions: () => Promise<void> = async (): Promise<void> => {
setIsAboutModalLoading(true);
try {
const verText: Dictionary<string> = {};
const apps: Array<{
name: string;
path: string;
}> = [
{
name: 'API',
path: '/api',
},
{
name: 'Dashboard',
path: '/dashboard',
},
{
name: 'Notification',
path: '/notification',
},
{
name: 'Identity Service',
path: '/identity',
},
];
for (const app of apps) {
const version: JSONObject = await fetchAppVersion(app.path);
verText[
app.name
] = `${app.name}: ${version['version']} (${version['commit']})`;
}
setVersionText(verText);
} catch (err) {
setVersionText({
error:
'Version data is not available: ' + (err as Error).message,
});
}
setIsAboutModalLoading(false);
};
const fetchAppVersion: (appName: string) => Promise<JSONObject> = async (
appName: string
): Promise<JSONObject> => {
const response: HTTPResponse<JSONObject> = await API.get<JSONObject>(
URL.fromString(`${HTTP_PROTOCOL}/${DOMAIN}${appName}/version`)
);
if (response.data) {
return response.data as JSONObject;
}
throw new BadDataException('Version data is not available');
};
return (
<>
<Footer
className="bg-white h-16 inset-x-0 bottom-0 px-8"
copyright="HackerBay, Inc."
links={[
{
title: 'Help and Support',
to: URL.fromString('https://oneuptime.com/support'),
},
{
title: 'Legal',
to: URL.fromString('https://oneuptime.com/legal'),
},
{
title: 'Version',
onClick: async () => {
setShowAboutModal(true);
await fetchVersions();
},
},
]}
/>
{showAboutModal ? (
<ConfirmModal
title={`OneUptime Version`}
description={
<div>
{Object.keys(versionText).map(
(key: string, i: number) => {
return (
<div key={i}>{versionText[key]}</div>
);
}
)}
</div>
}
isLoading={isAboutModalLoading}
submitButtonText={'Close'}
onSubmit={() => {
return setShowAboutModal(false);
}}
/>
) : (
<></>
)}
</>
);
};
export default DashboardFooter;

View File

@ -0,0 +1,34 @@
import React, { FunctionComponent, ReactElement } from 'react';
import Help from './Help';
import Header from 'CommonUI/src/Components/Header/Header';
import Logo from './Logo';
const DashboardHeader: FunctionComponent = (): ReactElement => {
return (
<>
<Header
leftComponents={
<>
<Logo onClick={() => {}} />
</>
}
centerComponents={
<>
{/* <SearchBox
key={2}
selectedProject={props.selectedProject}
onChange={(_value: string) => { }}
/>{' '} */}
</>
}
rightComponents={
<>
<Help />
</>
}
/>
</>
);
};
export default DashboardHeader;

View File

@ -0,0 +1,60 @@
import React, { ReactElement, useState } from 'react';
import HeaderIconDropdownButton from 'CommonUI/src/Components/Header/HeaderIconDropdownButton';
import IconDropdownItem from 'CommonUI/src/Components/Header/IconDropdown/IconDropdownItem';
import IconDropdownMenu from 'CommonUI/src/Components/Header/IconDropdown/IconDropdownMenu';
import IconDropdownRow from 'CommonUI/src/Components/Header/IconDropdown/IconDropdownRow';
import IconProp from 'Common/Types/Icon/IconProp';
import URL from 'Common/Types/API/URL';
const Help: () => JSX.Element = (): ReactElement => {
const [isDropdownVisible, setIsDropdownVisible] = useState<boolean>(false);
return (
<HeaderIconDropdownButton
icon={IconProp.Help}
name="Help"
showDropdown={isDropdownVisible}
onClick={() => {
setIsDropdownVisible(true);
}}
>
<IconDropdownMenu>
<IconDropdownRow>
<IconDropdownItem
title="Support Email"
icon={IconProp.Email}
openInNewTab={true}
url={URL.fromString('mailto:support@oneuptime.com')}
onClick={() => {
setIsDropdownVisible(false);
}}
/>
<IconDropdownItem
title="Chat on Slack"
icon={IconProp.Slack}
openInNewTab={true}
onClick={() => {
setIsDropdownVisible(false);
}}
url={URL.fromString(
'https://join.slack.com/t/oneuptimesupport/shared_invite/zt-1kavkds2f-gegm_wePorvwvM3M_SaoCQ'
)}
/>
<IconDropdownItem
title="Request Demo"
icon={IconProp.Window}
onClick={() => {
setIsDropdownVisible(false);
}}
openInNewTab={true}
url={URL.fromString(
'https://oneuptime.com/enterprise/demo'
)}
/>
</IconDropdownRow>
</IconDropdownMenu>
</HeaderIconDropdownButton>
);
};
export default Help;

View File

@ -0,0 +1,31 @@
// Tailwind
import React, { FunctionComponent, ReactElement } from 'react';
import Image from 'CommonUI/src/Components/Image/Image';
import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimeSVG/3-transparent.svg';
import Route from 'Common/Types/API/Route';
export interface ComponentProps {
onClick: () => void;
}
const Logo: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return (
<div className="relative z-10 flex px-2 lg:px-0">
<div className="flex flex-shrink-0 items-center">
<Image
className="block h-8 w-auto"
onClick={() => {
props.onClick && props.onClick();
}}
imageUrl={Route.fromString(`${OneUptimeLogo}`)}
alt={'OneUptime'}
/>
</div>
</div>
);
};
export default Logo;

View File

@ -0,0 +1,35 @@
import React, { ReactElement, useState } from 'react';
import HeaderIconDropdownButton from 'CommonUI/src/Components/Header/HeaderIconDropdownButton';
import Notifications from 'CommonUI/src/Components/Header/Notifications/Notifications';
import NotificationItem from 'CommonUI/src/Components/Header/Notifications/NotificationItem';
import IconProp from 'Common/Types/Icon/IconProp';
const DashboardHeader: () => JSX.Element = (): ReactElement => {
const [isDropdownVisible, setIsDropdownVisible] = useState<boolean>(false);
return (
<HeaderIconDropdownButton
name="Notifications"
onClick={() => {
setIsDropdownVisible(true);
}}
showDropdown={isDropdownVisible}
icon={IconProp.Notification}
badge={4}
>
<Notifications>
<NotificationItem
title="Sample Title"
description="Sample Description"
createdAt={new Date()}
icon={IconProp.Home}
onClick={() => {
setIsDropdownVisible(false);
}}
/>
</Notifications>
</HeaderIconDropdownButton>
);
};
export default DashboardHeader;

View File

@ -0,0 +1,285 @@
import React, {
FunctionComponent,
ReactElement,
useState,
useEffect,
} from 'react';
import ProjectPicker from 'CommonUI/src/Components/Header/ProjectPicker/ProjectPicker';
import IconProp from 'Common/Types/Icon/IconProp';
import Project from 'Model/Models/Project';
import ModelFormModal from 'CommonUI/src/Components/ModelFormModal/ModelFormModal';
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
import { FormType } from 'CommonUI/src/Components/Forms/ModelForm';
import ProjectUtil from 'CommonUI/src/Utils/Project';
import { BILLING_ENABLED, getAllEnvVars } from 'CommonUI/src/Config';
import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan';
import Field from 'CommonUI/src/Components/Forms/Types/Field';
import { RadioButton } from 'CommonUI/src/Components/RadioButtons/RadioButtons';
import Toggle from 'CommonUI/src/Components/Toggle/Toggle';
export interface ComponentProps {
projects: Array<Project>;
onProjectSelected: (project: Project) => void;
showProjectModal: boolean;
onProjectModalClose: () => void;
}
const DashboardProjectPicker: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
const [showModal, setShowModal] = useState<boolean>(false);
const [selectedProject, setSelectedProject] = useState<Project | null>(
null
);
const getFooter: Function = (): ReactElement => {
if (!BILLING_ENABLED) {
return <></>;
}
return (
<Toggle
title="Yearly Plan"
initialValue={isSubscriptionPlanYearly}
description="(Save 20%)"
onChange={(value: boolean) => {
setIsSubscriptionPlanYearly(value);
}}
/>
);
};
const [isSubscriptionPlanYearly, setIsSubscriptionPlanYearly] =
useState<boolean>(true);
const [fields, setFields] = useState<Array<Field<Project>>>([]);
useEffect(() => {
if (props.showProjectModal) {
setShowModal(true);
}
}, [props.showProjectModal]);
useEffect(() => {
const currentProject: Project | null = ProjectUtil.getCurrentProject();
setSelectedProject(currentProject);
if (currentProject && props.onProjectSelected) {
props.onProjectSelected(currentProject);
}
}, []);
useEffect(() => {
if (selectedProject) {
ProjectUtil.setCurrentProject(selectedProject);
if (props.onProjectSelected) {
props.onProjectSelected(selectedProject);
}
}
}, [selectedProject]);
useEffect(() => {
if (
props.projects &&
props.projects.length > 0 &&
!selectedProject &&
props.projects[0]
) {
const currentProject: Project | null =
ProjectUtil.getCurrentProject();
if (!currentProject) {
setSelectedProject(props.projects[0]);
} else if (
props.projects.filter((project: Project) => {
return project._id === currentProject._id;
}).length > 0
) {
setSelectedProject(
props.projects.filter((project: Project) => {
return project._id === currentProject._id;
})[0] as Project
);
} else {
setSelectedProject(props.projects[0]);
}
}
}, [props.projects]);
useEffect(() => {
refreshFields();
}, [isSubscriptionPlanYearly]);
const refreshFields: Function = (): void => {
let formFields: Array<Field<Project>> = [
{
field: {
name: true,
},
validation: {
minLength: 4,
},
fieldType: FormFieldSchemaType.Text,
placeholder: 'My Project',
description: 'Pick a friendly name.',
title: 'Project Name',
required: true,
stepId: BILLING_ENABLED ? 'basic' : undefined,
},
];
if (BILLING_ENABLED) {
formFields = [
...formFields,
{
field: {
paymentProviderPlanId: true,
},
stepId: 'plan',
validation: {
minLength: 6,
},
footerElement: getFooter(),
fieldType: FormFieldSchemaType.RadioButton,
radioButtonOptions: SubscriptionPlan.getSubscriptionPlans(
getAllEnvVars()
).map((plan: SubscriptionPlan): RadioButton => {
let description: string = plan.isCustomPricing()
? `Our sales team will contact you soon.`
: `Billed ${
isSubscriptionPlanYearly
? 'yearly'
: 'monthly'
}. ${
plan.getTrialPeriod() > 0
? `Free ${plan.getTrialPeriod()} days trial.`
: ''
}`;
if (
isSubscriptionPlanYearly &&
plan.getYearlySubscriptionAmountInUSD() === 0
) {
description = 'This plan is free, forever. ';
}
if (
!isSubscriptionPlanYearly &&
plan.getMonthlySubscriptionAmountInUSD() === 0
) {
description = 'This plan is free, forever. ';
}
return {
value: isSubscriptionPlanYearly
? plan.getYearlyPlanId()
: plan.getMonthlyPlanId(),
title: plan.getName(),
description: description,
sideTitle: plan.isCustomPricing()
? 'Custom Price'
: isSubscriptionPlanYearly
? '$' +
plan
.getYearlySubscriptionAmountInUSD()
.toString() +
'/mo billed yearly'
: '$' +
plan
.getMonthlySubscriptionAmountInUSD()
.toString(),
sideDescription: plan.isCustomPricing()
? ''
: isSubscriptionPlanYearly
? `~ $${
plan.getYearlySubscriptionAmountInUSD() *
12
} per user / year`
: `/month per user`,
};
}),
title: 'Please select a plan.',
required: true,
},
{
field: {
paymentProviderPromoCode: true,
},
fieldType: FormFieldSchemaType.Text,
placeholder: 'Promo Code (Optional)',
description: 'If you have a coupon code, enter it here.',
title: 'Promo Code',
required: false,
stepId: 'plan',
},
];
}
setFields(formFields);
};
return (
<>
{props.projects.length !== 0 && (
<ProjectPicker
selectedProjectName={selectedProject?.name || ''}
selectedProjectIcon={IconProp.Folder}
projects={props.projects}
onCreateProjectButtonClicked={() => {
setShowModal(true);
props.onProjectModalClose();
}}
onProjectSelected={(project: Project) => {
setSelectedProject(project);
}}
/>
)}
{showModal ? (
<ModelFormModal<Project>
modelType={Project}
name="Create New Project"
title="Create New Project"
description="Please create a new OneUptime project to get started."
onClose={() => {
setShowModal(false);
props.onProjectModalClose();
}}
submitButtonText="Create Project"
onSuccess={(project: Project | null) => {
setSelectedProject(project);
if (project && props.onProjectSelected) {
props.onProjectSelected(project);
}
setShowModal(false);
props.onProjectModalClose();
}}
formProps={{
name: 'Create New Project',
steps: BILLING_ENABLED
? [
{
title: 'Basic',
id: 'basic',
},
{
title: 'Select Plan',
id: 'plan',
},
]
: undefined,
saveRequestOptions: {
isMultiTenantRequest: true, // because this is a tenant request, we do not have to include the header in the request
},
modelType: Project,
id: 'create-project-from',
fields: [...fields],
formType: FormType.Create,
}}
/>
) : (
<></>
)}
</>
);
};
export default DashboardProjectPicker;

View File

@ -0,0 +1,20 @@
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,161 @@
import React, { ReactElement, useState } from 'react';
import IconProp from 'Common/Types/Icon/IconProp';
import ModelFormModal from 'CommonUI/src/Components/ModelFormModal/ModelFormModal';
import Project from 'Model/Models/Project';
import Navigation from 'CommonUI/src/Utils/Navigation';
import { FormType } from 'CommonUI/src/Components/Forms/ModelForm';
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan';
import { RadioButton } from 'CommonUI/src/Components/RadioButtons/RadioButtons';
import Button, { ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
import { BILLING_ENABLED, getAllEnvVars } from 'CommonUI/src/Config';
import DashboardNavigation from '../../Utils/Navigation';
import Toggle from 'CommonUI/src/Components/Toggle/Toggle';
const Upgrade: () => JSX.Element = (): ReactElement => {
const [showModal, setShowModal] = useState<boolean>(false);
const [isSubscriptionPlanYearly, setIsSubscriptionPlanYearly] =
useState<boolean>(true);
const getFooter: Function = (): ReactElement => {
if (!BILLING_ENABLED) {
return <></>;
}
return (
<Toggle
title="Yearly Plan"
initialValue={isSubscriptionPlanYearly}
description="(Save 20%)"
onChange={(value: boolean) => {
setIsSubscriptionPlanYearly(value);
}}
/>
);
};
return (
<>
<Button
title="Upgrade Plan"
onClick={() => {
setShowModal(true);
}}
buttonStyle={ButtonStyleType.LINK}
icon={IconProp.Star}
></Button>
{showModal ? (
<ModelFormModal<Project>
modelType={Project}
title="Change Plan"
name="Change Plan"
modelIdToEdit={DashboardNavigation.getProjectId()!}
onClose={() => {
setShowModal(false);
}}
submitButtonText="Change Plan"
onSuccess={() => {
Navigation.reload();
}}
formProps={{
name: 'Change Plan',
saveRequestOptions: {
isMultiTenantRequest: true, // because this is a tenant request, we do not have to include the header in the request
},
modelType: Project,
id: 'create-project-from',
fields: [
{
field: {
paymentProviderPlanId: true,
},
validation: {
minLength: 6,
},
fieldType: FormFieldSchemaType.RadioButton,
radioButtonOptions:
SubscriptionPlan.getSubscriptionPlans(
getAllEnvVars()
).map(
(
plan: SubscriptionPlan
): RadioButton => {
let description: string =
plan.isCustomPricing()
? `Our sales team will contact you soon.`
: `Billed ${
isSubscriptionPlanYearly
? 'yearly'
: 'monthly'
}. ${
plan.getTrialPeriod() >
0
? `Free ${plan.getTrialPeriod()} days trial.`
: ''
}`;
if (
isSubscriptionPlanYearly &&
plan.getYearlySubscriptionAmountInUSD() ===
0
) {
description =
'This plan is free, forever. ';
}
if (
!isSubscriptionPlanYearly &&
plan.getMonthlySubscriptionAmountInUSD() ===
0
) {
description =
'This plan is free, forever. ';
}
return {
value: isSubscriptionPlanYearly
? plan.getYearlyPlanId()
: plan.getMonthlyPlanId(),
title: plan.getName(),
description: description,
sideTitle:
plan.isCustomPricing()
? 'Custom Price'
: isSubscriptionPlanYearly
? '$' +
plan
.getYearlySubscriptionAmountInUSD()
.toString() +
'/mo billed yearly'
: '$' +
plan
.getMonthlySubscriptionAmountInUSD()
.toString(),
sideDescription:
plan.isCustomPricing()
? ''
: isSubscriptionPlanYearly
? `~ $${
plan.getYearlySubscriptionAmountInUSD() *
12
} per user / year`
: `/month per user`,
};
}
),
title: 'Please select a plan.',
required: true,
footerElement: getFooter(),
},
],
formType: FormType.Update,
}}
/>
) : (
<></>
)}
</>
);
};
export default Upgrade;

View File

@ -0,0 +1,56 @@
import React, { FunctionComponent, ReactElement, useState } from 'react';
import IconProp from 'Common/Types/Icon/IconProp';
import Route from 'Common/Types/API/Route';
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
import PageMap from '../../Utils/PageMap';
import BlankProfilePic from 'CommonUI/src/Images/users/blank-profile.svg';
import HeaderIconDropdownButton from 'CommonUI/src/Components/Header/HeaderIconDropdownButton';
import IconDropdownItem from 'CommonUI/src/Components/Header/IconDropdown/IconDropdownItem';
import IconDropdownMenu from 'CommonUI/src/Components/Header/IconDropdown/IconDropdownMenu';
export interface ComponentProps {
onClickUserProfile: () => void;
}
const DashboardUserProfile: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
const [isDropdownVisible, setIsDropdownVisible] = useState<boolean>(false);
return (
<>
<HeaderIconDropdownButton
iconImageUrl={BlankProfilePic}
name="User Profile"
showDropdown={isDropdownVisible}
onClick={() => {
setIsDropdownVisible(true);
}}
>
<IconDropdownMenu>
<IconDropdownItem
title="Profile"
onClick={() => {
setIsDropdownVisible(false);
props.onClickUserProfile();
}}
icon={IconProp.User}
/>
<IconDropdownItem
title="Log out"
onClick={() => {
setIsDropdownVisible(false);
}}
url={RouteUtil.populateRouteParams(
RouteMap[PageMap.LOGOUT] as Route
)}
icon={IconProp.Logout}
/>
</IconDropdownMenu>
</HeaderIconDropdownButton>
</>
);
};
export default DashboardUserProfile;

View File

@ -0,0 +1,29 @@
import MasterPage from 'CommonUI/src/Components/MasterPage/MasterPage';
import Footer from '../Footer/Footer';
import Header from '../Header/Header';
import NavBar from '../NavBar/NavBar';
import React, { FunctionComponent, ReactElement } from 'react';
export interface ComponentProps {
children: ReactElement | Array<ReactElement>;
}
const DashboardMasterPage: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return (
<MasterPage
footer={<Footer />}
header={<Header />}
navBar={<NavBar />}
isLoading={false}
error={''}
className="flex flex-col h-screen justify-between"
>
{props.children}
</MasterPage>
);
};
export default DashboardMasterPage;

View File

@ -0,0 +1,201 @@
import React, { FunctionComponent, ReactElement, useState } 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';
import NavBarMenuItem from 'CommonUI/src/Components/Navbar/NavBarMenuItem';
import Route from 'Common/Types/API/Route';
import IconProp from 'Common/Types/Icon/IconProp';
import PageMap from '../../Utils/PageMap';
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
import URL from 'Common/Types/API/URL';
const DashboardNavbar: FunctionComponent = (): ReactElement => {
const [isComponentVisible, setIsComponentVisible] =
useState<boolean>(false);
const [moreMenuTimeout, setMoreMenuTimeout] = useState<ReturnType<
typeof setTimeout
> | null>(null);
const hideMoreMenu: Function = (): void => {
if (moreMenuTimeout) {
clearTimeout(moreMenuTimeout);
setMoreMenuTimeout(null);
}
const timeout: ReturnType<typeof setTimeout> = setTimeout(() => {
setIsComponentVisible(false);
}, 500);
setMoreMenuTimeout(timeout);
};
const forceHideMoreMenu: Function = (): void => {
if (moreMenuTimeout) {
clearTimeout(moreMenuTimeout);
setMoreMenuTimeout(null);
}
setIsComponentVisible(false);
};
const showMoreMenu: Function = (): void => {
if (moreMenuTimeout) {
clearTimeout(moreMenuTimeout);
}
setIsComponentVisible(true);
};
return (
<NavBar>
<NavBarItem
title="Home"
icon={IconProp.Home}
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.HOME] as Route
)}
></NavBarItem>
<NavBarItem
title="Monitors"
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.MONITORS] as Route
)}
icon={IconProp.AltGlobe}
></NavBarItem>
<NavBarItem
title="Incidents"
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.INCIDENTS] as Route
)}
icon={IconProp.Alert}
></NavBarItem>
<NavBarItem
title="Scheduled Maintenance"
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.SCHEDULED_MAINTENANCE_EVENTS] as Route
)}
icon={IconProp.Clock}
></NavBarItem>
<NavBarItem
title="Status Pages"
icon={IconProp.CheckCircle}
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.STATUS_PAGES] as Route
)}
></NavBarItem>
<NavBarItem
title="More"
icon={IconProp.More}
onMouseLeave={() => {
hideMoreMenu();
}}
onMouseOver={() => {
showMoreMenu();
}}
onClick={() => {
showMoreMenu();
}}
>
<div
onMouseOver={() => {
showMoreMenu();
}}
onMouseLeave={() => {
hideMoreMenu();
}}
>
{isComponentVisible && (
<NavBarMenu
footer={{
title: 'Report a bug or request a feature.',
description:
'We embrace open source! Please report any issue you find and make feature requests on GitHub.',
link: URL.fromString(
'https://github.com/OneUptime/oneuptime/issues/new/choose'
),
}}
>
<NavBarMenuItem
title="On-Call Duty"
description="Manage your on-call schedules, escalations and more."
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.ON_CALL_DUTY] as Route
)}
icon={IconProp.Call}
onClick={() => {
forceHideMoreMenu();
}}
/>
<NavBarMenuItem
title="Workflows"
description="Integrate OneUptime with the rest of your ecosystem."
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.WORKFLOWS] as Route
)}
icon={IconProp.Workflow}
onClick={() => {
forceHideMoreMenu();
}}
/>
<NavBarMenuItem
title="Project Settings"
description="Review or manage settings related to this project here."
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.SETTINGS] as Route
)}
icon={IconProp.Settings}
onClick={() => {
forceHideMoreMenu();
}}
/>
<NavBarMenuItem
title="User Settings"
description="Review or manage user settings related to this project here."
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.USER_SETTINGS] as Route
)}
icon={IconProp.User}
onClick={() => {
forceHideMoreMenu();
}}
/>
{/* <NavBarMenuItem
title="Logs Management"
description='Manage your application logs.'
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.LOGS] as Route
)}
icon={IconProp.Terminal}
/>
<NavBarMenuItem
title="Error Tracker"
description='Manage your application errors.'
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.ERROR_TRACKER] as Route
)}
icon={IconProp.Error}
/>
<NavBarMenuItem
title="Reports"
description='Get insights into your Observability process.'
route={RouteUtil.populateRouteParams(
RouteMap[PageMap.REPORTS] as Route
)}
icon={IconProp.Report}
/> */}
</NavBarMenu>
)}
</div>
</NavBarItem>
</NavBar>
);
};
export default DashboardNavbar;

View File

@ -0,0 +1,13 @@
import PageLoader from 'CommonUI/src/Components/Loader/PageLoader';
import Page from 'CommonUI/src/Components/Page/Page';
import React, { FunctionComponent, ReactElement } from 'react';
const Init: FunctionComponent = (): ReactElement => {
return (
<Page title={''} breadcrumbLinks={[]}>
<PageLoader isVisible={true} />
</Page>
);
};
export default Init;

View File

@ -0,0 +1,5 @@
enum PageMap {
INIT = 'INIT',
}
export default PageMap;

View File

@ -0,0 +1,41 @@
import Route from 'Common/Types/API/Route';
import Dictionary from 'Common/Types/Dictionary';
import PageMap from './PageMap';
import RouteParams from './RouteParams';
import ObjectID from 'Common/Types/ObjectID';
const RouteMap: Dictionary<Route> = {
[PageMap.INIT]: new Route(`/admin-dashboard`),
};
export class RouteUtil {
public static populateRouteParams(
route: Route,
props?: {
modelId?: ObjectID;
subModelId?: ObjectID;
}
): Route {
// populate projectid
const tempRoute: Route = new Route(route.toString());
if (props && props.modelId) {
route = tempRoute.addRouteParam(
RouteParams.ModelID,
props.modelId.toString()
);
}
if (props && props.subModelId) {
route = tempRoute.addRouteParam(
RouteParams.SubModelID,
props.subModelId.toString()
);
}
return tempRoute;
}
}
export default RouteMap;

View File

@ -0,0 +1,6 @@
enum RouteParams {
ModelID = ':id',
SubModelID = ':subModelId',
}
export default RouteParams;