diff --git a/package.json b/package.json index 88f3f8e154..5830b9a281 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.23.0", + "@devtron-labs/devtron-fe-common-lib": "1.23.1", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rjsf/core": "^5.13.3", "@rjsf/utils": "^5.13.3", diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index f14667d53c..39cb0d7537 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { Component } from 'react' +import { Component } from 'react' import { showError, Progressing, @@ -34,10 +34,17 @@ import { TYPE_3_CHARACTERS_TO_SEE_MATCHING_RESULTS, TYPE_TO_SEE_MATCHING_RESULTS, SourceTypeMap, + Button, + ButtonStyleType, + ButtonVariantType, + ComponentSizeType, + Icon, + IconsProps, + ButtonComponentType, + stopPropagation, + BreadCrumb, } from '@devtron-labs/devtron-fe-common-lib' -import { RouteComponentProps, Link } from 'react-router-dom' import { components } from 'react-select' -import Tippy from '@tippyjs/react' import CreatableSelect from 'react-select/creatable' import SESConfigModal from './SESConfigModal' import { SlackConfigModal } from './SlackConfigModal' @@ -59,98 +66,16 @@ import { import './notifications.scss' import { getAppListMin, getEnvironmentListMin } from '../../services/service' import { SMTPConfigModal } from './SMTPConfigModal' -import { EMAIL_AGENT } from './types' +import { + AddNotificationsProps, + AddNotificationState, + EMAIL_AGENT, + FilterOptions, + NotificationPipelineType, +} from './types' import { WebhookConfigModal } from './WebhookConfigModal' import { getClusterListMin } from '@Components/ClusterNodes/clusterNodes.service' - -interface AddNotificationsProps extends RouteComponentProps<{}> {} - -export enum FilterOptions { - ENVIRONMENT = 'environment', - APPLICATION = 'application', - PROJECT = 'project', - CLUSTER = 'cluster', -} -interface Options { - environment: { - value: number - label: string - type: string - }[] - application: { - value: number - label: string - type: string - }[] - project: { - value: number - label: string - type: string - }[] - cluster: { - value: number - label: string - type: string - }[] -} -export interface PipelineType { - checkbox: { - isChecked: boolean - value: 'CHECKED' | 'INTERMEDIATE' - } - type: 'CI' | 'CD' - pipelineId: number - pipelineName: string - environmentName?: string - branch?: string - appName: string - success: boolean - trigger: boolean - failure: boolean - appliedFilters: Array<{ type: string; value: number | string | undefined; name: string; label: string | undefined }> - isVirtualEnvironment?: boolean -} - -interface AddNotificationState { - view: string - showSlackConfigModal: boolean - showSESConfigModal: boolean - showSMTPConfigModal: boolean - channelOptions: { - __isNew__?: boolean - label: string - value - data: { dest: 'slack' | 'ses' | 'smtp' | 'webhook' | ''; configId: number; recipient: string } - }[] - sesConfigOptions: { - id: number - configName: string - dest: 'slack' | 'ses' | 'smtp' | 'webhook' | '' - recipient: string - }[] - smtpConfigOptions: { - id: number - configName: string - dest: 'slack' | 'ses' | 'smtp' | 'webhook' | '' - recipient: string - }[] - isLoading: boolean - appliedFilters: Array<{ type: string; value: number | string | undefined; label: string | undefined }> - selectedChannels: { - __isNew__?: boolean - label: string - value - data: { dest: 'slack' | 'ses' | 'smtp' | 'webhook' | ''; configId: number; recipient: string } - }[] - openSelectPipeline: boolean - pipelineList: PipelineType[] - filterInput: string - emailAgentConfigId: number - options: Options - isApplistLoading: boolean - selectedEmailAgent: string - showWebhookConfigModal: boolean -} +import { EVENT_ICONS, EVENT_LABEL, EVENTS } from './constants' export class AddNotification extends Component { filterOptionsMain = [ @@ -189,7 +114,6 @@ export class AddNotification extends Component { const state = { ...this.state } const pipeline = state.pipelineList[pipelineIndex] pipeline[stage] = !pipeline[stage] - if (pipeline.success && pipeline.trigger && pipeline.failure) { + if (rowType === NotificationPipelineType.BASE) { pipeline.checkbox = { - value: 'CHECKED', - isChecked: true, + value: CHECKBOX_VALUE.CHECKED, + isChecked: pipeline.configApproval, } - } else if (pipeline.success || pipeline.trigger || pipeline.failure) { - pipeline.checkbox = { - value: 'INTERMEDIATE', - isChecked: true, - } - } else if (!(pipeline.success && pipeline.trigger && pipeline.failure)) { - pipeline.checkbox = { - value: 'CHECKED', - isChecked: false, + } else { + const baseEvents = pipeline.success && pipeline.trigger && pipeline.failure + const approvalEvents = pipeline.configApproval && pipeline.imageApproval + const anyEvent = + pipeline.success || + pipeline.trigger || + pipeline.failure || + pipeline.configApproval || + pipeline.imageApproval + + const isFullySelected = + rowType === NotificationPipelineType.CI + ? baseEvents && !pipeline.configApproval && !pipeline.imageApproval + : baseEvents && approvalEvents + + if (isFullySelected) { + pipeline.checkbox = { + value: CHECKBOX_VALUE.CHECKED, + isChecked: true, + } + } else if (anyEvent) { + pipeline.checkbox = { + value: CHECKBOX_VALUE.INTERMEDIATE, + isChecked: true, + } + } else { + pipeline.checkbox = { + value: CHECKBOX_VALUE.CHECKED, + isChecked: false, + } } } state.pipelineList[pipelineIndex] = pipeline this.setState(state) } - togglePipelineCheckbox(pipelineIndex: number): void { + togglePipelineCheckbox(pipelineIndex: number, rowType: NotificationPipelineType): void { const state = { ...this.state } const pipeline = state.pipelineList[pipelineIndex] pipeline.checkbox.isChecked = !pipeline.checkbox.isChecked - pipeline.checkbox.value = pipeline.checkbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' - pipeline.trigger = pipeline.checkbox.isChecked - pipeline.success = pipeline.checkbox.isChecked - pipeline.failure = pipeline.checkbox.isChecked + pipeline.checkbox.value = pipeline.checkbox.isChecked ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE + pipeline.trigger = rowType !== NotificationPipelineType.BASE ? pipeline.checkbox.isChecked : false + pipeline.success = rowType !== NotificationPipelineType.BASE ? pipeline.checkbox.isChecked : false + pipeline.failure = rowType !== NotificationPipelineType.BASE ? pipeline.checkbox.isChecked : false + pipeline.configApproval = rowType === NotificationPipelineType.CI ? false : pipeline.checkbox.isChecked + pipeline.imageApproval = + rowType === NotificationPipelineType.CI || rowType === NotificationPipelineType.BASE + ? false + : pipeline.checkbox.isChecked state.pipelineList[pipelineIndex] = pipeline this.setState(state) } @@ -405,7 +355,11 @@ export class AddNotification extends Component { + this.props.history.push(`${URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_NOTIFICATIONS}/channels`) + } + + saveNotification = (): void => { const selectedPipelines = this.state.pipelineList.filter((p) => p.checkbox.isChecked) if (!selectedPipelines.length) { ToastManager.showToast({ @@ -448,7 +402,7 @@ export class AddNotification extends Component { - this.props.history.push(`${URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_NOTIFICATIONS}/channels`) + this.handleBackClick() ToastManager.showToast({ variant: ToastVariantType.success, description: 'Saved Successfully', @@ -747,14 +701,13 @@ export class AddNotification extends Component - Pipeline Name + Resource Application Name - Type Env/Branch Events {this.state.pipelineList.map((row, rowIndex) => { - const _isCi = row.branch && row.type === 'CI' + const _isCi = row.branch && row.type === NotificationPipelineType.CI let _isWebhookCi if (_isCi) { try { @@ -765,102 +718,151 @@ export class AddNotification extends Component - - { - this.togglePipelineCheckbox(rowIndex) - }} - > - - - - - {row.appliedFilters.length ? ( - <> - All current and future pipelines matching. -
- {row.appliedFilters.map((e) => { - return ( - - {e?.type}: {e?.name} - - ) - })} -
{' '} - - ) : ( - row.pipelineName - )} - - {row?.appName} - {renderPipelineTypeIcon(row)} - - {_isCi && ( - - - - )} - {row.type === 'CD' ? row?.environmentName : ''} - - - -
- { - this.handlePipelineEventType(rowIndex, 'trigger') - }} - > - - -
-
- -
- { - this.handlePipelineEventType(rowIndex, 'success') - }} - > - - -
-
- -
- { - this.handlePipelineEventType(rowIndex, 'failure') - }} - > - - -
-
- - + <> + + + { + stopPropagation(e) + this.togglePipelineCheckbox(rowIndex, row.type) + }} + > + + + + + {renderPipelineTypeIcon(row, 16)} + {row.appliedFilters.length ? ( + <> + + {isApprovalPipeline + ? 'Base configuration matching:' + : `All existing and future ${row.type === NotificationPipelineType.CI ? 'build' : 'deployment'} pipelines matching:`} + +
+ {row.appliedFilters.map((e) => { + return ( + + {e?.type}: {e?.name} + + ) + })} +
+ + ) : ( + row.pipelineName + )} + + {row?.appName} + + {_isCi && ( + + + + )} + {row.type === NotificationPipelineType.CD ? row?.environmentName : ''} + + + {isApprovalPipeline + ? Object.values(EVENTS).map((event) => { + if (event === EVENTS.CONFIG_APPROVAL) { + return ( + + /> + - + variant={ButtonVariantType.primary} + disabled={this.state.isLoading} + /> ) diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 50119745dc..7d1e8a4a41 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -15,53 +15,55 @@ */ import { Component } from 'react' -import Tippy from '@tippyjs/react' + import { - showError, - Progressing, - PopupMenu, - Checkbox, - Reload, - GenericEmptyState, - CiPipelineSourceConfig, - EMPTY_STATE_STATUS, - Pagination, - ToastManager, - ToastVariantType, - TOAST_ACCESS_DENIED, Button, - ButtonVariantType, ButtonStyleType, + ButtonVariantType, + Checkbox, + CHECKBOX_VALUE, + Chip, + CiPipelineSourceConfig, ComponentSizeType, ConfirmationModal, ConfirmationModalVariantType, + EMPTY_STATE_STATUS, + GenericEmptyState, + Icon, + Pagination, + PopupMenu, + Progressing, + Reload, + showError, SourceTypeMap, + stopPropagation, + TOAST_ACCESS_DENIED, + ToastManager, + ToastVariantType, } from '@devtron-labs/devtron-fe-common-lib' + +import { InValidHostUrlWarningBlock } from '@Components/common' + import EmptyImage from '../../assets/img/ic-empty-notifications.png' +import { ViewType } from '../../config' +import { getHostURLConfiguration } from '../../services/service' +import { ModifyRecipientsModal } from './ModifyRecipientsModal' import { - getNotificationConfigurations, deleteNotifications, - updateNotificationEvents, getChannelsAndEmailsFilteredByEmail, + getNotificationConfigurations, + updateNotificationEvents, } from './notifications.service' -import { ReactComponent as Add } from '@Icons/ic-add.svg' -import { ReactComponent as Trash } from '@Icons/ic-delete-interactive.svg' -import { ReactComponent as Bell } from '@Icons/ic-bell.svg' -import { ReactComponent as User } from '@Icons/ic-users.svg' -import { ReactComponent as Slack } from '@Icons/slack-logo.svg' -import { ReactComponent as Email } from '@Icons/ic-mail.svg' -import { ReactComponent as Check } from '@Icons/ic-check.svg' -import { ReactComponent as Play } from '@Icons/ic-play.svg' -import { ReactComponent as Info } from '@Icons/ic-info-outline.svg' -import { ReactComponent as Webhook } from '@Icons/ic-CIWebhook.svg' -import { ViewType, URLS } from '../../config' -import { ModifyRecipientsModal } from './ModifyRecipientsModal' -import { getHostURLConfiguration } from '../../services/service' -import { renderPipelineTypeIcon } from './notifications.util' -import { NotificationTabState } from './types' -import { InValidHostUrlWarningBlock } from '@Components/common' +import { getRecipientChipStartIcon, renderPipelineTypeIcon } from './notifications.util' +import { NotificationPipelineType, NotificationTabState } from './types' +import { EVENT_ID } from './constants' +import { BulkMultiSelectTagWidget } from './BulkMultiSelectWidget' +import React from 'react' +import { AddNotificationButton } from './AddNotificationButton' export class NotificationTab extends Component { + bulkMultiSelectWidgetRef = React.createRef() + constructor(props) { super(props) this.state = { @@ -73,21 +75,30 @@ export class NotificationTab extends Component { showDeleteDialog: false, headerCheckbox: { isChecked: false, - value: 'INTERMEDIATE', + value: CHECKBOX_VALUE.INTERMEDIATE, }, - triggerCheckbox: { - isChecked: false, - value: 'INTERMEDIATE', - }, - successCheckbox: { - isChecked: false, - value: 'INTERMEDIATE', - }, - failureCheckbox: { - isChecked: false, - value: 'INTERMEDIATE', + events: { + trigger: { + isChecked: false, + value: CHECKBOX_VALUE.INTERMEDIATE, + }, + success: { + isChecked: false, + value: CHECKBOX_VALUE.INTERMEDIATE, + }, + failure: { + isChecked: false, + value: CHECKBOX_VALUE.INTERMEDIATE, + }, + configApproval: { + isChecked: false, + value: CHECKBOX_VALUE.INTERMEDIATE, + }, + imageApproval: { + isChecked: false, + value: CHECKBOX_VALUE.INTERMEDIATE, + }, }, - // TODO: create new component for modify events menu payloadUpdateEvents: [], pagination: { size: 20, @@ -98,12 +109,8 @@ export class NotificationTab extends Component { deleting: false, confirmation: false, singleDeletedId: 0, - disableEdit: false, + selectedNotificationList: [], } - this.updateNotificationEvents = this.updateNotificationEvents.bind(this) - this.changePageSize = this.changePageSize.bind(this) - this.changePage = this.changePage.bind(this) - this.onChangePipelineCheckbox = this.onChangePipelineCheckbox.bind(this) } componentDidMount() { @@ -118,15 +125,15 @@ export class NotificationTab extends Component { }) } - getHostURLConfig() { + getHostURLConfig = () => { getHostURLConfiguration() .then((response) => { this.setState({ hostURLConfig: response.result }) }) - .catch((error) => {}) + .catch(() => {}) } - getAllNotifications() { + getAllNotifications = () => { getNotificationConfigurations(this.state.pagination.offset, this.state.pagination.pageSize) .then((response: any) => { this.setState({ @@ -135,7 +142,7 @@ export class NotificationTab extends Component { notificationList: response.result.settings, headerCheckbox: { isChecked: false, - value: 'INTERMEDIATE', + value: CHECKBOX_VALUE.INTERMEDIATE, }, pagination: { ...this.state.pagination, @@ -149,25 +156,23 @@ export class NotificationTab extends Component { }) } - getChannels() { + getChannels = () => { getChannelsAndEmailsFilteredByEmail() .then((response) => { let list: any[] = response.result || [] - list = list.map((item) => { - return { - label: item.recipient, - value: item.recipient, - data: item, - } - }) + list = list.map((item) => ({ + label: item.recipient, + value: item.recipient, + data: item, + })) this.setState({ channelList: list }) }) - .catch((error) => { - this.setState({ disableEdit: true }) + .catch(() => { + this.props.toggleDisableEdit(true) }) } - changePage(pageNo, pageSize?): void { + changePage = (pageNo, pageSize?): void => { const state = { ...this.state } state.view = ViewType.LOADING state.pagination.offset = pageSize ? 0 : (pageNo - 1) * this.state.pagination.pageSize @@ -177,11 +182,11 @@ export class NotificationTab extends Component { }) } - changePageSize(pageSize): void { + changePageSize = (pageSize): void => { this.changePage(1, pageSize) } - toggleNotification(id: number): void { + toggleNotification = (id: number): void => { const state = { ...this.state } let isAnySelected = false let areAllSelected = true @@ -194,22 +199,25 @@ export class NotificationTab extends Component { return config }) state.headerCheckbox.isChecked = isAnySelected - state.headerCheckbox.value = areAllSelected ? 'CHECKED' : 'INTERMEDIATE' + state.headerCheckbox.value = areAllSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE this.setState(state) } - toggleAllNotification(): void { + toggleAllNotification = (): void => { const state = { ...this.state } state.headerCheckbox.isChecked = !state.headerCheckbox.isChecked - state.headerCheckbox.value = state.headerCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' + state.headerCheckbox.value = state.headerCheckbox.isChecked + ? CHECKBOX_VALUE.CHECKED + : CHECKBOX_VALUE.INTERMEDIATE state.notificationList = state.notificationList.map((config) => { config.isSelected = state.headerCheckbox.isChecked return config }) this.setState(state) + this.setState({ selectedNotificationList: state.notificationList.filter((row) => row.isSelected) }) } - onOpenEditNotficationMenu(): void { + onOpenEditNotificationMenu = (): void => { const allSelectedRows = this.state.notificationList .filter((row) => row.isSelected) .map((row) => { @@ -223,6 +231,12 @@ export class NotificationTab extends Component { if (row.failure) { eventTypeIds.push(3) } + if (row.configApproval) { + eventTypeIds.push(4) + } + if (row.imageApproval) { + eventTypeIds.push(7) + } return { id: row.id, @@ -230,94 +244,83 @@ export class NotificationTab extends Component { trigger: row.trigger, success: row.success, failure: row.failure, + configApproval: row.configApproval, + imageApproval: row.imageApproval, } }) let isAnyTriggerEventSelected = false let isAnySuccessEventSelected = false let isAnyFailureEventSelected = false + let isAnyConfigApprovalEventSelected = false + let isAnyImageApprovalEventSelected = false let areAllTriggerEventSelected = true - let areAllSucessEventSelected = true + let areAllSuccessEventSelected = true let areAllFailureEventSelected = true + let areAllConfigApprovalEventSelected = true + let areAllImageApprovalEventSelected = true for (let i = 0; i < allSelectedRows.length; i++) { isAnyTriggerEventSelected = isAnyTriggerEventSelected || allSelectedRows[i].trigger isAnySuccessEventSelected = isAnySuccessEventSelected || allSelectedRows[i].success isAnyFailureEventSelected = isAnyFailureEventSelected || allSelectedRows[i].failure + isAnyConfigApprovalEventSelected = isAnyConfigApprovalEventSelected || allSelectedRows[i].configApproval + isAnyImageApprovalEventSelected = isAnyImageApprovalEventSelected || allSelectedRows[i].imageApproval areAllTriggerEventSelected = areAllTriggerEventSelected && allSelectedRows[i].trigger - areAllSucessEventSelected = areAllSucessEventSelected && allSelectedRows[i].success + areAllSuccessEventSelected = areAllSuccessEventSelected && allSelectedRows[i].success areAllFailureEventSelected = areAllFailureEventSelected && allSelectedRows[i].failure + areAllConfigApprovalEventSelected = areAllConfigApprovalEventSelected && allSelectedRows[i].configApproval + areAllImageApprovalEventSelected = areAllImageApprovalEventSelected && allSelectedRows[i].imageApproval } this.setState({ - triggerCheckbox: { - isChecked: isAnyTriggerEventSelected, - value: areAllTriggerEventSelected ? 'CHECKED' : 'INTERMEDIATE', - }, - successCheckbox: { - isChecked: isAnySuccessEventSelected, - value: areAllSucessEventSelected ? 'CHECKED' : 'INTERMEDIATE', - }, - failureCheckbox: { - isChecked: isAnyFailureEventSelected, - value: areAllFailureEventSelected ? 'CHECKED' : 'INTERMEDIATE', + events: { + trigger: { + isChecked: isAnyTriggerEventSelected, + value: areAllTriggerEventSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, + }, + success: { + isChecked: isAnySuccessEventSelected, + value: areAllSuccessEventSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, + }, + failure: { + isChecked: isAnyFailureEventSelected, + value: areAllFailureEventSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, + }, + configApproval: { + isChecked: isAnyConfigApprovalEventSelected, + value: areAllConfigApprovalEventSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, + }, + imageApproval: { + isChecked: isAnyImageApprovalEventSelected, + value: areAllImageApprovalEventSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, + }, }, payloadUpdateEvents: allSelectedRows, }) } - triggerCheckboxHandler(): void { + onChangeCheckboxHandler = (e, value) => () => { + stopPropagation(e) const state = { ...this.state } - state.triggerCheckbox = { - isChecked: !state.triggerCheckbox.isChecked, - value: !state.triggerCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE', + state.events[value] = { + isChecked: !state.events[value].isChecked, + value: !state.events[value].isChecked ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE, } state.payloadUpdateEvents = state.payloadUpdateEvents.map((row) => { - if (state.triggerCheckbox.isChecked) { - row.eventTypeIds.push(1) + if (state.events[value].isChecked) { + row.eventTypeIds.push(EVENT_ID[value]) } else { - row.eventTypeIds = row.eventTypeIds.filter((id) => id !== 1) + row.eventTypeIds = row.eventTypeIds.filter((id) => id !== EVENT_ID[value]) } return row }) this.setState(state) } - successCheckboxHandler(): void { - const state = { ...this.state } - state.successCheckbox.isChecked = !state.successCheckbox.isChecked - state.successCheckbox.value = state.successCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' - state.payloadUpdateEvents = state.payloadUpdateEvents.map((row) => { - if (state.successCheckbox.isChecked) { - row.eventTypeIds.push(2) - } else { - row.eventTypeIds = row.eventTypeIds.filter((id) => id !== 2) - } - return row - }) - this.setState(state) - } - - failureCheckboxHandler(): void { - const state = { ...this.state } - state.failureCheckbox.isChecked = !state.failureCheckbox.isChecked - state.failureCheckbox.value = state.failureCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' - state.payloadUpdateEvents = state.payloadUpdateEvents.map((row) => { - if (state.failureCheckbox.isChecked) { - row.eventTypeIds.push(3) - } else { - row.eventTypeIds = row.eventTypeIds.filter((id) => id !== 3) - } - return row - }) - this.setState(state) - } - - updateNotificationEvents(event): void { + updateNotificationEvents = (): void => { this.setState({ view: ViewType.LOADING }) - const payload = this.state.payloadUpdateEvents.map((row) => { - return { - id: row.id, - eventTypeIds: row.eventTypeIds, - } - }) + const payload = this.state.payloadUpdateEvents.map((row) => ({ + id: row.id, + eventTypeIds: row.eventTypeIds, + })) updateNotificationEvents(payload) .then((response) => { if (response) { @@ -375,43 +378,21 @@ export class NotificationTab extends Component { ) } - CreateNewNotification = () => { - if (this.state.disableEdit) { - ToastManager.showToast({ - variant: ToastVariantType.notAuthorized, - description: TOAST_ACCESS_DENIED.SUBTITLE, - }) - } else { - this.props.history.push(URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_NOTIFICATIONS_ADD_NEW) - } - } - - renderGenericState() { - const renderGenericStateButton = () => { - return ( - - ) - } - return ( - - ) - } + renderAddNotificationButton = () => ( + + ) + renderGenericEmptyState = () => ( + + ) validateAccess = (updateState): void => { - if (this.state.disableEdit) { + if (this.props.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, description: TOAST_ACCESS_DENIED.SUBTITLE, @@ -425,14 +406,14 @@ export class NotificationTab extends Component { this.validateAccess({ showDeleteDialog: !this.state.showDeleteDialog, singleDeletedId: 0 }) } - applyModifyEvents = (event) => { - if (this.state.disableEdit) { + applyModifyEvents = () => { + if (this.props.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, description: TOAST_ACCESS_DENIED.SUBTITLE, }) } else { - this.updateNotificationEvents(event) + this.updateNotificationEvents() } } @@ -440,100 +421,8 @@ export class NotificationTab extends Component { this.validateAccess({ showModifyRecipientsModal: !this.state.showModifyRecipientsModal }) } - renderModifyEventPopUpBody = () => ( - -
    -
  • - Trigger - { - this.triggerCheckboxHandler() - }} - > - - -
  • -
  • - Success - { - e.stopPropagation() - this.successCheckboxHandler() - }} - > - - -
  • -
  • - Failure - { - this.failureCheckboxHandler() - }} - > - - -
  • -
-
- -
-
- ) - - renderOptions() { - if (this.state.headerCheckbox.isChecked) { - return ( -
- {/* NOTE: Need to replace all the icons with the new Button component all together */} - -
- -
-
- { - if (isOpen) { - this.onOpenEditNotficationMenu() - } - }} - > - - -
- -
-
-
- {this.renderModifyEventPopUpBody()} -
- -
- -
-
-
- ) - } - } - - onChangePipelineCheckbox(e) { - e.stopPropagation() + onChangePipelineCheckbox = (e) => { + stopPropagation(e) this.toggleAllNotification() } @@ -544,204 +433,236 @@ export class NotificationTab extends Component { }) } - renderPipelineList() { - return ( - - - - - - - - - - - - {this.state.notificationList.map((row) => { - const _isCi = row.branch && row.pipelineType === 'CI' - let _isWebhookCi - if (_isCi) { - try { - JSON.parse(row.branch) - _isWebhookCi = true - } catch (e) { - _isWebhookCi = false - } + onClickToggleNotification = (id) => (e) => { + stopPropagation(e) + this.toggleNotification(id) + this.setState({ selectedNotificationList: this.state.notificationList.filter((row) => row.isSelected) }) + } + + renderPipelineList = () => ( +
- - - - Pipeline NameApplication NameTypeEnv/BranchEventsRecipients -
+ + + + + + + + + + + + {this.state.notificationList.map((row) => { + const _isCi = row.branch && row.pipelineType === NotificationPipelineType.CI + let _isWebhookCi + if (_isCi) { + try { + JSON.parse(row.branch) + _isWebhookCi = true + } catch (e) { + _isWebhookCi = false } - return ( - - - + + - - - - + + + - - - - ) - })} - -
+ + + + + + Resource + Application NameEnv/BranchEventsRecipients +
- { - e.stopPropagation() - this.toggleNotification(row.id) - }} - > - - - + } + const isBaseConfig = + row.appliedFilters.environment?.length || + row.appliedFilters.application.length || + row.appliedFilters.project?.length || + row.appliedFilters.cluster?.length + return ( +
+ + + + +
+ {!isBaseConfig && renderPipelineTypeIcon(row)} {row.pipelineName ? row.pipelineName : ''} - {row.appliedFilters.environment?.length || - row.appliedFilters.application.length || - row.appliedFilters.project?.length || - row.appliedFilters.cluster?.length ? ( - <> - All current and future pipelines matching. -
- {row.appliedFilters.project.map((element) => { - return ( - - Project:{element.name} - - ) - })} - {row.appliedFilters.application.map((element) => { - return ( - - App:{element.name} - - ) - })} - {row.appliedFilters.environment.map((element) => { - return ( - - Env:{element.name} - - ) - })} - {row.appliedFilters.cluster.map((element) => { - return ( - - Cluster:{element.name} - - ) - })} -
{' '} - - ) : null} -
{row?.appName}{renderPipelineTypeIcon(row)} - {_isCi && ( - - - - )} - {row.pipelineType === 'CD' ? row?.environmentName : ''} - + + + {isBaseConfig ? ( +
+
+ {renderPipelineTypeIcon(row)} + + + {row.pipelineType === NotificationPipelineType.BASE + ? 'Base configuration matching:' + : `All existing and future ${row.pipelineType === NotificationPipelineType.CI ? 'build' : 'deployment'} pipelines matching:`} + +
+
+ {row.appliedFilters.project.map((element) => ( + + ))} + {row.appliedFilters.application.map((element) => ( + + ))} + {row.appliedFilters.environment.map((element) => ( + + ))} + {row.appliedFilters.cluster.map((element) => ( + + ))} +
+
+ ) : null} +
{row?.appName} + {_isCi && ( + + + + )} + {row.pipelineType === NotificationPipelineType.CD ? row?.environmentName : ''} + +
{row.trigger ? ( - -
- -
-
+ ) : ( - +
)} {row.success ? ( - -
- -
-
+ ) : ( - +
)} {row.failure ? ( - -
- -
-
+ ) : ( - +
+ )} + {row.configApproval ? ( + + ) : ( +
)} -
-
- {row.providers.map((p) => { - return ( -
- {p.dest === 'ses' ? : null} - {p.dest === 'slack' ? : null} - {p.dest === 'email' ? : null} - {p.dest === 'smtp' ? : null} - {p.dest === 'webhook' ? ( - - ) : null} - {p.recipient ? p.recipient : p.name} -
- ) - })} -
-
-
- ) - } - renderPagination() { + {row.imageApproval ? ( + + ) : ( +
+ )} +
+ + +
+ {row.providers.map((p) => ( + + ))} +
+ + +