add sso model

This commit is contained in:
Simon Larsen
2023-03-03 20:55:24 +00:00
parent af832b74f0
commit 0fa3f3ef08
32 changed files with 838 additions and 79 deletions

View File

@@ -135,6 +135,12 @@ enum Permission {
CanEditStatusPageDomain = 'CanEditStatusPageDomain',
CanReadStatusPageDomain = 'CanReadStatusPageDomain',
CanCreateProjectSSO = 'CanCreateProjectSSO',
CanDeleteProjectSSO = 'CanDeleteProjectSSO',
CanEditProjectSSO = 'CanEditProjectSSO',
CanReadProjectSSO = 'CanReadProjectSSO',
// Label Permissions (Owner + Admin Permission by default)
CanCreateProjectLabel = 'CanCreateProjectLabel',
CanEditProjectLabel = 'CanEditProjectLabel',
@@ -1011,6 +1017,45 @@ export class PermissionHelper {
isAccessControlPermission: false,
},
{
permission: Permission.CanCreateProjectSSO,
title: 'Can Create Project SSO',
description:
'A user assigned this permission can create Project SSO in this project.',
isAssignableToTenant: true,
isAccessControlPermission: false,
},
{
permission: Permission.CanDeleteProjectSSO,
title: 'Can Delete Project SSO',
description:
'A user assigned this permission can delete Project SSO in this project.',
isAssignableToTenant: true,
isAccessControlPermission: false,
},
{
permission: Permission.CanEditProjectSSO,
title: 'Can Edit Project SSO',
description:
'A user assigned this permission can edit Project SSO in this project.',
isAssignableToTenant: true,
isAccessControlPermission: false,
},
{
permission: Permission.CanReadProjectSSO,
title: 'Can Read Project SSO',
description:
'A user assigned this permission can read Project SSO in this project.',
isAssignableToTenant: true,
isAccessControlPermission: false,
},
{
permission: Permission.CanCreateProjectSMTPConfig,
title: 'Can Create SMTP Config',

View File

@@ -0,0 +1,8 @@
enum DigestMethod {
SHA1 = "SHA1",
SHA256 = "SHA256",
SHA384 = "SHA384",
SHA512 = "SHA512",
}
export default DigestMethod;

View File

@@ -0,0 +1,8 @@
enum SignatureMethod {
SHA1 = "RSA-SHA1",
SHA256 = "RSA-SHA256",
SHA384 = "RSA-SHA384",
SHA512 = "RSA-SHA512",
}
export default SignatureMethod;

View File

@@ -0,0 +1,11 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Model/Models/ProjectSso';
import DatabaseService from './DatabaseService';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
}
}
export default new Service();

View File

@@ -635,7 +635,7 @@ const BasicForm: Function = <T extends Object>(
</Field>
)}
{field.fieldType === FormFieldSchemaType.Checkbox && (
{field.fieldType === FormFieldSchemaType.Toggle && (
<Field name={fieldName}>
{({ form }: any) => {
return (
@@ -1130,7 +1130,7 @@ const BasicForm: Function = <T extends Object>(
for (const field of props.fields) {
if (
field.fieldType === FormFieldSchemaType.Checkbox
field.fieldType === FormFieldSchemaType.Toggle
) {
const fieldName: string = field.overideFieldKey
? field.overideFieldKey

View File

@@ -19,7 +19,7 @@ enum FormFieldSchemaType {
Dropdown = 'Dropdown',
File = 'File',
MultiSelectDropdown = 'MultiSelectDropdown',
Checkbox = 'Boolean',
Toggle = 'Boolean',
Port = 'Port',
EncryptedText = 'EncryptedText',
Markdown = 'Markdown',

View File

@@ -55,7 +55,7 @@ export const componentInputTypeToFormFieldType: Function = (
if (componentInputType === ComponentInputType.Boolean) {
return {
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
dropdownOptions: [],
};
}

View File

@@ -0,0 +1,13 @@
import { DropdownOption } from "../Components/Dropdown/Dropdown"
export default class DropdownUtil {
public static getDropdownOptionsFromEnum(obj: Object): Array<DropdownOption> {
return Object.keys(obj).map((key: string)=> {
return {
label: ((obj as any)[key]).toString(),
value: ((obj as any)[key]).toString()
}
})
}
}

View File

@@ -86,6 +86,7 @@ import SettingsScheduledMaintenanceState from './Pages/Settings/ScheduledMainten
import SettingsDomains from './Pages/Settings/Domains';
import SettingsIncidentSeverity from './Pages/Settings/IncidentSeverity';
import SettingsBilling from './Pages/Settings/Billing';
import SettingsSSO from './Pages/Settings/SSO';
import SettingsInvoices from './Pages/Settings/Invoices';
import MonitorCustomFields from './Pages/Settings/MonitorCustomFields';
import StatusPageCustomFields from './Pages/Settings/StatusPageCustomFields';
@@ -199,7 +200,7 @@ const App: FunctionComponent = () => {
} catch (err) {
setError(
(err as HTTPErrorResponse).message ||
'Server Error. Please try again'
'Server Error. Please try again'
);
}
@@ -284,7 +285,7 @@ const App: FunctionComponent = () => {
<NotOperationalMonitors
pageRoute={
RouteMap[
PageMap.HOME_NOT_OPERATIONAL_MONITORS
PageMap.HOME_NOT_OPERATIONAL_MONITORS
] as Route
}
currentProject={selectedProject}
@@ -304,8 +305,8 @@ const App: FunctionComponent = () => {
<OngoingScheduledEvents
pageRoute={
RouteMap[
PageMap
.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
PageMap
.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -333,7 +334,7 @@ const App: FunctionComponent = () => {
<MonitorInoperational
pageRoute={
RouteMap[
PageMap.MONITORS_INOPERATIONAL
PageMap.MONITORS_INOPERATIONAL
] as Route
}
currentProject={selectedProject}
@@ -375,7 +376,7 @@ const App: FunctionComponent = () => {
<MonitorViewStatusTimeline
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_STATUS_TIMELINE
PageMap.MONITOR_VIEW_STATUS_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -392,7 +393,7 @@ const App: FunctionComponent = () => {
<MonitorIncidents
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_INCIDENTS
PageMap.MONITOR_VIEW_INCIDENTS
] as Route
}
currentProject={selectedProject}
@@ -410,7 +411,7 @@ const App: FunctionComponent = () => {
<MonitorViewCustomFields
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_CUSTOM_FIELDS
PageMap.MONITOR_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -561,7 +562,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDelete
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DELETE
PageMap.STATUS_PAGE_VIEW_DELETE
] as Route
}
currentProject={selectedProject}
@@ -579,7 +580,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewBranding
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_BRANDING
PageMap.STATUS_PAGE_VIEW_BRANDING
] as Route
}
currentProject={selectedProject}
@@ -597,7 +598,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}
@@ -615,7 +616,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAdvancedOptions
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
] as Route
}
currentProject={selectedProject}
@@ -633,7 +634,7 @@ const App: FunctionComponent = () => {
<StatusPageViewCustomFields
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_CUSTOM_FIELDS
PageMap.STATUS_PAGE_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -651,7 +652,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmailSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -669,7 +670,7 @@ const App: FunctionComponent = () => {
<StatusPageViewPrivateUser
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_PRIVATE_USERS
PageMap.STATUS_PAGE_VIEW_PRIVATE_USERS
] as Route
}
currentProject={selectedProject}
@@ -687,7 +688,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewSMSSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -705,7 +706,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewHeaderStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_HEADER_STYLE
PageMap.STATUS_PAGE_VIEW_HEADER_STYLE
] as Route
}
currentProject={selectedProject}
@@ -723,7 +724,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewFooterStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_FOOTER_STYLE
PageMap.STATUS_PAGE_VIEW_FOOTER_STYLE
] as Route
}
currentProject={selectedProject}
@@ -741,7 +742,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewNavBarStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_NAVBAR_STYLE
PageMap.STATUS_PAGE_VIEW_NAVBAR_STYLE
] as Route
}
currentProject={selectedProject}
@@ -759,7 +760,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewWebhookSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -777,7 +778,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmbedded
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMBEDDED
PageMap.STATUS_PAGE_VIEW_EMBEDDED
] as Route
}
currentProject={selectedProject}
@@ -795,7 +796,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewResources
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_RESOURCES
PageMap.STATUS_PAGE_VIEW_RESOURCES
] as Route
}
currentProject={selectedProject}
@@ -813,7 +814,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDomains
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DOMAINS
PageMap.STATUS_PAGE_VIEW_DOMAINS
] as Route
}
currentProject={selectedProject}
@@ -830,7 +831,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewGroups
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_GROUPS
PageMap.STATUS_PAGE_VIEW_GROUPS
] as Route
}
currentProject={selectedProject}
@@ -848,7 +849,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAnnouncement
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
] as Route
}
currentProject={selectedProject}
@@ -916,7 +917,7 @@ const App: FunctionComponent = () => {
<IncidentViewStateTimeline
pageRoute={
RouteMap[
PageMap.INCIDENT_VIEW_STATE_TIMELINE
PageMap.INCIDENT_VIEW_STATE_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -933,7 +934,7 @@ const App: FunctionComponent = () => {
<IncidentInternalNote
pageRoute={
RouteMap[
PageMap.INCIDENT_INTERNAL_NOTE
PageMap.INCIDENT_INTERNAL_NOTE
] as Route
}
currentProject={selectedProject}
@@ -951,7 +952,7 @@ const App: FunctionComponent = () => {
<IncidentViewCustomFields
pageRoute={
RouteMap[
PageMap.INCIDENT_VIEW_CUSTOM_FIELDS
PageMap.INCIDENT_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -985,7 +986,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEvents
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_EVENTS
PageMap.SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -1003,7 +1004,7 @@ const App: FunctionComponent = () => {
<OngoingScheduledMaintenanceEvents
pageRoute={
RouteMap[
PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS
PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -1021,7 +1022,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventView
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_VIEW
PageMap.SCHEDULED_MAINTENANCE_VIEW
] as Route
}
currentProject={selectedProject}
@@ -1039,8 +1040,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventsViewCustomFields
pageRoute={
RouteMap[
PageMap
.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
PageMap
.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1058,7 +1059,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventViewDelete
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE
PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE
] as Route
}
currentProject={selectedProject}
@@ -1076,8 +1077,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventViewStateTimeline
pageRoute={
RouteMap[
PageMap
.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
PageMap
.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -1095,7 +1096,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventInternalNote
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE
PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE
] as Route
}
currentProject={selectedProject}
@@ -1113,7 +1114,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventPublicNote
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE
PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE
] as Route
}
currentProject={selectedProject}
@@ -1175,7 +1176,7 @@ const App: FunctionComponent = () => {
<SettingsMonitors
pageRoute={
RouteMap[
PageMap.SETTINGS_MONITORS_STATUS
PageMap.SETTINGS_MONITORS_STATUS
] as Route
}
currentProject={selectedProject}
@@ -1193,7 +1194,7 @@ const App: FunctionComponent = () => {
<SettingsIncidents
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_STATE
PageMap.SETTINGS_INCIDENTS_STATE
] as Route
}
currentProject={selectedProject}
@@ -1211,7 +1212,26 @@ const App: FunctionComponent = () => {
<SettingsScheduledMaintenanceState
pageRoute={
RouteMap[
PageMap.SETTINGS_SCHEDULED_MAINTENANCE_STATE
PageMap.SETTINGS_SCHEDULED_MAINTENANCE_STATE
] as Route
}
currentProject={selectedProject}
/>
}
/>
<PageRoute
path={
RouteMap[
PageMap.SETTINGS_SSO
]?.toString() || ''
}
element={
<SettingsSSO
pageRoute={
RouteMap[
PageMap.SETTINGS_SSO
] as Route
}
currentProject={selectedProject}
@@ -1229,7 +1249,7 @@ const App: FunctionComponent = () => {
<SettingsIncidentSeverity
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_SEVERITY
PageMap.SETTINGS_INCIDENTS_SEVERITY
] as Route
}
currentProject={selectedProject}
@@ -1299,7 +1319,7 @@ const App: FunctionComponent = () => {
<MonitorCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_MONITOR_CUSTOM_FIELDS
PageMap.SETTINGS_MONITOR_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1317,7 +1337,7 @@ const App: FunctionComponent = () => {
<StatusPageCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_STATUS_PAGE_CUSTOM_FIELDS
PageMap.SETTINGS_STATUS_PAGE_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1335,8 +1355,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceCustomFields
pageRoute={
RouteMap[
PageMap
.SETTINGS_SCHEDULED_MAINTENANCE_CUSTOM_FIELDS
PageMap
.SETTINGS_SCHEDULED_MAINTENANCE_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1354,7 +1374,7 @@ const App: FunctionComponent = () => {
<IncidentCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENT_CUSTOM_FIELDS
PageMap.SETTINGS_INCIDENT_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1384,7 +1404,7 @@ const App: FunctionComponent = () => {
<SettingsInvoices
pageRoute={
RouteMap[
PageMap.SETTINGS_BILLING_INVOICES
PageMap.SETTINGS_BILLING_INVOICES
] as Route
}
currentProject={selectedProject}

View File

@@ -102,7 +102,7 @@ const CustomSMTP: FunctionComponent<PageComponentProps> = (
secure: true,
},
title: 'Use SSL / TLS',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
description: 'Make email communication secure?',
},
{

View File

@@ -0,0 +1,168 @@
import Route from 'Common/Types/API/Route';
import Page from 'CommonUI/src/Components/Page/Page';
import React, { FunctionComponent, ReactElement } from 'react';
import PageMap from '../../Utils/PageMap';
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
import PageComponentProps from '../PageComponentProps';
import DashboardSideMenu from './SideMenu';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
import DropdownUtil from "CommonUI/src/Utils/Dropdown";
import FieldType from 'CommonUI/src/Components/Types/FieldType';
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
import IconProp from 'Common/Types/Icon/IconProp';
import DashboardNavigation from '../../Utils/Navigation';
import Navigation from 'CommonUI/src/Utils/Navigation';
import ProjectSSO from 'Model/Models/ProjectSso';
import SignatureMethod from 'Common/Types/SSO/SignatureMethod';
import DigestMethod from 'Common/Types/SSO/DigestMethod';
const SSOPage: FunctionComponent<PageComponentProps> = (
_props: PageComponentProps
): ReactElement => {
return (
<Page
title={'Project Settings'}
breadcrumbLinks={[
{
title: 'Project',
to: RouteUtil.populateRouteParams(
RouteMap[PageMap.HOME] as Route
),
},
{
title: 'Settings',
to: RouteUtil.populateRouteParams(
RouteMap[PageMap.SETTINGS] as Route
),
},
{
title: 'SSO',
to: RouteUtil.populateRouteParams(
RouteMap[PageMap.SETTINGS_SSO] as Route
),
},
]}
sideMenu={<DashboardSideMenu />}
>
<ModelTable<ProjectSSO>
modelType={ProjectSSO}
query={{
projectId: DashboardNavigation.getProjectId()?.toString(),
}}
id="sso-table"
name="Settings > Project SSO"
isDeleteable={true}
isEditable={true}
isCreateable={true}
cardProps={{
icon: IconProp.Lock,
title: 'Single Sign On (SSO)',
description:
'Single sign-on is an authentication scheme that allows a user to log in with a single ID to any of several related, yet independent, software systems.',
}}
noItemsMessage={'No SSO configuration found.'}
viewPageRoute={Navigation.getCurrentRoute()}
formFields={[
{
field: {
name: true,
},
title: 'Name',
fieldType: FormFieldSchemaType.Text,
required: true,
description: 'Friendly name to help you remember.',
placeholder: 'Okta',
validation: {
minLength: 2,
},
},
{
field: {
signOnURL: true,
},
title: 'Sign On URL',
fieldType: FormFieldSchemaType.URL,
required: true,
description: "Members will be forwarded here when signing in to your organization",
placeholder:
'https://yourapp.example.com/apps/appId',
},
{
field: {
issuerURL: true,
},
title: 'Issuer',
description: "Typically a unique URL generated by your SAML identity provider",
fieldType: FormFieldSchemaType.URL,
required: true,
placeholder: 'https://example.com',
},
{
field: {
publicCertificate: true,
},
title: 'Public Certificate',
description: "Paste in your x509 certificate here.",
fieldType: FormFieldSchemaType.LongText,
required: true,
placeholder: 'https://example.com',
},
{
field: {
signatureMethod: true,
},
title: 'Signature Method',
description: "If you do not know what this is, please leave this to RSA-SHA256",
fieldType: FormFieldSchemaType.Dropdown,
dropdownOptions: DropdownUtil.getDropdownOptionsFromEnum(SignatureMethod),
required: true,
placeholder: 'RSA-SHA256',
},
{
field: {
digestMethod: true,
},
title: 'Digest Method',
description: "If you do not know what this is, please leave this to SHA256",
fieldType: FormFieldSchemaType.Dropdown,
dropdownOptions: DropdownUtil.getDropdownOptionsFromEnum(DigestMethod),
required: true,
placeholder: 'SHA256',
},
{
field: {
isEnabled: true,
},
description: "You can test this first, before enabling it. To test, please save the config.",
title: 'Enabled',
fieldType: FormFieldSchemaType.Toggle,
},
]}
showRefreshButton={true}
showFilterButton={true}
columns={[
{
field: {
name: true,
},
title: 'Name',
type: FieldType.Text,
isFilterable: true,
},
{
field: {
isEnabled: true,
},
title: 'Enabled',
type: FieldType.Boolean,
isFilterable: true,
},
]}
/>
</Page>
);
};
export default SSOPage;

View File

@@ -234,6 +234,17 @@ const DashboardSideMenu: FunctionComponent = (): ReactElement => {
) : (
<></>
)}
<SideMenuSection title="Authentication Security">
<SideMenuItem
link={{
title: 'SSO',
to: RouteUtil.populateRouteParams(
RouteMap[PageMap.SETTINGS_SSO] as Route
),
}}
icon={IconProp.Lock}
/>
</SideMenuSection>
<SideMenuSection title="Danger Zone">
<SideMenuItem
link={{

View File

@@ -69,7 +69,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
isPublicStatusPage: true,
},
title: 'Is Visible to Public',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
placeholder: 'Is this status page visible to public',
},

View File

@@ -243,7 +243,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showFooter: true,
},
title: 'Show Footer on Status Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}

View File

@@ -114,7 +114,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
isExpandedByDefault: true,
},
title: 'Is this group expanded by default on the staus page?',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}

View File

@@ -305,7 +305,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showHeader: true,
},
title: 'Show Header on Status Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}

View File

@@ -125,7 +125,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showOverviewPage: true,
},
title: 'Show Overview Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
{
@@ -133,7 +133,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showIncidentsPage: true,
},
title: 'Show Incidents Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
{
@@ -141,7 +141,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showAnouncementsPage: true,
},
title: 'Show Announcements Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
{
@@ -149,7 +149,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showScheduledMaintenancePage: true,
},
title: 'Show Scheduled Maintenance Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
{
@@ -157,7 +157,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
enableSubscribers: true,
},
title: 'Enable Subscribers',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
// {
@@ -165,7 +165,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
// showRssPage: true,
// },
// title: 'Enable RSS Page',
// fieldType: FormFieldSchemaType.Checkbox,
// fieldType: FormFieldSchemaType.Toggle,
// required: false,
// },
]}
@@ -237,7 +237,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showNavbar: true,
},
title: 'Show Navigation Menu on Status Page',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}

View File

@@ -187,7 +187,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showCurrentStatus: true,
},
title: 'Show Current Resource Status',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
defaultValue: true,
description:
@@ -198,7 +198,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
showStatusHistoryChart: true,
},
title: 'Show Status History Chart',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
description:
'Show resource status history for the past 90 days. ',

View File

@@ -68,7 +68,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
enableSubscribers: true,
},
title: 'Enable Subscribers',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: false,
placeholder:
'Can subscribers subscribe to this status page?',

View File

@@ -91,7 +91,7 @@ const Workflows: FunctionComponent<PageComponentProps> = (
title: 'Secret',
description:
'Is this variable secret or secure? Should this be encrypted in the Database?',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: true,
},
{

View File

@@ -93,7 +93,7 @@ const Delete: FunctionComponent<PageComponentProps> = (
isEnabled: true,
},
title: 'Enabled',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
},
{
field: {

View File

@@ -109,7 +109,7 @@ const Workflows: FunctionComponent<PageComponentProps> = (
title: 'Secret',
description:
'Is this variable secret or secure? Should this be encrypted in the Database?',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
required: true,
},
{

View File

@@ -113,7 +113,7 @@ const Workflows: FunctionComponent<PageComponentProps> = (
isEnabled: true,
},
title: 'Enabled',
fieldType: FormFieldSchemaType.Checkbox,
fieldType: FormFieldSchemaType.Toggle,
},
]}
showRefreshButton={true}

View File

@@ -94,6 +94,9 @@ enum PageMap {
// Labels.
SETTINGS_LABELS = 'SETTINGS_LABELS',
// SSO.
SETTINGS_SSO = 'SETTINGS_SSO',
// Domains
SETTINGS_DOMAINS = 'SETTINGS_DOMAINS',

View File

@@ -243,6 +243,7 @@ const RouteMap: Dictionary<Route> = {
`/dashboard/${RouteParams.ProjectID}/settings/incidents-state`
),
[PageMap.SETTINGS_SCHEDULED_MAINTENANCE_STATE]: new Route(
`/dashboard/${RouteParams.ProjectID}/settings/scheduled-maintenance-state`
),
@@ -255,6 +256,10 @@ const RouteMap: Dictionary<Route> = {
`/dashboard/${RouteParams.ProjectID}/settings/domains`
),
[PageMap.SETTINGS_SSO]: new Route(
`/dashboard/${RouteParams.ProjectID}/settings/sso`
),
[PageMap.SETTINGS_TEAMS]: new Route(
`/dashboard/${RouteParams.ProjectID}/settings/teams`
),

View File

@@ -30,6 +30,13 @@ import WorkflowLogService, {
Service as WorkflowLogServiceType,
} from 'CommonServer/Services/WorkflowLogService';
import ProjectSSO from 'Model/Models/ProjectSso';
import ProjectSSOService, {
Service as ProjectSSOServiceType,
} from 'CommonServer/Services/ProjectSsoService';
import WorkflowVariable from 'Model/Models/WorkflowVariable';
import WorkflowVariableService, {
Service as WorkflowVariableServiceType,
@@ -469,6 +476,15 @@ app.use(
).getRouter()
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<ProjectSSO, ProjectSSOServiceType>(
ProjectSSO,
ProjectSSOService
).getRouter()
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<MonitorTimelineStatus, MonitorTimelineStatusServiceType>(

View File

@@ -1,5 +1,4 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import AccessControlModel from 'Common/Models/AccessControlModel';
import User from './User';
import Project from './Project';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
@@ -19,6 +18,7 @@ import IconProp from 'Common/Types/Icon/IconProp';
import CustomFieldType from 'Common/Types/CustomField/CustomFieldType';
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
import BaseModel from 'Common/Models/BaseModel';
@TableBillingAccessControl({
create: PlanSelect.Growth,
@@ -60,7 +60,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
@Entity({
name: 'IncidentCustomField',
})
export default class IncidentCustomField extends AccessControlModel {
export default class IncidentCustomField extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -72,6 +72,9 @@ import Workflow from './Workflow';
import WorkflowVariables from './WorkflowVariable';
import WorkflowLog from './WorkflowLog';
//SSO
import ProjectSSO from './ProjectSso';
export default [
User,
Probe,
@@ -126,4 +129,6 @@ export default [
Workflow,
WorkflowVariables,
WorkflowLog,
ProjectSSO
];

View File

@@ -1,5 +1,4 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import AccessControlModel from 'Common/Models/AccessControlModel';
import User from './User';
import Project from './Project';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
@@ -19,6 +18,7 @@ import IconProp from 'Common/Types/Icon/IconProp';
import CustomFieldType from 'Common/Types/CustomField/CustomFieldType';
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
import BaseModel from 'Common/Models/BaseModel';
@TableBillingAccessControl({
create: PlanSelect.Growth,
@@ -60,7 +60,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
@Entity({
name: 'MonitorCustomField',
})
export default class MonitorCustomField extends AccessControlModel {
export default class MonitorCustomField extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

446
Model/Models/ProjectSso.ts Normal file
View File

@@ -0,0 +1,446 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import User from './User';
import Project from './Project';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
import Route from 'Common/Types/API/Route';
import TableColumnType from 'Common/Types/Database/TableColumnType';
import TableColumn from 'Common/Types/Database/TableColumn';
import ColumnType from 'Common/Types/Database/ColumnType';
import ObjectID from 'Common/Types/ObjectID';
import TableAccessControl from 'Common/Types/Database/AccessControl/TableAccessControl';
import Permission from 'Common/Types/Permission';
import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAccessControl';
import UniqueColumnBy from 'Common/Types/Database/UniqueColumnBy';
import TenantColumn from 'Common/Types/Database/TenantColumn';
import TableMetadata from 'Common/Types/Database/TableMetadata';
import IconProp from 'Common/Types/Icon/IconProp';
import BaseModel from 'Common/Models/BaseModel';
import URL from 'Common/Types/API/URL';
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
import ColumnLength from 'Common/Types/Database/ColumnLength';
import SignatureMethod from "Common/Types/SSO/SignatureMethod";
import DigestMethod from "Common/Types/SSO/DigestMethod";
@TableBillingAccessControl({
create: PlanSelect.Scale,
read: PlanSelect.Scale,
update: PlanSelect.Scale,
delete: PlanSelect.Scale,
})
@TenantColumn('projectId')
@TableAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
delete: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanDeleteProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@CrudApiEndpoint(new Route('/project-sso'))
@TableMetadata({
tableName: 'ProjectSSO',
singularName: 'SSO',
pluralName: 'SSO',
icon: IconProp.Lock,
})
@Entity({
name: 'ProjectSSO',
})
export default class ProjectSSO extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: 'projectId',
type: TableColumnType.Entity,
modelType: Project,
})
@ManyToOne(
(_type: string) => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: 'CASCADE',
orphanedRowAction: 'nullify',
}
)
@JoinColumn({ name: 'projectId' })
public project?: Project = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnPopulate: true,
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
@UniqueColumnBy('projectId')
public name?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public signatureMethod?: SignatureMethod = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public digestMethod?: DigestMethod = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.LongURL,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.LongURL,
transformer: URL.getDatabaseTransformer()
})
@UniqueColumnBy('projectId')
public signOnURL?: URL = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.LongURL,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.LongURL,
transformer: URL.getDatabaseTransformer()
})
public issuerURL?: URL = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.LongText,
canReadOnPopulate: true,
})
@Column({
nullable: false,
type: ColumnType.LongText,
})
public publicCertificate?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: 'createdByUserId',
type: TableColumnType.Entity,
modelType: User,
})
@ManyToOne(
(_type: string) => {
return User;
},
{
eager: false,
nullable: true,
onDelete: 'CASCADE',
orphanedRowAction: 'nullify',
}
)
@JoinColumn({ name: 'createdByUserId' })
public createdByUser?: User = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@TableColumn({ type: TableColumnType.ObjectID })
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public createdByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: 'deletedByUserId',
type: TableColumnType.ObjectID,
})
@ManyToOne(
(_type: string) => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: 'CASCADE',
orphanedRowAction: 'nullify',
}
)
@JoinColumn({ name: 'deletedByUserId' })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [],
})
@TableColumn({ type: TableColumnType.ObjectID })
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanCreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CanReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CanEditProjectSSO,
],
})
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
@Column({
type: ColumnType.Boolean,
default: false,
})
public isEnabled?: boolean = undefined;
}

View File

@@ -1,5 +1,4 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import AccessControlModel from 'Common/Models/AccessControlModel';
import User from './User';
import Project from './Project';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
@@ -19,6 +18,7 @@ import IconProp from 'Common/Types/Icon/IconProp';
import CustomFieldType from 'Common/Types/CustomField/CustomFieldType';
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
import BaseModel from 'Common/Models/BaseModel';
@TableBillingAccessControl({
create: PlanSelect.Growth,
@@ -60,7 +60,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
@Entity({
name: 'ScheduledMaintenanceCustomField',
})
export default class ScheduledMaintenanceCustomField extends AccessControlModel {
export default class ScheduledMaintenanceCustomField extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -1,5 +1,4 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import AccessControlModel from 'Common/Models/AccessControlModel';
import User from './User';
import Project from './Project';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
@@ -19,6 +18,7 @@ import IconProp from 'Common/Types/Icon/IconProp';
import CustomFieldType from 'Common/Types/CustomField/CustomFieldType';
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
import BaseModel from 'Common/Models/BaseModel';
@TableBillingAccessControl({
create: PlanSelect.Growth,
@@ -60,7 +60,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
@Entity({
name: 'StatusPageCustomField',
})
export default class StatusPageCustomField extends AccessControlModel {
export default class StatusPageCustomField extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,