Skip to content

Commit fc96adb

Browse files
authored
feat(cdevents-notification): CDEvents notification to produce CDEvents (#9997)
* feat(cdevents-notification): CDEvents notification to produce CDEvents * fix: linter issue Sort the import statements * fix: cdevents files formatting * adding validations for URL and cdevents type * fix prettier formatting issue * update regex for URL validation * review comments on placeholder/regex configurable * lint issue with order import * lint issue Prettier
1 parent 20d6ca8 commit fc96adb

File tree

9 files changed

+86
-2
lines changed

9 files changed

+86
-2
lines changed

halconfig/settings.js

+3
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ window.spinnakerSettings = {
142142
pubsub: {
143143
enabled: true,
144144
},
145+
cdevents: {
146+
enabled: true,
147+
},
145148
slack: slack,
146149
sms: sms,
147150
},

packages/app/src/settings.js

+3
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ window.spinnakerSettings = {
178178
sms: {
179179
enabled: true,
180180
},
181+
cdevents: {
182+
enabled: true,
183+
},
181184
},
182185
onDemandClusterThreshold: Number(onDemandClusterThreshold),
183186
pollSchedule: 30000,

packages/core/src/config/settings.ts

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface INotificationSettings {
2121
pubsub: { enabled: boolean };
2222
slack: { botName: string; enabled: boolean };
2323
sms: { enabled: boolean };
24+
cdevents: { enabled: boolean };
2425
}
2526

2627
export interface IFeatures {
@@ -152,6 +153,10 @@ export interface ISpinnakerSettings {
152153
useClassicFirewallLabels: boolean;
153154
kubernetesAdHocInfraWritesEnabled: boolean;
154155
changelogUrl: string;
156+
cdevents?: {
157+
validUrlPattern: string;
158+
validCDEvent: string;
159+
};
155160
}
156161

157162
export const SETTINGS: ISpinnakerSettings = (window as any).spinnakerSettings || {};

packages/core/src/notification/modal/NotificationDetails.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ export class NotificationDetails extends React.Component<INotificationDetailsPro
5454
}
5555

5656
private renderCustomMessage = (type: string, whenOption: string): React.ReactNode => {
57-
if (whenOption !== 'manualJudgment' && ['email', 'slack', 'googlechat', 'microsoftteams'].includes(type)) {
57+
if (
58+
whenOption !== 'manualJudgment' &&
59+
['email', 'slack', 'googlechat', 'microsoftteams', 'cdevents'].includes(type)
60+
) {
5861
return (
5962
<FormikFormField
6063
name={`message["${whenOption}"].text`}

packages/core/src/notification/notification.types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { INotificationTypeConfig } from '../domain';
66
import { Registry } from '../registry';
77

88
import { bearyChatNotification } from './selector/types/bearychat/beary.notification';
9+
import { cdEventsNotification } from './selector/types/cdevents/cdevents.notification';
910
import { emailNotification } from './selector/types/email/email.notification';
1011
import { githubstatusNotification } from './selector/types/githubstatus/githubstatus.notification';
1112
import { googlechatNotification } from './selector/types/googlechat/googlechat.notification';
@@ -23,6 +24,7 @@ import { smsNotification } from './selector/types/sms/sms.notification';
2324
pubsubNotification,
2425
slackNotification,
2526
smsNotification,
27+
cdEventsNotification,
2628
].forEach((config: INotificationTypeConfig) => {
2729
if (SETTINGS.notifications) {
2830
const notificationSetting: { enabled: boolean; botName?: string } =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
3+
import type { INotificationTypeCustomConfig } from '../../../../domain';
4+
import { FormikFormField, TextInput, Validators } from '../../../../presentation';
5+
6+
export class CDEventsNotificationType extends React.Component<INotificationTypeCustomConfig> {
7+
public render() {
8+
const { fieldName } = this.props;
9+
return (
10+
<>
11+
<FormikFormField
12+
label="Events Broker URL"
13+
name={fieldName ? `${fieldName}.address` : 'address'}
14+
validate={Validators.skipIfSpel(Validators.urlValue('Please enter a valid URL'))}
15+
input={(props) => (
16+
<TextInput
17+
inputClassName={'form-control input-sm'}
18+
{...props}
19+
placeholder="Enter an events message broker URL"
20+
/>
21+
)}
22+
required={true}
23+
/>
24+
<FormikFormField
25+
label="CDEvents Type"
26+
name={fieldName ? `${fieldName}.cdEventsType` : 'cdEventsType'}
27+
validate={Validators.skipIfSpel(Validators.cdeventsTypeValue('Please enter a valid CDEvents Type'))}
28+
input={(props) => (
29+
<TextInput inputClassName={'form-control input-sm'} {...props} placeholder="Enter a CDEvents type" />
30+
)}
31+
required={true}
32+
/>
33+
</>
34+
);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { CDEventsNotificationType } from './CDEventsNotificationType';
2+
import type { INotificationTypeConfig } from '../../../../domain';
3+
4+
export const cdEventsNotification: INotificationTypeConfig = {
5+
component: CDEventsNotificationType,
6+
key: 'cdevents',
7+
label: 'CDEvents',
8+
};

packages/core/src/notification/selector/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export * from './microsoftteams/MicrosoftTeamsNotificationType';
55
export * from './pubsub/PubsubNotificationType';
66
export * from './slack/SlackNotificationType';
77
export * from './sms/SmsNotificationType';
8+
export * from './cdevents/CDEventsNotificationType';

packages/core/src/presentation/forms/validation/validators.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { isNumber } from 'lodash';
2-
import { robotToHuman } from '../../robotToHumanFilter/robotToHuman.filter';
32

3+
import { SETTINGS } from '../../../config/settings';
4+
import { robotToHuman } from '../../robotToHumanFilter/robotToHuman.filter';
45
import type { IValidator } from './validation';
56

67
const THIS_FIELD = 'This field';
@@ -9,13 +10,33 @@ const VALID_EMAIL_REGEX = new RegExp(
910
'^(([^<>()\\[\\]\\\\.,;:\\s@"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@"]+)*)|(".+"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$',
1011
);
1112

13+
const urlPattern = SETTINGS.cdevents?.validUrlPattern ?? '^https?://.+$';
14+
const VALID_URL = new RegExp(urlPattern);
15+
16+
const cdeventPattern = SETTINGS.cdevents?.validCDEvent ?? '^dev\\.cdevents\\.[^.]+\\.[^.]+$';
17+
const VALID_CDEVENT_REGEX = new RegExp(cdeventPattern);
18+
1219
const emailValue = (message?: string): IValidator => {
1320
return function emailValue(val: string, label = THIS_FIELD) {
1421
message = message || `${label} is not a valid email address.`;
1522
return val && !VALID_EMAIL_REGEX.test(val) && message;
1623
};
1724
};
1825

26+
const urlValue = (message?: string): IValidator => {
27+
return function urlValue(val: string, label = THIS_FIELD) {
28+
message = message || `${label} is not a valid URL.`;
29+
return val && !VALID_URL.test(val) && message;
30+
};
31+
};
32+
33+
const cdeventsTypeValue = (message?: string): IValidator => {
34+
return function cdeventsTypeValue(val: string, label = THIS_FIELD) {
35+
message = message || `${label} is not a valid CDEvents Type.`;
36+
return val && !VALID_CDEVENT_REGEX.test(val) && message;
37+
};
38+
};
39+
1940
const isRequired = (message?: string): IValidator => {
2041
return function isRequired(val: any, label = THIS_FIELD) {
2142
message = message || `${label} is required.`;
@@ -138,6 +159,8 @@ export const Validators = {
138159
arrayNotEmpty,
139160
checkBetween,
140161
emailValue,
162+
cdeventsTypeValue,
163+
urlValue,
141164
isNum,
142165
isRequired,
143166
isValidJson,

0 commit comments

Comments
 (0)