mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-21 22:59:07 +00:00
add recurring field element adn controls.
This commit is contained in:
parent
72ffaace2d
commit
20e56fb1d7
@ -8,7 +8,6 @@ import OnCallDutyPolicyExecutionLogService from "Common/Server/Services/OnCallDu
|
||||
import logger from "Common/Server/Utils/Logger";
|
||||
import OnCallDutyPolicyEscalationRule from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRule";
|
||||
import OnCallDutyPolicyExecutionLog from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLog";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import IncidentService from "Common/Server/Services/IncidentService";
|
||||
|
||||
RunCron(
|
||||
@ -58,7 +57,6 @@ RunCron(
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
type ExecuteOnCallPolicyFunction = (
|
||||
executionLog: OnCallDutyPolicyExecutionLog,
|
||||
) => Promise<void>;
|
||||
@ -67,31 +65,30 @@ const executeOnCallPolicy: ExecuteOnCallPolicyFunction = async (
|
||||
executionLog: OnCallDutyPolicyExecutionLog,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
|
||||
// get trigger by incident
|
||||
if(executionLog.triggeredByIncidentId){
|
||||
// check if this incident is ack.
|
||||
const isAcknowledged: boolean = await IncidentService.isIncidentAcknowledged({
|
||||
incidentId: executionLog.triggeredByIncidentId
|
||||
});
|
||||
if (executionLog.triggeredByIncidentId) {
|
||||
// check if this incident is ack.
|
||||
const isAcknowledged: boolean =
|
||||
await IncidentService.isIncidentAcknowledged({
|
||||
incidentId: executionLog.triggeredByIncidentId,
|
||||
});
|
||||
|
||||
if(isAcknowledged){
|
||||
// then mark this policy as executed.
|
||||
if (isAcknowledged) {
|
||||
// then mark this policy as executed.
|
||||
await OnCallDutyPolicyExecutionLogService.updateOneById({
|
||||
id: executionLog.id!,
|
||||
data: {
|
||||
status: OnCallDutyPolicyStatus.Completed
|
||||
status: OnCallDutyPolicyStatus.Completed,
|
||||
},
|
||||
props: {
|
||||
isRoot: true
|
||||
}
|
||||
})
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check if this execution needs to be executed.
|
||||
|
||||
const currentDate: Date = OneUptimeDate.getCurrentDate();
|
||||
|
@ -882,7 +882,6 @@ export default class ScheduledMaintenance extends BaseModel {
|
||||
})
|
||||
public isOwnerNotifiedOfResourceCreation?: boolean = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -916,7 +915,6 @@ export default class ScheduledMaintenance extends BaseModel {
|
||||
})
|
||||
public subscriberNotificationsBeforeTheEvent?: Array<Recurring> = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -950,5 +948,4 @@ export default class ScheduledMaintenance extends BaseModel {
|
||||
nullable: true,
|
||||
})
|
||||
public nextSubscriberNotificationBeforeTheEventAt?: Date = undefined;
|
||||
|
||||
}
|
||||
|
@ -950,4 +950,37 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
nullable: true,
|
||||
})
|
||||
public customFields?: JSONObject = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceTemplate,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.JSON,
|
||||
required: false,
|
||||
isDefaultValueColumn: false,
|
||||
title: "Subscriber notifications before the event",
|
||||
description: "Should subscribers be notified before the event?",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.JSON,
|
||||
nullable: true,
|
||||
})
|
||||
public subscriberNotificationsBeforeTheEvent?: Array<Recurring> = undefined;
|
||||
}
|
||||
|
@ -1,18 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1725975175669 implements MigrationInterface {
|
||||
public name = 'MigrationName1725975175669'
|
||||
public name = "MigrationName1725975175669";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "ScheduledMaintenance" ADD "subscriberNotificationsBeforeTheEvent" jsonb`);
|
||||
await queryRunner.query(`ALTER TABLE "ScheduledMaintenance" ADD "nextSubscriberNotificationBeforeTheEventAt" TIMESTAMP WITH TIME ZONE`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_37b2094ce25cc62b4766a7d3b1" ON "ScheduledMaintenance" ("nextSubscriberNotificationBeforeTheEventAt") `);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_37b2094ce25cc62b4766a7d3b1"`);
|
||||
await queryRunner.query(`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "nextSubscriberNotificationBeforeTheEventAt"`);
|
||||
await queryRunner.query(`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "subscriberNotificationsBeforeTheEvent"`);
|
||||
}
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenance" ADD "subscriberNotificationsBeforeTheEvent" jsonb`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenance" ADD "nextSubscriberNotificationBeforeTheEventAt" TIMESTAMP WITH TIME ZONE`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_37b2094ce25cc62b4766a7d3b1" ON "ScheduledMaintenance" ("nextSubscriberNotificationBeforeTheEventAt") `,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_37b2094ce25cc62b4766a7d3b1"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "nextSubscriberNotificationBeforeTheEventAt"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "subscriberNotificationsBeforeTheEvent"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1725976810107 implements MigrationInterface {
|
||||
public name = "MigrationName1725976810107";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceTemplate" ADD "subscriberNotificationsBeforeTheEvent" jsonb`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceTemplate" DROP COLUMN "subscriberNotificationsBeforeTheEvent"`,
|
||||
);
|
||||
}
|
||||
}
|
@ -59,6 +59,7 @@ import { MigrationName1725898621366 } from "./1725898621366-MigrationName";
|
||||
import { MigrationName1725900315712 } from "./1725900315712-MigrationName";
|
||||
import { MigrationName1725901024444 } from "./1725901024444-MigrationName";
|
||||
import { MigrationName1725975175669 } from "./1725975175669-MigrationName";
|
||||
import { MigrationName1725976810107 } from "./1725976810107-MigrationName";
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
@ -121,5 +122,6 @@ export default [
|
||||
MigrationName1725898621366,
|
||||
MigrationName1725900315712,
|
||||
MigrationName1725901024444,
|
||||
MigrationName1725975175669
|
||||
MigrationName1725975175669,
|
||||
MigrationName1725976810107,
|
||||
];
|
||||
|
@ -41,8 +41,8 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
|
||||
public async isIncidentAcknowledged(data: {
|
||||
incidentId: ObjectID
|
||||
}){
|
||||
incidentId: ObjectID;
|
||||
}): Promise<boolean> {
|
||||
const incident: Model | null = await this.findOneBy({
|
||||
query: {
|
||||
_id: data.incidentId,
|
||||
@ -50,38 +50,39 @@ export class Service extends DatabaseService<Model> {
|
||||
select: {
|
||||
projectId: true,
|
||||
currentIncidentState: {
|
||||
order: true
|
||||
}
|
||||
order: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true
|
||||
}
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if(!incident){
|
||||
if (!incident) {
|
||||
throw new BadDataException("Incident not found");
|
||||
}
|
||||
|
||||
if(!incident.projectId){
|
||||
if (!incident.projectId) {
|
||||
throw new BadDataException("Incient Project ID not found");
|
||||
}
|
||||
|
||||
const ackIncidentState: IncidentState = await IncidentStateService.getAcknowledgedIncidentState({
|
||||
projectId: incident.projectId,
|
||||
props: {
|
||||
isRoot: true,
|
||||
}
|
||||
});
|
||||
const ackIncidentState: IncidentState =
|
||||
await IncidentStateService.getAcknowledgedIncidentState({
|
||||
projectId: incident.projectId,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const currentIncidentStateOrder: number = incident.currentIncidentState?.order!;
|
||||
const ackIncidentStateOrder: number = ackIncidentState.order!;
|
||||
const currentIncidentStateOrder: number =
|
||||
incident.currentIncidentState!.order!;
|
||||
const ackIncidentStateOrder: number = ackIncidentState.order!;
|
||||
|
||||
if(currentIncidentStateOrder>=ackIncidentStateOrder){
|
||||
return true;
|
||||
if (currentIncidentStateOrder >= ackIncidentStateOrder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async acknowledgeIncident(
|
||||
|
@ -153,9 +153,9 @@ export class Service extends DatabaseService<IncidentState> {
|
||||
}
|
||||
|
||||
public async getAllIncidentStates(data: {
|
||||
projectId: ObjectID,
|
||||
props: DatabaseCommonInteractionProps,
|
||||
}){
|
||||
projectId: ObjectID;
|
||||
props: DatabaseCommonInteractionProps;
|
||||
}): Promise<Array<IncidentState>> {
|
||||
const incidentStates: Array<IncidentState> = await this.findBy({
|
||||
query: {
|
||||
projectId: data.projectId,
|
||||
@ -168,24 +168,25 @@ export class Service extends DatabaseService<IncidentState> {
|
||||
select: {
|
||||
_id: true,
|
||||
isResolvedState: true,
|
||||
isAcknowledgedState: true,
|
||||
isAcknowledgedState: true,
|
||||
isCreatedState: true,
|
||||
order: true
|
||||
order: true,
|
||||
},
|
||||
props: data.props,
|
||||
});
|
||||
|
||||
return incidentStates;
|
||||
return incidentStates;
|
||||
}
|
||||
|
||||
public async getUnresolvedIncidentStates(
|
||||
projectId: ObjectID,
|
||||
props: DatabaseCommonInteractionProps,
|
||||
): Promise<IncidentState[]> {
|
||||
const incidentStates: Array<IncidentState> = await this.getAllIncidentStates({
|
||||
projectId: projectId,
|
||||
props: props
|
||||
})
|
||||
const incidentStates: Array<IncidentState> =
|
||||
await this.getAllIncidentStates({
|
||||
projectId: projectId,
|
||||
props: props,
|
||||
});
|
||||
|
||||
const unresolvedIncidentStates: Array<IncidentState> = [];
|
||||
|
||||
@ -201,21 +202,25 @@ export class Service extends DatabaseService<IncidentState> {
|
||||
}
|
||||
|
||||
public async getAcknowledgedIncidentState(data: {
|
||||
projectId: ObjectID,
|
||||
props: DatabaseCommonInteractionProps,
|
||||
}
|
||||
): Promise<IncidentState> {
|
||||
const incidentStates: Array<IncidentState> = await this.getAllIncidentStates({
|
||||
projectId: data.projectId,
|
||||
props: data.props
|
||||
})
|
||||
projectId: ObjectID;
|
||||
props: DatabaseCommonInteractionProps;
|
||||
}): Promise<IncidentState> {
|
||||
const incidentStates: Array<IncidentState> =
|
||||
await this.getAllIncidentStates({
|
||||
projectId: data.projectId,
|
||||
props: data.props,
|
||||
});
|
||||
|
||||
const ackIncidentState: IncidentState | undefined = incidentStates.find((incidentState: IncidentState)=>{
|
||||
return incidentState?.isAcknowledgedState;
|
||||
});
|
||||
const ackIncidentState: IncidentState | undefined = incidentStates.find(
|
||||
(incidentState: IncidentState) => {
|
||||
return incidentState?.isAcknowledgedState;
|
||||
},
|
||||
);
|
||||
|
||||
if(!ackIncidentState){
|
||||
throw new BadDataException("Acknowledged Incident State not found for this project");
|
||||
if (!ackIncidentState) {
|
||||
throw new BadDataException(
|
||||
"Acknowledged Incident State not found for this project",
|
||||
);
|
||||
}
|
||||
|
||||
return ackIncidentState;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import DatabaseProperty from "../Database/DatabaseProperty";
|
||||
import OneUptimeDate from "../Date";
|
||||
import BadDataException from "../Exception/BadDataException";
|
||||
import { JSONObject, ObjectType } from "../JSON";
|
||||
import { JSONArray, JSONObject, ObjectType } from "../JSON";
|
||||
import JSONFunctions from "../JSONFunctions";
|
||||
import PositiveNumber from "../PositiveNumber";
|
||||
import EventInterval from "./EventInterval";
|
||||
@ -114,6 +114,18 @@ export default class Recurring extends DatabaseProperty {
|
||||
});
|
||||
}
|
||||
|
||||
public static fromJSONArray(
|
||||
json: JSONArray | Array<Recurring>,
|
||||
): Array<Recurring> {
|
||||
const arrayToReturn: Array<Recurring> = [];
|
||||
|
||||
for (const item of json) {
|
||||
arrayToReturn.push(this.fromJSON(item));
|
||||
}
|
||||
|
||||
return arrayToReturn;
|
||||
}
|
||||
|
||||
public static override fromJSON(json: JSONObject | Recurring): Recurring {
|
||||
if (json instanceof Recurring) {
|
||||
return json;
|
||||
|
106
Common/UI/Components/Events/RecurringArrayFieldElement.tsx
Normal file
106
Common/UI/Components/Events/RecurringArrayFieldElement.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import EventInterval from "Common/Types/Events/EventInterval";
|
||||
import Recurring from "Common/Types/Events/Recurring";
|
||||
import PositiveNumber from "Common/Types/PositiveNumber";
|
||||
import React, { FunctionComponent, ReactElement, useState } from "react";
|
||||
import RecurringFieldElement from "./RecurringFieldElement";
|
||||
import Button, { ButtonSize, ButtonStyleType } from "../Button/Button";
|
||||
import IconProp from "../../../Types/Icon/IconProp";
|
||||
|
||||
export interface ComponentProps {
|
||||
error?: string | undefined;
|
||||
onChange?: ((value: Array<Recurring>) => void) | undefined;
|
||||
initialValue?: Array<Recurring> | undefined;
|
||||
}
|
||||
|
||||
const RecurringArrayFieldElement: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const [recurrings, setRecurrings] = useState<Array<Recurring> | undefined>(
|
||||
props.initialValue && props.initialValue.length > 0
|
||||
? props.initialValue.map((item: Recurring) => {
|
||||
return Recurring.fromJSON(item);
|
||||
})
|
||||
: undefined,
|
||||
);
|
||||
|
||||
type UpdateRecurringFunction = (recurring: Recurring, index: number) => void;
|
||||
|
||||
const updateRecurrings: UpdateRecurringFunction = (
|
||||
recurring: Recurring,
|
||||
index: number,
|
||||
): void => {
|
||||
const existingRecurrings: Array<Recurring> = [...(recurrings || [])];
|
||||
|
||||
existingRecurrings[index] = recurring;
|
||||
|
||||
setRecurrings(existingRecurrings);
|
||||
|
||||
if (props.onChange) {
|
||||
props.onChange(existingRecurrings);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{recurrings &&
|
||||
recurrings.map((recurring: Recurring, index: number) => {
|
||||
return (
|
||||
<div key={index} className="flex">
|
||||
<div className="">
|
||||
<RecurringFieldElement
|
||||
initialValue={recurring}
|
||||
onChange={(recurring: Recurring) => {
|
||||
updateRecurrings(recurring, index);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
dataTestId={`delete-${index}`}
|
||||
title="Delete"
|
||||
buttonStyle={ButtonStyleType.ICON}
|
||||
icon={IconProp.Trash}
|
||||
onClick={() => {
|
||||
const newData: Array<Recurring> = [...(recurrings || [])];
|
||||
newData.splice(index, 1);
|
||||
setRecurrings(newData);
|
||||
props.onChange && props.onChange(newData);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="flex space-x-3 mt-3">
|
||||
<Button
|
||||
dataTestId={`add-recurring`}
|
||||
title="Add"
|
||||
buttonStyle={ButtonStyleType.NORMAL}
|
||||
buttonSize={ButtonSize.Small}
|
||||
icon={IconProp.Add}
|
||||
onClick={() => {
|
||||
const newData: Array<Recurring> = [...(recurrings || [])];
|
||||
|
||||
const recurring: Recurring = new Recurring();
|
||||
recurring.intervalCount = new PositiveNumber(1);
|
||||
recurring.intervalType = EventInterval.Day;
|
||||
|
||||
newData.push(recurring);
|
||||
setRecurrings(newData);
|
||||
props.onChange && props.onChange(newData);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{props.error && (
|
||||
<p data-testid="error-message" className="mt-1 text-sm text-red-400">
|
||||
{props.error}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecurringArrayFieldElement;
|
30
Common/UI/Components/Events/RecurringArrayViewElement.tsx
Normal file
30
Common/UI/Components/Events/RecurringArrayViewElement.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import Recurring from "Common/Types/Events/Recurring";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import RecurringViewElement from "./RecurringViewElement";
|
||||
|
||||
export interface ComponentProps {
|
||||
value?: Array<Recurring> | undefined;
|
||||
}
|
||||
|
||||
const RecurringArrayViewElement: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
if (!props.value) {
|
||||
return <p>-</p>;
|
||||
}
|
||||
|
||||
const items: Array<Recurring> = Recurring.fromJSONArray(props.value);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{items &&
|
||||
items.length > 0 &&
|
||||
items.map((item: Recurring, index: number) => {
|
||||
return <RecurringViewElement key={index} value={item} />;
|
||||
})}
|
||||
{(!items || items.length === 0) && <p>-</p>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecurringArrayViewElement;
|
@ -33,6 +33,9 @@ import DropdownUtil from "Common/UI/Utils/Dropdown";
|
||||
import IconProp from "Common/Types/Icon/IconProp";
|
||||
import { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import FormValues from "Common/UI/Components/Forms/Types/FormValues";
|
||||
import { CustomElementProps } from "Common/UI/Components/Forms/Types/Field";
|
||||
import RecurringArrayFieldElement from "Common/UI/Components/Events/RecurringArrayFieldElement";
|
||||
import Recurring from "Common/Types/Events/Recurring";
|
||||
|
||||
export interface ComponentProps {
|
||||
query?: Query<ScheduledMaintenance> | undefined;
|
||||
@ -84,6 +87,7 @@ const ScheduledMaintenancesTable: FunctionComponent<ComponentProps> = (
|
||||
shouldStatusPageSubscribersBeNotifiedWhenEventChangedToEnded: true,
|
||||
shouldStatusPageSubscribersBeNotifiedWhenEventChangedToOngoing:
|
||||
true,
|
||||
subscriberNotificationsBeforeTheEvent: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -432,6 +436,30 @@ const ScheduledMaintenancesTable: FunctionComponent<ComponentProps> = (
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
subscriberNotificationsBeforeTheEvent: true,
|
||||
},
|
||||
stepId: "subscribers",
|
||||
title: "Send reminders to subscribers before the event",
|
||||
description:
|
||||
"Please add a list of notification options to notify subscribers before the event",
|
||||
fieldType: FormFieldSchemaType.CustomComponent,
|
||||
getCustomElement: (
|
||||
value: FormValues<ScheduledMaintenance>,
|
||||
props: CustomElementProps,
|
||||
) => {
|
||||
return (
|
||||
<RecurringArrayFieldElement
|
||||
{...props}
|
||||
initialValue={
|
||||
value.subscriberNotificationsBeforeTheEvent as Array<Recurring>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
|
@ -24,6 +24,11 @@ import ScheduledMaintenance from "Common/Models/DatabaseModels/ScheduledMaintena
|
||||
import ScheduledMaintenanceStateTimeline from "Common/Models/DatabaseModels/ScheduledMaintenanceStateTimeline";
|
||||
import StatusPage from "Common/Models/DatabaseModels/StatusPage";
|
||||
import React, { Fragment, FunctionComponent, ReactElement } from "react";
|
||||
import FormValues from "Common/UI/Components/Forms/Types/FormValues";
|
||||
import { CustomElementProps } from "Common/UI/Components/Forms/Types/Field";
|
||||
import RecurringArrayFieldElement from "Common/UI/Components/Events/RecurringArrayFieldElement";
|
||||
import Recurring from "Common/Types/Events/Recurring";
|
||||
import RecurringArrayViewElement from "Common/UI/Components/Events/RecurringArrayViewElement";
|
||||
|
||||
const ScheduledMaintenanceView: FunctionComponent<
|
||||
PageComponentProps
|
||||
@ -53,6 +58,10 @@ const ScheduledMaintenanceView: FunctionComponent<
|
||||
title: "Status Pages",
|
||||
id: "status-pages",
|
||||
},
|
||||
{
|
||||
title: "Subscribers",
|
||||
id: "subscribers",
|
||||
},
|
||||
{
|
||||
title: "Labels",
|
||||
id: "labels",
|
||||
@ -127,6 +136,72 @@ const ScheduledMaintenanceView: FunctionComponent<
|
||||
required: false,
|
||||
placeholder: "Select Status Pages",
|
||||
},
|
||||
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedOnEventCreated: true,
|
||||
},
|
||||
|
||||
title: "Event Created: Notify Status Page Subscribers",
|
||||
stepId: "subscribers",
|
||||
description:
|
||||
"Should status page subscribers be notified when this event is created?",
|
||||
fieldType: FormFieldSchemaType.Checkbox,
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedWhenEventChangedToOngoing:
|
||||
true,
|
||||
},
|
||||
|
||||
title: "Event Ongoing: Notify Status Page Subscribers",
|
||||
stepId: "subscribers",
|
||||
description:
|
||||
"Should status page subscribers be notified when this event state changes to ongoing?",
|
||||
fieldType: FormFieldSchemaType.Checkbox,
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedWhenEventChangedToEnded:
|
||||
true,
|
||||
},
|
||||
|
||||
title: "Event Ended: Notify Status Page Subscribers",
|
||||
stepId: "subscribers",
|
||||
description:
|
||||
"Should status page subscribers be notified when this event state changes to ended?",
|
||||
fieldType: FormFieldSchemaType.Checkbox,
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
subscriberNotificationsBeforeTheEvent: true,
|
||||
},
|
||||
stepId: "subscribers",
|
||||
title: "Send reminders to subscribers before the event",
|
||||
description:
|
||||
"Please add a list of notification options to notify subscribers before the event",
|
||||
fieldType: FormFieldSchemaType.CustomComponent,
|
||||
getCustomElement: (
|
||||
value: FormValues<ScheduledMaintenance>,
|
||||
props: CustomElementProps,
|
||||
) => {
|
||||
return (
|
||||
<RecurringArrayFieldElement
|
||||
{...props}
|
||||
initialValue={
|
||||
value.subscriberNotificationsBeforeTheEvent as Array<Recurring>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
@ -276,6 +351,20 @@ const ScheduledMaintenanceView: FunctionComponent<
|
||||
title: "Created At",
|
||||
fieldType: FieldType.DateTime,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedOnEventCreated: true,
|
||||
},
|
||||
title: "Send reminders to subscribers before the event",
|
||||
fieldType: FieldType.Boolean,
|
||||
getElement: (item: ScheduledMaintenance): ReactElement => {
|
||||
return (
|
||||
<RecurringArrayViewElement
|
||||
value={item.subscriberNotificationsBeforeTheEvent}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedOnEventCreated: true,
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
getFormSteps,
|
||||
getTemplateFormFields,
|
||||
} from "./ScheduledMaintenanceTemplates";
|
||||
import RecurringArrayViewElement from "Common/UI/Components/Events/RecurringArrayViewElement";
|
||||
|
||||
const TeamView: FunctionComponent<PageComponentProps> = (): ReactElement => {
|
||||
const modelId: ObjectID = Navigation.getLastParamAsObjectID();
|
||||
@ -176,7 +177,22 @@ const TeamView: FunctionComponent<PageComponentProps> = (): ReactElement => {
|
||||
return Boolean(item.isRecurringEvent);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedOnEventCreated: true,
|
||||
},
|
||||
title: "Send reminders to subscribers before the event",
|
||||
fieldType: FieldType.Boolean,
|
||||
getElement: (
|
||||
item: ScheduledMaintenanceTemplate,
|
||||
): ReactElement => {
|
||||
return (
|
||||
<RecurringArrayViewElement
|
||||
value={item.subscriberNotificationsBeforeTheEvent}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
shouldStatusPageSubscribersBeNotifiedOnEventCreated: true,
|
||||
|
@ -19,6 +19,7 @@ import { CustomElementProps } from "Common/UI/Components/Forms/Types/Field";
|
||||
import RecurringFieldElement from "Common/UI/Components/Events/RecurringFieldElement";
|
||||
import Recurring from "Common/Types/Events/Recurring";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import RecurringArrayFieldElement from "Common/UI/Components/Events/RecurringArrayFieldElement";
|
||||
|
||||
type GetTemplateFormFieldsFunction = (data: {
|
||||
isViewPage: boolean;
|
||||
@ -230,6 +231,30 @@ export const getTemplateFormFields: GetTemplateFormFieldsFunction = (data: {
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
subscriberNotificationsBeforeTheEvent: true,
|
||||
},
|
||||
stepId: "subscribers",
|
||||
title: "Send reminders to subscribers before the event",
|
||||
description:
|
||||
"Please add a list of notification options to notify subscribers before the event",
|
||||
fieldType: FormFieldSchemaType.CustomComponent,
|
||||
getCustomElement: (
|
||||
value: FormValues<ScheduledMaintenanceTemplate>,
|
||||
props: CustomElementProps,
|
||||
) => {
|
||||
return (
|
||||
<RecurringArrayFieldElement
|
||||
{...props}
|
||||
initialValue={
|
||||
value.subscriberNotificationsBeforeTheEvent as Array<Recurring>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isRecurringEvent: true,
|
||||
|
Loading…
Reference in New Issue
Block a user