From f24d072052469482119b541c0c7623e20f0145f1 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Thu, 22 Jan 2026 10:29:49 +0530 Subject: [PATCH 01/24] chore: notification code refactoring --- .../notifications/AddNotification.tsx | 2 +- .../notifications/ModifyRecipientsModal.tsx | 89 ++---- .../notifications/NotificationTab.tsx | 294 ++++++++++-------- .../notifications/notifications.scss | 4 - .../notifications/notifications.util.tsx | 17 +- src/components/notifications/types.tsx | 35 +++ src/css/base.scss | 4 + 7 files changed, 246 insertions(+), 199 deletions(-) diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index f14667d53c..45fb541cd1 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -880,7 +880,7 @@ export class AddNotification extends Component ( diff --git a/src/components/notifications/ModifyRecipientsModal.tsx b/src/components/notifications/ModifyRecipientsModal.tsx index d2a8212776..1d20dae88e 100644 --- a/src/components/notifications/ModifyRecipientsModal.tsx +++ b/src/components/notifications/ModifyRecipientsModal.tsx @@ -15,7 +15,18 @@ */ import { Component } from 'react' -import { showError, Progressing, VisibleModal, RadioGroup, RadioGroupItem, ToastVariantType, ToastManager } from '@devtron-labs/devtron-fe-common-lib' +import { + showError, + VisibleModal, + RadioGroup, + RadioGroupItem, + ToastVariantType, + ToastManager, + preventDefault, + Button, + ButtonVariantType, + ButtonStyleType, +} from '@devtron-labs/devtron-fe-common-lib' import CreatableSelect from 'react-select/creatable' import { ReactComponent as Close } from '../../assets/icons/ic-close.svg' import { ReactComponent as Slack } from '../../assets/icons/slack-logo.svg' @@ -25,40 +36,7 @@ import { ReactComponent as Webhook } from '../../assets/icons/ic-CIWebhook.svg' import { updateNotificationRecipients } from './notifications.service' import { multiSelectStyles, DropdownIndicator, MultiValueLabel, Option } from './notifications.util' import './notifications.scss' -import { EMAIL_AGENT } from './types' - -interface ModifyRecipientsModalProps { - channelList: SelectedRecipientType[] - onSaveSuccess: () => void - closeModifyRecipientsModal: () => void - notificationListFromParent: { - id: number - providers: { dest: string; configId: number; recipient: string; name?: string }[] - }[] -} - -interface RecipientType { - configId: number - recipient: string - dest: string - name?: string -} - -interface SelectedRecipientType { - __isNew__?: boolean - label: string - value: string - data: RecipientType -} - -interface ModifyRecipientsModalState { - isLoading: boolean - savedRecipients: RecipientType[] - selectedRecipient: SelectedRecipientType[] - showEmailAgents: boolean - selectedEmailAgent: string - recipientWithoutEmailAgent: boolean -} +import { EMAIL_AGENT, ModifyRecipientsModalProps, ModifyRecipientsModalState } from './types' export class ModifyRecipientsModal extends Component { constructor(props) { @@ -71,8 +49,6 @@ export class ModifyRecipientsModal extends Component { + preventDefault(e) if ( this.state.selectedRecipient.length > 0 && this.state.recipientWithoutEmailAgent && @@ -164,13 +140,13 @@ export class ModifyRecipientsModal extends Component { const state = { ...this.state } state.selectedEmailAgent = event.target.value this.setState(state) } - renderEmailAgentSelector() { + renderEmailAgentSelector = () => { if (this.state.selectedRecipient.length > 0 && this.state.recipientWithoutEmailAgent) { return (
@@ -285,26 +261,23 @@ export class ModifyRecipientsModal extends Component )}
-
{this.renderEmailAgentSelector()}
+
{this.renderEmailAgentSelector}
-
- - + variant={ButtonVariantType.primary} + disabled={this.state.isLoading} + />
) diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 50119745dc..7e8979c40f 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -36,6 +36,9 @@ import { ConfirmationModal, ConfirmationModalVariantType, SourceTypeMap, + Icon, + stopPropagation, + Chip, } from '@devtron-labs/devtron-fe-common-lib' import EmptyImage from '../../assets/img/ic-empty-notifications.png' import { @@ -45,19 +48,11 @@ import { getChannelsAndEmailsFilteredByEmail, } 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 { getRecipientChipStartIcon, renderPipelineTypeIcon } from './notifications.util' import { NotificationTabState } from './types' import { InValidHostUrlWarningBlock } from '@Components/common' @@ -100,10 +95,6 @@ export class NotificationTab extends Component { singleDeletedId: 0, disableEdit: false, } - 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,7 +109,7 @@ export class NotificationTab extends Component { }) } - getHostURLConfig() { + getHostURLConfig = () => { getHostURLConfiguration() .then((response) => { this.setState({ hostURLConfig: response.result }) @@ -126,7 +117,7 @@ export class NotificationTab extends Component { .catch((error) => {}) } - getAllNotifications() { + getAllNotifications = () => { getNotificationConfigurations(this.state.pagination.offset, this.state.pagination.pageSize) .then((response: any) => { this.setState({ @@ -149,7 +140,7 @@ export class NotificationTab extends Component { }) } - getChannels() { + getChannels = () => { getChannelsAndEmailsFilteredByEmail() .then((response) => { let list: any[] = response.result || [] @@ -167,7 +158,7 @@ export class NotificationTab extends Component { }) } - 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 +168,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 @@ -198,7 +189,7 @@ export class NotificationTab extends Component { 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' @@ -209,7 +200,7 @@ export class NotificationTab extends Component { this.setState(state) } - onOpenEditNotficationMenu(): void { + onOpenEditNotficationMenu = (): void => { const allSelectedRows = this.state.notificationList .filter((row) => row.isSelected) .map((row) => { @@ -263,7 +254,8 @@ export class NotificationTab extends Component { }) } - triggerCheckboxHandler(): void { + triggerCheckboxHandler = (e): void => { + stopPropagation(e) const state = { ...this.state } state.triggerCheckbox = { isChecked: !state.triggerCheckbox.isChecked, @@ -280,7 +272,8 @@ export class NotificationTab extends Component { this.setState(state) } - successCheckboxHandler(): void { + successCheckboxHandler = (e): void => { + stopPropagation(e) const state = { ...this.state } state.successCheckbox.isChecked = !state.successCheckbox.isChecked state.successCheckbox.value = state.successCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' @@ -295,7 +288,8 @@ export class NotificationTab extends Component { this.setState(state) } - failureCheckboxHandler(): void { + failureCheckboxHandler = (e): void => { + stopPropagation(e) const state = { ...this.state } state.failureCheckbox.isChecked = !state.failureCheckbox.isChecked state.failureCheckbox.value = state.failureCheckbox.isChecked ? 'CHECKED' : 'INTERMEDIATE' @@ -310,7 +304,7 @@ export class NotificationTab extends Component { this.setState(state) } - updateNotificationEvents(event): void { + updateNotificationEvents = (): void => { this.setState({ view: ViewType.LOADING }) const payload = this.state.payloadUpdateEvents.map((row) => { return { @@ -375,7 +369,7 @@ export class NotificationTab extends Component { ) } - CreateNewNotification = () => { + createNewNotification = () => { if (this.state.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, @@ -386,26 +380,27 @@ export class NotificationTab extends Component { } } - renderGenericState() { - const renderGenericStateButton = () => { - return ( - - ) - } + renderAddNotificationButton = () => { + return ( + + /> + - + ) - renderOptions = () => { + renderBulkOptions = () => { if (this.state.headerCheckbox.isChecked) { return (
@@ -629,6 +502,11 @@ export class NotificationTab extends Component { }) } + onClickToggleNotification = (id) => (e) => { + stopPropagation(e) + this.toggleNotification(id) + } + renderPipelineList = () => ( @@ -645,7 +523,7 @@ export class NotificationTab extends Component { - + @@ -676,11 +554,8 @@ export class NotificationTab extends Component { { - e.stopPropagation() - this.toggleNotification(row.id) - }} + value={row.isSelected ? CHECKBOX_VALUE.CHECKED : CHECKBOX_VALUE.INTERMEDIATE} + onChange={this.onClickToggleNotification(row.id)} > @@ -726,7 +601,7 @@ export class NotificationTab extends Component { ) : null} - + - - - - - - + <> + + + + + + + + + ) })} diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 5fcbe5d8f2..55ca8befe5 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -1,6 +1,13 @@ -import { Button, ButtonVariantType, Checkbox, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib' +import { + Button, + ButtonVariantType, + Checkbox, + ComponentSizeType, + Icon, + IconName, +} from '@devtron-labs/devtron-fe-common-lib' -import { EVENT_LABEL, EVENTS } from './constants' +import { EVENT_ICONS, EVENT_LABEL, EVENTS } from './constants' import { NotificationTabEvents } from './types' export const ModifyRecipientPopUp = ({ @@ -12,14 +19,22 @@ export const ModifyRecipientPopUp = ({ applyModifyEvents: () => void onChangeCheckboxHandler: (e, value) => () => void }) => { - const options = Object.values(EVENTS).map((value) => ({ label: EVENT_LABEL[value], value })) + const options = Object.values(EVENTS).map((value) => ({ + label: EVENT_LABEL[value], + value, + icon: EVENT_ICONS[value], + })) return (
    {options.map((option) => (
  • - {option.label} +
    + + {option.label} +
    + { row.appliedFilters.project?.length || row.appliedFilters.cluster?.length ? ( <> - All current and future pipelines matching. -
    + All existing and future pipelines matching: +
    {row.appliedFilters.project.map((element) => ( { )} {row.pipelineType === 'CD' ? row?.environmentName : ''} -
- {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 { @@ -702,6 +732,8 @@ export class AddNotification extends Component @@ -711,16 +743,21 @@ export class AddNotification extends Component { - this.togglePipelineCheckbox(rowIndex) + stopPropagation(e) + this.togglePipelineCheckbox(rowIndex, row.type) }} > diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 55ca8befe5..8962567b49 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -8,38 +8,60 @@ import { } from '@devtron-labs/devtron-fe-common-lib' import { EVENT_ICONS, EVENT_LABEL, EVENTS } from './constants' -import { NotificationTabEvents } from './types' +import { ModifyRecipientPopUpType, NotificationPipelineType } from './types' export const ModifyRecipientPopUp = ({ events, applyModifyEvents, onChangeCheckboxHandler, -}: { - events: NotificationTabEvents - applyModifyEvents: () => void - onChangeCheckboxHandler: (e, value) => () => void -}) => { + selectedNotificationList, +}: ModifyRecipientPopUpType) => { + const getDisabledLabel = (value) => { + if ( + selectedNotificationList.some( + (row) => + row.pipelineType === NotificationPipelineType.BASE && + value !== EVENTS.CONFIG_APPROVAL && + selectedNotificationList.length === 1, + ) + ) { + return true + } + if ( + selectedNotificationList.some( + (row) => + row.pipelineType === NotificationPipelineType.CI && + (value === EVENTS.CONFIG_APPROVAL || value === EVENTS.IMAGE_APPROVAL) && + selectedNotificationList.length === 1, + ) + ) { + return true + } + return false + } const options = Object.values(EVENTS).map((value) => ({ label: EVENT_LABEL[value], value, icon: EVENT_ICONS[value], + isDisabled: getDisabledLabel(value), })) return (
    {options.map((option) => ( -
  • -
    +
  • +
    {option.label}
    onChangeCheckboxHandler(e, option.value)()} + disabled={option.isDisabled} > diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 98e1c4fbca..6ca293ba6a 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -55,7 +55,7 @@ import { updateNotificationEvents, } from './notifications.service' import { getRecipientChipStartIcon, renderPipelineTypeIcon } from './notifications.util' -import { NotificationTabState } from './types' +import { NotificationPipelineType, NotificationTabState } from './types' import { ModifyRecipientPopUp } from './ModifyRecipientPopUp' import { EVENT_ID } from './constants' @@ -106,6 +106,7 @@ export class NotificationTab extends Component { confirmation: false, singleDeletedId: 0, disableEdit: false, + selectedNotificationList: [], } } @@ -210,6 +211,7 @@ export class NotificationTab extends Component { return config }) this.setState(state) + this.setState({ selectedNotificationList: state.notificationList.filter((row) => row.isSelected) }) } onOpenEditNotificationMenu = (): void => { @@ -441,6 +443,7 @@ export class NotificationTab extends Component { events={this.state.events} applyModifyEvents={this.applyModifyEvents} onChangeCheckboxHandler={this.onChangeCheckboxHandler} + selectedNotificationList={this.state.selectedNotificationList} /> ) @@ -505,6 +508,7 @@ export class NotificationTab extends Component { onClickToggleNotification = (id) => (e) => { stopPropagation(e) this.toggleNotification(id) + this.setState({ selectedNotificationList: this.state.notificationList.filter((row) => row.isSelected) }) } renderPipelineList = () => ( @@ -531,7 +535,7 @@ export class NotificationTab extends Component {
{this.state.notificationList.map((row) => { - const _isCi = row.branch && row.pipelineType === 'CI' + const _isCi = row.branch && row.pipelineType === NotificationPipelineType.CI let _isWebhookCi if (_isCi) { try { @@ -567,7 +571,7 @@ export class NotificationTab extends Component { row.appliedFilters.project?.length || row.appliedFilters.cluster?.length ? ( <> - All existing and future pipelines matching: + {row.pipelineType === NotificationPipelineType.BASE ? 'Base configuration matching:' : 'All existing and future deployment pipelines matching:'}
{row.appliedFilters.project.map((element) => ( { /> )} - {row.pipelineType === 'CD' ? row?.environmentName : ''} + {row.pipelineType === NotificationPipelineType.CD ? row?.environmentName : ''}
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 4e05d85761..2461d7a3f1 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -65,7 +65,7 @@ } .pipeline-list__pipeline-name { - width: 40%; + width: 30%; padding: 10px; } @@ -85,7 +85,7 @@ } .pipeline-list__stages { - width: 15%; + width: 188px; padding: 10px; } diff --git a/src/components/notifications/notifications.util.tsx b/src/components/notifications/notifications.util.tsx index 88261f1235..2e87a3e52d 100644 --- a/src/components/notifications/notifications.util.tsx +++ b/src/components/notifications/notifications.util.tsx @@ -163,7 +163,7 @@ export const renderPipelineTypeIcon = (row) => { return } if (row.pipelineType === NotificationPipelineType.BASE || row.type === NotificationPipelineType.BASE ) { - return + return } return } From 6633bee90015ada57c94b5f8368e9d6cc326de1d Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 15:05:32 +0530 Subject: [PATCH 09/24] feat: tooltip added in modify recipient popup for disabled options --- .../notifications/ModifyRecipientPopUp.tsx | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 8962567b49..0f3a2e8e0c 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -5,6 +5,7 @@ import { ComponentSizeType, Icon, IconName, + Tooltip, } from '@devtron-labs/devtron-fe-common-lib' import { EVENT_ICONS, EVENT_LABEL, EVENTS } from './constants' @@ -50,24 +51,35 @@ export const ModifyRecipientPopUp = ({
    {options.map((option) => ( -
  • -
    - - {option.label} -
    - - onChangeCheckboxHandler(e, option.value)()} - disabled={option.isDisabled} + +
  • - - -
  • +
    + + {option.label} +
    + + onChangeCheckboxHandler(e, option.value)()} + disabled={option.isDisabled} + > + + + + ))}
+
From 8ee8be4db9d6f55365d89cf26566e7364239ed34 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 16:14:22 +0530 Subject: [PATCH 11/24] chore: css fixes --- src/components/notifications/AddNotification.tsx | 4 ++-- src/components/notifications/NotificationTab.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index 375ae3248b..8f6602279a 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -694,7 +694,7 @@ export class AddNotification extends Component + @@ -736,7 +736,7 @@ export class AddNotification extends Component {isApprovalPipeline ? 'Base configuration matching:' - : 'All existing and future deployment pipelines matching:'} + : `All existing and future ${row.type === NotificationPipelineType.CI ? 'build' : 'deployment'} pipelines matching:`}
{row.appliedFilters.map((e) => { diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 6ca293ba6a..4abb073629 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -526,7 +526,7 @@ export class NotificationTab extends Component { -
+ From 4f373b963b272d14e900e637ed94acf815dcb1da Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 16:16:20 +0530 Subject: [PATCH 12/24] chore: position of tooltip fixed --- src/components/notifications/ModifyRecipientPopUp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 0f3a2e8e0c..6429653e17 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -53,7 +53,7 @@ export const ModifyRecipientPopUp = ({ {options.map((option) => ( From 20a8ee7dc9af8ab5ec5768172ea70c03eaf67e7b Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 16:24:36 +0530 Subject: [PATCH 13/24] chore: version bump --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 5be1b4f298..958065be84 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.22.0-alpha-12", + "@devtron-labs/devtron-fe-common-lib": "1.22.8-beta-1", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rjsf/core": "^5.13.3", "@rjsf/utils": "^5.13.3", diff --git a/yarn.lock b/yarn.lock index 01cc654f26..e4baa19db2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1729,9 +1729,9 @@ __metadata: languageName: node linkType: hard -"@devtron-labs/devtron-fe-common-lib@npm:1.22.0-alpha-12": - version: 1.22.0-alpha-12 - resolution: "@devtron-labs/devtron-fe-common-lib@npm:1.22.0-alpha-12" +"@devtron-labs/devtron-fe-common-lib@npm:1.22.8-beta-1": + version: 1.22.8-beta-1 + resolution: "@devtron-labs/devtron-fe-common-lib@npm:1.22.8-beta-1" dependencies: "@codemirror/autocomplete": "npm:6.18.6" "@codemirror/lang-json": "npm:6.0.1" @@ -1785,7 +1785,7 @@ __metadata: react-select: 5.8.0 rxjs: ^7.8.1 yaml: ^2.4.1 - checksum: 10c0/2f390de2adbc165cfc4b011ec8fa5e72213a3924903edbfc59a8ab4a9c264c3e1e835f1243b6ea162ced55dd0c1294b9c80a24a5f700fa0cc81f32d1eeae0308 + checksum: 10c0/278f9658e4d94d29e0424818161cf93b1fafdcf88e878352af4b5958143d5c0715f628356e5e92c55c36c24e220597f1c0a3a52df2228e29a8449531ae4afb24 languageName: node linkType: hard @@ -5599,7 +5599,7 @@ __metadata: version: 0.0.0-use.local resolution: "dashboard@workspace:." dependencies: - "@devtron-labs/devtron-fe-common-lib": "npm:1.22.0-alpha-12" + "@devtron-labs/devtron-fe-common-lib": "npm:1.22.8-beta-1" "@esbuild-plugins/node-globals-polyfill": "npm:0.2.3" "@playwright/test": "npm:^1.32.1" "@rjsf/core": "npm:^5.13.3" From 074faec4a667c32178eb826669551f68478d17b3 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 17:06:26 +0530 Subject: [PATCH 14/24] chore: recipient popup toggle code optimization --- .../notifications/ModifyRecipientPopUp.tsx | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 6429653e17..3ea61267cb 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -18,28 +18,19 @@ export const ModifyRecipientPopUp = ({ selectedNotificationList, }: ModifyRecipientPopUpType) => { const getDisabledLabel = (value) => { - if ( - selectedNotificationList.some( - (row) => - row.pipelineType === NotificationPipelineType.BASE && - value !== EVENTS.CONFIG_APPROVAL && - selectedNotificationList.length === 1, - ) - ) { - return true + // If BASE type is present among all, only CONFIG_APPROVAL should be enabled + if (selectedNotificationList.some((row) => row.pipelineType === NotificationPipelineType.BASE)) { + return value !== EVENTS.CONFIG_APPROVAL } - if ( - selectedNotificationList.some( - (row) => - row.pipelineType === NotificationPipelineType.CI && - (value === EVENTS.CONFIG_APPROVAL || value === EVENTS.IMAGE_APPROVAL) && - selectedNotificationList.length === 1, - ) - ) { - return true + + // If CI is available, disable CONFIG_APPROVAL and IMAGE_APPROVAL + if (selectedNotificationList.some((row) => row.pipelineType === NotificationPipelineType.CI)) { + return value === EVENTS.CONFIG_APPROVAL || value === EVENTS.IMAGE_APPROVAL } + return false } + const options = Object.values(EVENTS).map((value) => ({ label: EVENT_LABEL[value], value, From 88f9a00c80586b49ff5b8a2b985f1be3746418a8 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 17:21:05 +0530 Subject: [PATCH 15/24] chore: css fixes --- src/components/notifications/ModifyRecipientPopUp.tsx | 2 +- src/components/notifications/NotificationTab.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 3ea61267cb..8b46adeb57 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -43,7 +43,7 @@ export const ModifyRecipientPopUp = ({
    {options.map((option) => ( { ) } return ( -
    +
    {this.renderHostErrorMessage()} {this.renderBody()} {this.state.showDeleteDialog && this.renderDeleteDialog()} From e68c5e216a1362af9f02e8bea07b49432752af52 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Thu, 5 Feb 2026 15:18:49 +0530 Subject: [PATCH 16/24] chore: add notification position fix --- .../notifications/NotificationTab.tsx | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 4cb21582c3..42802662c9 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -571,8 +571,12 @@ export class NotificationTab extends Component { row.appliedFilters.project?.length || row.appliedFilters.cluster?.length ? ( <> - {row.pipelineType === NotificationPipelineType.BASE ? 'Base configuration matching:' : 'All existing and future deployment pipelines matching:'} -
    + + {row.pipelineType === NotificationPipelineType.BASE + ? 'Base configuration matching:' + : 'All existing and future deployment pipelines matching:'} + +
    {row.appliedFilters.project.map((element) => ( { renderBody = () => (
    -
    +
    + {this.renderBulkOptions()} + {this.renderPipelineList()} + {this.renderPagination()} +
    ) From 0375d37bcfd626dddd3da669533b631aacbcb60b Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 6 Feb 2026 12:30:28 +0530 Subject: [PATCH 17/24] chore: renderEmailAgentSelector ui fix --- src/components/notifications/ModifyRecipientsModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/notifications/ModifyRecipientsModal.tsx b/src/components/notifications/ModifyRecipientsModal.tsx index 1d20dae88e..0d236bafd8 100644 --- a/src/components/notifications/ModifyRecipientsModal.tsx +++ b/src/components/notifications/ModifyRecipientsModal.tsx @@ -261,7 +261,7 @@ export class ModifyRecipientsModal extends Component )}
    -
    {this.renderEmailAgentSelector}
    + {this.renderEmailAgentSelector()}
- @@ -731,6 +736,7 @@ export class AddNotification extends Component -
Pipeline NameApplication NameApplication Name Type Env/Branch Events{row?.appName}{row?.appName} {renderPipelineTypeIcon(row)} {_isCi && ( @@ -862,7 +737,7 @@ export class NotificationTab extends Component { dataTestId="delete-notification-button" startIcon={} /> - {this.renderOptions()} + {this.renderBulkOptions()} {this.renderPipelineList()} {this.renderPagination()} diff --git a/src/components/notifications/notifications.service.ts b/src/components/notifications/notifications.service.ts index 7964bc9490..78dc0dfb2a 100644 --- a/src/components/notifications/notifications.service.ts +++ b/src/components/notifications/notifications.service.ts @@ -93,6 +93,12 @@ function createSaveNotificationPayload(selectedPipelines, providers): SaveNotifi if (config.failure) { eventTypeIds.push(3) } + if (config.configApproval) { + eventTypeIds.push(4) + } + if (config.imageApproval) { + eventTypeIds.push(7) + } const teamId = config.appliedFilters .filter((filter) => filter.type === FilterOptions.PROJECT) @@ -233,6 +239,8 @@ export function getNotificationConfigurations(offset: number, pageSize: number): trigger: config.eventTypes.includes(1), success: config.eventTypes.includes(2), failure: config.eventTypes.includes(3), + configApproval: config.eventTypes.includes(4) || config.eventTypes.includes(5), + imageApproval: config.eventTypes.includes(7), isSelected: false, providers, appliedFilters: { From 191733b412fab08903c76c99261c9ccc4f931d30 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 27 Jan 2026 12:21:00 +0530 Subject: [PATCH 05/24] fix: css fixes in notification tab --- .../notifications/AddNotification.tsx | 2 +- .../notifications/ModifyRecipientPopUp.tsx | 19 +++++++++++-------- .../notifications/NotificationTab.tsx | 2 +- .../notifications/notifications.scss | 2 +- src/css/base.scss | 6 ------ 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index 5d9f1a2ea2..e5ea7c6dda 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -733,7 +733,7 @@ export class AddNotification extends Component ) })} - {' '} + ) : ( row.pipelineName diff --git a/src/components/notifications/ModifyRecipientPopUp.tsx b/src/components/notifications/ModifyRecipientPopUp.tsx index 93d3f9d1fc..5fcbe5d8f2 100644 --- a/src/components/notifications/ModifyRecipientPopUp.tsx +++ b/src/components/notifications/ModifyRecipientPopUp.tsx @@ -24,20 +24,23 @@ export const ModifyRecipientPopUp = ({ rootClassName="" isChecked={events[option.value].isChecked} value={events[option.value].value} - onChange={(e) => onChangeCheckboxHandler(e, option.value)} + onChange={(e) => onChangeCheckboxHandler(e, option.value)()} > ))} - - { - 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 : ''} - - {Object.values(EVENTS).map((event) => { - return ( -
+ { + 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 : ''} + + {Object.values(EVENTS) + .filter((event) => row.type !== 'CI' || (event !== 'configApproval' && event !== 'imageApproval')) + .map((event) => { + return ( +
- {row.trigger ? ( - - ) : ( - - )} - {row.success ? ( - - ) : ( - - )} - {row.failure ? ( - - ) : ( - - )} - {row.configApproval ? ( - - ) : ( - - )} - - {row.imageApproval ? ( - - ) : ( - - )} + +
+ {row.trigger ? ( + + ) : ( +
+ )} + {row.success ? ( + + ) : ( +
+ )} + {row.failure ? ( + + ) : ( +
+ )} + {row.configApproval ? ( + + ) : ( +
+ )} + + {row.imageApproval ? ( + + ) : ( +
+ )} +
@@ -692,7 +694,7 @@ export class NotificationTab extends Component { ))}
+
- {row.appliedFilters.length ? ( + {row.appliedFilters.length ? ( <> - All current and future pipelines matching. + + {isApprovalPipeline + ? 'Base configuration matching:' + : 'All existing and future deployment pipelines matching:'} +
{row.appliedFilters.map((e) => { return ( @@ -749,39 +786,49 @@ export class AddNotification extends Component )} - {row.type === 'CD' ? row?.environmentName : ''} + {row.type === NotificationPipelineType.CD ? row?.environmentName : ''}
{Object.values(EVENTS) - .filter((event) => row.type !== 'CI' || (event !== 'configApproval' && event !== 'imageApproval')) + .filter((event) => { + if (isApprovalPipeline) { + return event === EVENTS.CONFIG_APPROVAL + } + return ( + row.type !== NotificationPipelineType.CI || + (event !== EVENTS.CONFIG_APPROVAL && event !== EVENTS.IMAGE_APPROVAL) + ) + }) .map((event) => { - return ( -
diff --git a/src/components/notifications/constants.ts b/src/components/notifications/constants.ts index db2400ebf3..dce5ae3fc1 100644 --- a/src/components/notifications/constants.ts +++ b/src/components/notifications/constants.ts @@ -196,8 +196,8 @@ export const EVENT_LABEL = { [EVENTS.TRIGGER]: 'Trigger', [EVENTS.SUCCESS]: 'Success', [EVENTS.FAILURE]: 'Failure', - [EVENTS.CONFIG_APPROVAL]: 'Config approval', - [EVENTS.IMAGE_APPROVAL]: 'Image approval', + [EVENTS.CONFIG_APPROVAL]: 'Config change approval', + [EVENTS.IMAGE_APPROVAL]: 'Deployment approval', } export const EVENT_ID = { diff --git a/src/components/notifications/notifications.service.ts b/src/components/notifications/notifications.service.ts index 78dc0dfb2a..ca7faf474d 100644 --- a/src/components/notifications/notifications.service.ts +++ b/src/components/notifications/notifications.service.ts @@ -16,7 +16,7 @@ import { get, post, trash, put, ResponseType, sortCallback, CHECKBOX_VALUE } from '@devtron-labs/devtron-fe-common-lib' import { Routes } from '../../config/constants' -import { FilterOptions, NotificationConfiguration, PipelineType, SMTPConfigResponseType, WebhookAttributesResponseType } from './types' +import { FilterOptions, NotificationConfiguration, NotificationPipelineType, PipelineType, SMTPConfigResponseType, WebhookAttributesResponseType } from './types' interface UpdateNotificationEvent { id: number @@ -29,7 +29,7 @@ interface SaveNotificationPayload { appId: number[] envId: number[] pipelineId: number - pipelineType: 'CI' | 'CD' + pipelineType: NotificationPipelineType eventTypeIds: number[] }[] providers: { configId: number; dest: 'ses' | 'slack' | ''; recipient: string }[] diff --git a/src/components/notifications/notifications.util.tsx b/src/components/notifications/notifications.util.tsx index a7a7ee7a6f..88261f1235 100644 --- a/src/components/notifications/notifications.util.tsx +++ b/src/components/notifications/notifications.util.tsx @@ -35,7 +35,7 @@ import { } from '@devtron-labs/devtron-fe-common-lib' import { ConfigurationFieldKeys, ConfigurationsTabTypes, ConfigurationTabText } from './constants' import { validateEmail } from '../common' -import { FormError, SESFormType, SMTPFormType, WebhookDataRowType, WebhookHeaderKeyType } from './types' +import { FormError, NotificationPipelineType, SESFormType, SMTPFormType, WebhookDataRowType, WebhookHeaderKeyType } from './types' import { REQUIRED_FIELD_MSG } from '@Config/constantMessaging' export const multiSelectStyles = { @@ -162,6 +162,9 @@ export const renderPipelineTypeIcon = (row) => { if (row.pipelineType === 'CI' || row.type === 'CI') { return } + if (row.pipelineType === NotificationPipelineType.BASE || row.type === NotificationPipelineType.BASE ) { + return + } return } diff --git a/src/components/notifications/types.tsx b/src/components/notifications/types.tsx index 111a047938..0b12c8045b 100644 --- a/src/components/notifications/types.tsx +++ b/src/components/notifications/types.tsx @@ -267,7 +267,7 @@ export interface NotificationConfiguration extends NotificationEventsType { pipelineId?: number appName: string pipelineName?: string - pipelineType: 'CI' | 'CD' + pipelineType: NotificationPipelineType environmentName?: string branch?: string isSelected: boolean @@ -314,6 +314,7 @@ export interface NotificationTabState { confirmation: boolean singleDeletedId: number disableEdit: boolean + selectedNotificationList: NotificationConfiguration[] } export interface BaseConfigurationTableRowType { @@ -388,12 +389,18 @@ interface Options { project: BaseOptionsType[] cluster: BaseOptionsType[] } + +export enum NotificationPipelineType { + CI = 'CI', + CD = 'CD', + BASE = 'BASE', +} export interface PipelineType extends NotificationEventsType { checkbox: { isChecked: boolean value: CHECKBOX_VALUE } - type: 'CI' | 'CD' | 'configApproval' + type: NotificationPipelineType pipelineId: number pipelineName: string environmentName?: string @@ -437,3 +444,9 @@ export interface AddNotificationState { selectedEmailAgent: string showWebhookConfigModal: boolean } + +export interface ModifyRecipientPopUpType extends Pick { + events: NotificationTabEvents + applyModifyEvents: () => void + onChangeCheckboxHandler: (e, value) => () => void +} From 802d9650fb6b875898348c487dda316c12d8270b Mon Sep 17 00:00:00 2001 From: shivani170 Date: Fri, 30 Jan 2026 13:31:38 +0530 Subject: [PATCH 08/24] chore: add notification fix for icon positioning of config approval --- .../notifications/AddNotification.tsx | 109 ++++++++++++------ .../notifications/notifications.scss | 4 +- .../notifications/notifications.util.tsx | 2 +- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index d7c832f6c8..0349dadfab 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -789,46 +789,79 @@ export class AddNotification extends Component
- {Object.values(EVENTS) - .filter((event) => { - if (isApprovalPipeline) { - return event === EVENTS.CONFIG_APPROVAL + {isApprovalPipeline + ? Object.values(EVENTS).map((event) => { + if (event === EVENTS.CONFIG_APPROVAL) { + return ( +
- {isApprovalPipeline + + {isApprovalPipeline ? Object.values(EVENTS).map((event) => { - if (event === EVENTS.CONFIG_APPROVAL) { - return ( -
- Pipeline NameResource Application Name Type Env/BranchPipeline NameResource Application Name Type Env/Branch -
+
{row.providers.map((p) => ( { if (r.configId) { return { configId: r.configId, dest: r.dest === 'slack' || r.dest === 'webhook' ? r.dest : emailChannel, - recipient: '', + recipient: r.recipient, } } return { From d4415e322fdd9e9431585a86b3ef970b3dcc3da0 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Mon, 16 Feb 2026 18:21:28 +0530 Subject: [PATCH 19/24] feat: notification ui fixes --- .../notifications/AddNotification.tsx | 17 +- .../notifications/BulkMultiSelectWidget.tsx | 96 +++++++++++ .../notifications/NotificationTab.tsx | 152 +++++++----------- .../notifications/Notifications.tsx | 79 +++++++-- .../notifications/notifications.scss | 20 ++- .../notifications/notifications.util.tsx | 4 +- src/components/notifications/types.tsx | 21 ++- 7 files changed, 266 insertions(+), 123 deletions(-) create mode 100644 src/components/notifications/BulkMultiSelectWidget.tsx diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index 8f6602279a..363fcd92a5 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -278,11 +278,17 @@ export class AddNotification extends Component
Resource Application NameType Env/Branch Events
+ {renderPipelineTypeIcon(row, 20)} {row.appliedFilters.length ? ( <> @@ -753,7 +759,6 @@ export class AddNotification extends Component {row?.appName}{renderPipelineTypeIcon(row)} {_isCi && ( diff --git a/src/components/notifications/BulkMultiSelectWidget.tsx b/src/components/notifications/BulkMultiSelectWidget.tsx new file mode 100644 index 0000000000..3d4b524ff8 --- /dev/null +++ b/src/components/notifications/BulkMultiSelectWidget.tsx @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024. Devtron Inc. + */ + +import { + Button, + ButtonStyleType, + ButtonVariantType, + DraggableButton, + DraggablePositionVariant, + DraggableWrapper, + Icon, + PopupMenu, +} from '@devtron-labs/devtron-fe-common-lib' + +import { ModifyRecipientPopUp } from './ModifyRecipientPopUp' +import { BulkMultiSelectTagWidgetType } from './types' + +export const BulkMultiSelectTagWidget = ({ + parentRef, + selectedIdentifiersCount, + showDeleteModal, + events, + applyModifyEvents, + onChangeCheckboxHandler, + selectedNotificationList, + onOpenEditNotificationMenu, + showModifyModal, +}: BulkMultiSelectTagWidgetType) => { + const renderModifyEventPopUpBody = () => ( + + + + ) + return ( + +
+ +
+ {selectedIdentifiersCount} + Selected +
+
+
+
+
+
+ + ) +} diff --git a/src/components/notifications/NotificationTab.tsx b/src/components/notifications/NotificationTab.tsx index 42802662c9..ad042090e3 100644 --- a/src/components/notifications/NotificationTab.tsx +++ b/src/components/notifications/NotificationTab.tsx @@ -58,8 +58,12 @@ import { getRecipientChipStartIcon, renderPipelineTypeIcon } from './notificatio import { NotificationPipelineType, NotificationTabState } from './types' import { ModifyRecipientPopUp } from './ModifyRecipientPopUp' import { EVENT_ID } from './constants' +import { BulkMultiSelectTagWidget } from './BulkMultiSelectWidget' +import React from 'react' export class NotificationTab extends Component { + bulkMultiSelectWidgetRef = React.createRef() + constructor(props) { super(props) this.state = { @@ -105,7 +109,6 @@ export class NotificationTab extends Component { deleting: false, confirmation: false, singleDeletedId: 0, - disableEdit: false, selectedNotificationList: [], } } @@ -164,8 +167,8 @@ export class NotificationTab extends Component { })) this.setState({ channelList: list }) }) - .catch((error) => { - this.setState({ disableEdit: true }) + .catch(() => { + this.props.toggleDisableEdit(true) }) } @@ -376,7 +379,7 @@ export class NotificationTab extends Component { } createNewNotification = () => { - if (this.state.disableEdit) { + if (this.props.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, description: TOAST_ACCESS_DENIED.SUBTITLE, @@ -408,7 +411,7 @@ export class NotificationTab extends Component { ) validateAccess = (updateState): void => { - if (this.state.disableEdit) { + if (this.props.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, description: TOAST_ACCESS_DENIED.SUBTITLE, @@ -423,7 +426,7 @@ export class NotificationTab extends Component { } applyModifyEvents = () => { - if (this.state.disableEdit) { + if (this.props.disableEdit) { ToastManager.showToast({ variant: ToastVariantType.notAuthorized, description: TOAST_ACCESS_DENIED.SUBTITLE, @@ -437,62 +440,6 @@ export class NotificationTab extends Component { this.validateAccess({ showModifyRecipientsModal: !this.state.showModifyRecipientsModal }) } - renderModifyEventPopUpBody = () => ( - - - - ) - - renderBulkOptions = () => { - if (this.state.headerCheckbox.isChecked) { - return ( -
-
- ) - } - } - onChangePipelineCheckbox = (e) => { stopPropagation(e) this.toggleAllNotification() @@ -512,12 +459,12 @@ export class NotificationTab extends Component { } renderPipelineList = () => ( - - +
+ - - + - + + {this.state.notificationList.map((row) => { const _isCi = row.branch && row.pipelineType === NotificationPipelineType.CI let _isWebhookCi @@ -545,6 +496,11 @@ export class NotificationTab extends Component { _isWebhookCi = false } } + const isBaseConfig = + row.appliedFilters.environment?.length || + row.appliedFilters.application.length || + row.appliedFilters.project?.length || + row.appliedFilters.cluster?.length return ( { - -
+ { Resource + + Resource + Application NameType Env/Branch Events Recipients
- {row.pipelineName ? row.pipelineName : ''} - {row.appliedFilters.environment?.length || - row.appliedFilters.application.length || - row.appliedFilters.project?.length || - row.appliedFilters.cluster?.length ? ( - <> - - {row.pipelineType === NotificationPipelineType.BASE - ? 'Base configuration matching:' - : 'All existing and future deployment pipelines matching:'} - + +
+ {!isBaseConfig && renderPipelineTypeIcon(row)} + {row.pipelineName ? row.pipelineName : ''} +
+ + {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) => ( { /> ))}
- +
) : null}
{row?.appName}{renderPipelineTypeIcon(row)} {_isCi && ( @@ -691,7 +651,7 @@ export class NotificationTab extends Component { -
+
{row.providers.map((p) => ( { renderBody = () => (
-
-
- {this.renderBulkOptions()} {this.renderPipelineList()} {this.renderPagination()}
@@ -800,11 +749,24 @@ export class NotificationTab extends Component { ) } return ( -
+
{this.renderHostErrorMessage()} {this.renderBody()} {this.state.showDeleteDialog && this.renderDeleteDialog()} {this.renderModifyRecipients()} + {this.state.headerCheckbox.isChecked && ( + row.isSelected).length} + showDeleteModal={this.showDeleteModal} + events={this.state.events} + applyModifyEvents={this.applyModifyEvents} + onChangeCheckboxHandler={this.onChangeCheckboxHandler} + selectedNotificationList={this.state.selectedNotificationList} + onOpenEditNotificationMenu={this.onOpenEditNotificationMenu} + showModifyModal={this.showModifyModal} + /> + )}
) } diff --git a/src/components/notifications/Notifications.tsx b/src/components/notifications/Notifications.tsx index d97c63938f..ac020bc373 100644 --- a/src/components/notifications/Notifications.tsx +++ b/src/components/notifications/Notifications.tsx @@ -16,29 +16,72 @@ import { Component } from 'react' import { Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom' -import { DOCUMENTATION, ErrorScreenNotAuthorized, FeatureTitleWithInfo, TabGroup } from '@devtron-labs/devtron-fe-common-lib' +import { + Button, + ButtonVariantType, + ComponentSizeType, + ErrorScreenNotAuthorized, + FeatureTitleWithInfo, + Icon, + TabGroup, + TOAST_ACCESS_DENIED, + ToastManager, + ToastVariantType, +} from '@devtron-labs/devtron-fe-common-lib' import { ConfigurationTab } from './ConfigurationTab' import { NotificationTab } from './NotificationTab' import { ErrorBoundary } from '../common' -import { HEADER_TEXT } from '../../config' +import { HEADER_TEXT, URLS } from '../../config' import './notifications.scss' +import { NotificationsProps, NotificationsState } from './types' -interface NotificationsProps extends RouteComponentProps<{}> { - isSuperAdmin: boolean -} +export default class Notifications extends Component { + + constructor(props) { + super(props) + this.state = { + disableEdit: false, + } + } + + 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) + } + } + + toggleDisableEdit = (disableEdit: boolean) => { + this.setState({ disableEdit }) + } -export default class Notifications extends Component { renderNotificationHeader() { return (
- HEADER_TEXT.NOTIFICATIONS.description} - docLink="GLOBAL_CONFIG_NOTIFICATION" - showInfoIconTippy - dataTestId="notifications-feature-title" - /> +
+ HEADER_TEXT.NOTIFICATIONS.description} + docLink="GLOBAL_CONFIG_NOTIFICATION" + showInfoIconTippy + dataTestId="notifications-feature-title" + /> +
+
+
{
- + ( + + )} + /> diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 2461d7a3f1..d788cf983d 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -54,14 +54,24 @@ color: var(--N500); text-transform: capitalize; display: table-row; + + th { + padding: 10px; + vertical-align: left; + } +} + +thead { + position: sticky; + top: 0; + z-index: 2; box-shadow: inset 0 -1px 0 0 var(--N200); - padding: 10px 0 16px 0; + background-color: var(--bg-primary); } .pipeline-list__checkbox { width: 24px; padding: 10px; - padding-top: 15px; } .pipeline-list__pipeline-name { @@ -125,8 +135,8 @@ } -.configuration-drawer{ - .webhook-config-modal{ +.configuration-drawer { + .webhook-config-modal { display: grid; grid-template-columns: 1fr 280px; } @@ -331,4 +341,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/components/notifications/notifications.util.tsx b/src/components/notifications/notifications.util.tsx index 2e87a3e52d..06e8ff4c0a 100644 --- a/src/components/notifications/notifications.util.tsx +++ b/src/components/notifications/notifications.util.tsx @@ -155,7 +155,7 @@ export const Option = (props) => { ) } -export const renderPipelineTypeIcon = (row) => { +export const renderPipelineTypeIcon = (row, size = 24 as IconBaseSizeType ) => { if (row.isVirtualEnvironment) { return } @@ -163,7 +163,7 @@ export const renderPipelineTypeIcon = (row) => { return } if (row.pipelineType === NotificationPipelineType.BASE || row.type === NotificationPipelineType.BASE ) { - return + return } return } diff --git a/src/components/notifications/types.tsx b/src/components/notifications/types.tsx index 0b12c8045b..48795e04af 100644 --- a/src/components/notifications/types.tsx +++ b/src/components/notifications/types.tsx @@ -313,7 +313,6 @@ export interface NotificationTabState { deleting: boolean confirmation: boolean singleDeletedId: number - disableEdit: boolean selectedNotificationList: NotificationConfiguration[] } @@ -450,3 +449,23 @@ export interface ModifyRecipientPopUpType extends Pick void onChangeCheckboxHandler: (e, value) => () => void } + +export interface NotificationsProps extends RouteComponentProps<{}> { + isSuperAdmin: boolean +} + +export interface NotificationsState { + disableEdit: boolean +} + +export interface BulkMultiSelectTagWidgetType { + parentRef: React.RefObject + selectedIdentifiersCount: number + showDeleteModal: () => void + events: NotificationTabEvents + applyModifyEvents: () => void + onChangeCheckboxHandler: (e, value) => () => void + selectedNotificationList: NotificationConfiguration[] + onOpenEditNotificationMenu: () => void + showModifyModal: () => void +} From 493b48403c23afa55e7f30968a448f226b9c680b Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 17 Feb 2026 13:06:07 +0530 Subject: [PATCH 20/24] fix: css fixes --- .../notifications/AddNotification.tsx | 34 ++++++++++--------- .../notifications/BulkMultiSelectWidget.tsx | 22 ++++++------ .../notifications/Notifications.tsx | 2 +- .../notifications/notifications.util.tsx | 4 +-- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/components/notifications/AddNotification.tsx b/src/components/notifications/AddNotification.tsx index 363fcd92a5..39cb0d7537 100644 --- a/src/components/notifications/AddNotification.tsx +++ b/src/components/notifications/AddNotification.tsx @@ -42,6 +42,7 @@ import { IconsProps, ButtonComponentType, stopPropagation, + BreadCrumb, } from '@devtron-labs/devtron-fe-common-lib' import { components } from 'react-select' import CreatableSelect from 'react-select/creatable' @@ -736,7 +737,7 @@ export class AddNotification extends Component
- {renderPipelineTypeIcon(row, 20)} + {renderPipelineTypeIcon(row, 16)} {row.appliedFilters.length ? ( <> @@ -1063,28 +1064,29 @@ export class AddNotification extends Component { + const breadcrumbs = [ + { + name: 'Notifications', + to: URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_NOTIFICATIONS, + }, + { + name: 'Add Notification', + to: '', + }, + ] + return + } + render() { return (
-
{this.renderAddCard()} {this.renderShowSlackConfigModal()} diff --git a/src/components/notifications/BulkMultiSelectWidget.tsx b/src/components/notifications/BulkMultiSelectWidget.tsx index 3d4b524ff8..d388c07298 100644 --- a/src/components/notifications/BulkMultiSelectWidget.tsx +++ b/src/components/notifications/BulkMultiSelectWidget.tsx @@ -51,17 +51,7 @@ export const BulkMultiSelectTagWidget = ({ Selected
-
-
diff --git a/src/components/notifications/Notifications.tsx b/src/components/notifications/Notifications.tsx index ac020bc373..dcc0473ac5 100644 --- a/src/components/notifications/Notifications.tsx +++ b/src/components/notifications/Notifications.tsx @@ -74,7 +74,7 @@ export default class Notifications extends Component