diff --git a/src/components/notifications/ConfigTableRowActionButton.tsx b/src/components/notifications/ConfigTableRowActionButton.tsx index fb087179d3..447c67f9a7 100644 --- a/src/components/notifications/ConfigTableRowActionButton.tsx +++ b/src/components/notifications/ConfigTableRowActionButton.tsx @@ -14,11 +14,18 @@ * limitations under the License. */ -import { Button, ButtonStyleType, ButtonVariantType, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib' +import { useHistory } from 'react-router-dom' -import { ReactComponent as Edit } from '@Icons/ic-pencil.svg' -import { Trash } from '@Components/common' +import { + Button, + ButtonStyleType, + ButtonVariantType, + ComponentSizeType, + Icon, + useSearchString, +} from '@devtron-labs/devtron-fe-common-lib' +import { ConfigurationsTabTypes } from './constants' import { ConfigTableRowActionButtonProps } from './types' export const ConfigTableRowActionButton = ({ @@ -33,7 +40,7 @@ export const ConfigTableRowActionButton = ({ variant={ButtonVariantType.borderLess} size={ComponentSizeType.xs} dataTestId={`${modal}-config-edit-button`} - icon={} + icon={} ariaLabel="Edit" style={ButtonStyleType.neutral} /> @@ -42,10 +49,42 @@ export const ConfigTableRowActionButton = ({ variant={ButtonVariantType.borderLess} size={ComponentSizeType.xs} dataTestId={`${modal}-config-delete-button`} - icon={} + icon={} ariaLabel="Delete" style={ButtonStyleType.negativeGrey} /> ) + +export const ConfigurationRowActionButtonWrapper = ({ + row, + deleteClickHandler, + modal, +}: { + row: any + deleteClickHandler: (id: number, modal: ConfigurationsTabTypes) => () => void + modal: ConfigurationsTabTypes +}) => { + const { searchParams } = useSearchString() + const history = useHistory() + + const onClickEditRow = () => () => { + const newParams = { + ...searchParams, + configId: row.id, + modal, + } + history.push({ + search: new URLSearchParams(newParams).toString(), + }) + } + + return ( + + ) +} diff --git a/src/components/notifications/ConfigurationTables.tsx b/src/components/notifications/ConfigurationTables.tsx index c31905834d..30286c659b 100644 --- a/src/components/notifications/ConfigurationTables.tsx +++ b/src/components/notifications/ConfigurationTables.tsx @@ -18,8 +18,6 @@ import { Route, Switch, useRouteMatch } from 'react-router-dom' import { showError } from '@devtron-labs/devtron-fe-common-lib' -import { DeleteComponentsName } from '@Config/constantMessaging' - import { ConfigurationsTabTypes } from './constants' import { getSESConfiguration, @@ -77,7 +75,7 @@ export const ConfigurationTables = ({ activeTab, state, setState }: Configuratio ...state, webhookConfig: { ...result, - channel: DeleteComponentsName.WebhookConfigurationTab, + channel: ConfigurationsTabTypes.WEBHOOK, }, confirmation: true, activeTab: ConfigurationsTabTypes.WEBHOOK, diff --git a/src/components/notifications/SESConfigurationTable.tsx b/src/components/notifications/SESConfigurationTable.tsx index 0fc2bc6a66..e26b221d20 100644 --- a/src/components/notifications/SESConfigurationTable.tsx +++ b/src/components/notifications/SESConfigurationTable.tsx @@ -14,17 +14,21 @@ * limitations under the License. */ +import { useMemo } from 'react' import { useHistory } from 'react-router-dom' -import { useSearchString } from '@devtron-labs/devtron-fe-common-lib' +import { + FiltersTypeEnum, + InteractiveCellText, + PaginationEnum, + Table, + useSearchString, +} from '@devtron-labs/devtron-fe-common-lib' -import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText/InteractiveCellText' -import { DeleteComponentsName } from '@Config/constantMessaging' - -import { ConfigTableRowActionButton } from './ConfigTableRowActionButton' -import { ConfigurationsTabTypes } from './constants' -import { getConfigTabIcons, renderDefaultTag } from './notifications.util' -import { ConfigurationTableProps } from './types' +import { ConfigurationRowActionButtonWrapper } from './ConfigTableRowActionButton' +import { BASE_CONFIG, ConfigurationsTabTypes, SES_TABLE_COLUMNS } from './constants' +import { renderDefaultTag } from './notifications.util' +import { ConfigurationTableProps, SESConfigurationTableRowType } from './types' import './notifications.scss' @@ -32,7 +36,7 @@ const SESConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTable const { searchParams } = useSearchString() const history = useHistory() - const onClickSESConfigEdit = (id: number) => () => { + const onClickEditRow = (id: number) => () => { const newParams = { ...searchParams, configId: id.toString(), @@ -43,43 +47,56 @@ const SESConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTable }) } - return ( -
-
-

-

Name

-

Access Key Id

-

Sender's Email

-

-

-
- {state.sesConfigurationList.map((sesConfig) => ( -
- {getConfigTabIcons(ConfigurationsTabTypes.SES)} -
- + const tableRows = useMemo( + () => + state.sesConfigurationList.map((sesConfig) => ({ + id: `${sesConfig.id}`, + data: { + name: ( +
+ {renderDefaultTag(sesConfig.isDefault)}
- - - -
- ))} -
-
+ ), + accessKeyId: sesConfig.accessKeyId, + email: sesConfig.email, + }, + })), + [state.sesConfigurationList], + ) + + const onRowClick = (rowData) => { + onClickEditRow(Number(rowData.id))() + } + + return ( + + id="table__ses-configuration" + columns={SES_TABLE_COLUMNS} + rows={tableRows} + emptyStateConfig={{ + noRowsConfig: { + title: 'No SES Configurations Found', + }, + }} + filtersVariant={FiltersTypeEnum.STATE} + additionalFilterProps={{ + initialSortKey: BASE_CONFIG[0].field, + }} + paginationVariant={PaginationEnum.NOT_PAGINATED} + filter={null} + rowStartIconConfig={{ + name: 'ic-ses', + color: null, + size: 24, + }} + rowActionOnHoverConfig={{ + width: 100, + Component: ConfigurationRowActionButtonWrapper, + }} + additionalProps={{ deleteClickHandler, modal: ConfigurationsTabTypes.SES }} + onRowClick={onRowClick} + /> ) } diff --git a/src/components/notifications/SMTPConfigurationTable.tsx b/src/components/notifications/SMTPConfigurationTable.tsx index d07fe05789..525d1a0c49 100644 --- a/src/components/notifications/SMTPConfigurationTable.tsx +++ b/src/components/notifications/SMTPConfigurationTable.tsx @@ -14,27 +14,27 @@ * limitations under the License. */ +import { useMemo } from 'react' import { useHistory } from 'react-router-dom' -import { useSearchString } from '@devtron-labs/devtron-fe-common-lib' +import { FiltersTypeEnum, PaginationEnum, Table, useSearchString } from '@devtron-labs/devtron-fe-common-lib' import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText/InteractiveCellText' -import { DeleteComponentsName } from '@Config/constantMessaging' -import { ConfigTableRowActionButton } from './ConfigTableRowActionButton' -import { ConfigurationsTabTypes } from './constants' -import { getConfigTabIcons, renderDefaultTag } from './notifications.util' -import { ConfigurationTableProps } from './types' +import { ConfigurationRowActionButtonWrapper } from './ConfigTableRowActionButton' +import { BASE_CONFIG, ConfigurationsTabTypes, SMTP_TABLE_COLUMNS } from './constants' +import { renderDefaultTag } from './notifications.util' +import { ConfigurationTableProps, SMTPConfigurationTableRowType } from './types' export const SMTPConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTableProps) => { const { smtpConfigurationList } = state const { searchParams } = useSearchString() const history = useHistory() - const onClickEditRow = (configId) => () => { + const onClickEditRow = (id: number) => () => { const newParams = { ...searchParams, - configId: configId.toString(), + configId: id.toString(), modal: ConfigurationsTabTypes.SMTP, } history.push({ @@ -42,51 +42,59 @@ export const SMTPConfigurationTable = ({ state, deleteClickHandler }: Configurat }) } - return ( -
-
-

-

Name

-

Host

-

Port

-

Sender' Email

-

-

-
- {smtpConfigurationList.map((smtpConfig) => ( -
- {getConfigTabIcons(ConfigurationsTabTypes.SMTP)} -
+ const tableRows = useMemo( + () => + smtpConfigurationList.map((smtpConfig) => ({ + id: `${smtpConfig.id}`, + data: { + name: ( +
{renderDefaultTag(smtpConfig.isDefault)}
- - - - -
- ))} -
-
+ ), + host: smtpConfig.host, + port: smtpConfig.port.toString(), + email: smtpConfig.email, + }, + })), + [smtpConfigurationList], + ) + + const onRowClick = (rowData) => { + onClickEditRow(Number(rowData.id))() + } + + return ( + + id="table__smtp-configuration" + columns={SMTP_TABLE_COLUMNS} + rows={tableRows} + emptyStateConfig={{ + noRowsConfig: { + title: 'No SMTP Configurations Found', + }, + }} + filtersVariant={FiltersTypeEnum.STATE} + additionalFilterProps={{ + initialSortKey: BASE_CONFIG[0].field, + }} + paginationVariant={PaginationEnum.NOT_PAGINATED} + filter={null} + rowStartIconConfig={{ + name: 'ic-smtp', + color: null, + size: 24, + }} + rowActionOnHoverConfig={{ + width: 100, + Component: ConfigurationRowActionButtonWrapper, + }} + additionalProps={{ deleteClickHandler, modal: ConfigurationsTabTypes.SMTP }} + onRowClick={onRowClick} + /> ) } diff --git a/src/components/notifications/SlackConfigurationTable.tsx b/src/components/notifications/SlackConfigurationTable.tsx index 0918182f0d..b791de075c 100644 --- a/src/components/notifications/SlackConfigurationTable.tsx +++ b/src/components/notifications/SlackConfigurationTable.tsx @@ -14,17 +14,16 @@ * limitations under the License. */ +import { useMemo } from 'react' import { useHistory } from 'react-router-dom' -import { useSearchString } from '@devtron-labs/devtron-fe-common-lib' +import { FiltersTypeEnum, PaginationEnum, Table, useSearchString } from '@devtron-labs/devtron-fe-common-lib' import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText/InteractiveCellText' -import { DeleteComponentsName } from '@Config/constantMessaging' -import { ConfigTableRowActionButton } from './ConfigTableRowActionButton' -import { ConfigurationsTabTypes } from './constants' -import { getConfigTabIcons } from './notifications.util' -import { ConfigurationTableProps } from './types' +import { ConfigurationRowActionButtonWrapper } from './ConfigTableRowActionButton' +import { BASE_CONFIG, ConfigurationsTabTypes, SLACK_WEBHOOK_TABLE_COLUMNS } from './constants' +import { ConfigurationTableProps, SlackWebhookConfigurationTableRowType } from './types' import './notifications.scss' @@ -33,7 +32,7 @@ const SlackConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTab const history = useHistory() const { slackConfigurationList } = state - const onClickSlackConfigEdit = (id: number) => () => { + const onClickEditRow = (id: number) => () => { const newParams = { ...searchParams, configId: id.toString(), @@ -44,40 +43,57 @@ const SlackConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTab }) } - return ( -
-
-
-

Name

-

Webhook URL

-

-

-
- {slackConfigurationList.map((slackConfig) => ( -
- {getConfigTabIcons(ConfigurationsTabTypes.SLACK)} -
+ const tableRow = useMemo( + () => + slackConfigurationList.map((slackConfig) => ({ + id: `${slackConfig.id}`, + data: { + name: ( +
- - -
- ))} -
-
+ ), + webhookUrl: slackConfig.webhookUrl, + }, + })), + [state.slackConfigurationList], + ) + + const onRowClick = (rowData) => { + onClickEditRow(Number(rowData.id))() + } + + return ( + + id="table__slack-configuration" + columns={SLACK_WEBHOOK_TABLE_COLUMNS} + rows={tableRow} + emptyStateConfig={{ + noRowsConfig: { + title: 'No Slack Configurations Found', + }, + }} + filtersVariant={FiltersTypeEnum.STATE} + additionalFilterProps={{ + initialSortKey: BASE_CONFIG[0].field, + }} + paginationVariant={PaginationEnum.NOT_PAGINATED} + filter={null} + rowStartIconConfig={{ + name: 'ic-slack', + color: null, + size: 24, + }} + rowActionOnHoverConfig={{ + width: 100, + Component: ConfigurationRowActionButtonWrapper, + }} + additionalProps={{ deleteClickHandler, modal: ConfigurationsTabTypes.SLACK }} + onRowClick={onRowClick} + /> ) } diff --git a/src/components/notifications/WebhookConfigurationTable.tsx b/src/components/notifications/WebhookConfigurationTable.tsx index 8eeb174c9e..685858209c 100644 --- a/src/components/notifications/WebhookConfigurationTable.tsx +++ b/src/components/notifications/WebhookConfigurationTable.tsx @@ -14,17 +14,16 @@ * limitations under the License. */ +import { useMemo } from 'react' import { useHistory } from 'react-router-dom' -import { useSearchString } from '@devtron-labs/devtron-fe-common-lib' +import { FiltersTypeEnum, PaginationEnum, Table, useSearchString } from '@devtron-labs/devtron-fe-common-lib' import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText/InteractiveCellText' -import { DeleteComponentsName } from '@Config/constantMessaging' -import { ConfigTableRowActionButton } from './ConfigTableRowActionButton' -import { ConfigurationsTabTypes } from './constants' -import { getConfigTabIcons } from './notifications.util' -import { ConfigurationTableProps } from './types' +import { ConfigurationRowActionButtonWrapper } from './ConfigTableRowActionButton' +import { BASE_CONFIG, ConfigurationsTabTypes, SLACK_WEBHOOK_TABLE_COLUMNS } from './constants' +import { ConfigurationTableProps, SlackWebhookConfigurationTableRowType } from './types' export const WebhookConfigurationTable = ({ state, deleteClickHandler }: ConfigurationTableProps) => { const { webhookConfigurationList } = state @@ -42,42 +41,56 @@ export const WebhookConfigurationTable = ({ state, deleteClickHandler }: Configu }) } + const tableRows = useMemo( + () => + webhookConfigurationList.map((webhookConfig) => ({ + id: `${webhookConfig.id}`, + data: { + name: ( +
+ +
+ ), + webhookUrl: webhookConfig.webhookUrl, + }, + })), + [webhookConfigurationList], + ) + + const onRowClick = (rowData) => { + onClickWebhookConfigEdit(Number(rowData.id))() + } + return ( -
-
-

-

Name

-

Webhook URL

-

-

-
- {webhookConfigurationList.map((webhookConfig) => ( -
- {getConfigTabIcons(ConfigurationsTabTypes.WEBHOOK)} - - - -
- ))} -
-
+ + id="table__webhook-configuration" + columns={SLACK_WEBHOOK_TABLE_COLUMNS} + rows={tableRows} + emptyStateConfig={{ + noRowsConfig: { + title: 'No Webhook Configurations Found', + }, + }} + filtersVariant={FiltersTypeEnum.STATE} + additionalFilterProps={{ + initialSortKey: BASE_CONFIG[0].field, + }} + paginationVariant={PaginationEnum.NOT_PAGINATED} + filter={null} + rowStartIconConfig={{ + name: 'ic-webhook-config', + color: null, + size: 24, + }} + rowActionOnHoverConfig={{ + width: 100, + Component: ConfigurationRowActionButtonWrapper, + }} + additionalProps={{ deleteClickHandler, modal: ConfigurationsTabTypes.WEBHOOK }} + onRowClick={onRowClick} + /> ) } diff --git a/src/components/notifications/constants.ts b/src/components/notifications/constants.ts index f52e27c2c7..e10d669e93 100644 --- a/src/components/notifications/constants.ts +++ b/src/components/notifications/constants.ts @@ -16,7 +16,14 @@ // ------------ Configuration Constants ------------ -import { SlackFormType } from './types' +import { FiltersTypeEnum, TableProps } from '@devtron-labs/devtron-fe-common-lib' + +import { + SESConfigurationTableRowType, + SlackFormType, + SlackWebhookConfigurationTableRowType, + SMTPConfigurationTableRowType, +} from './types' export enum ConfigurationsTabTypes { SES = 'ses', @@ -120,3 +127,59 @@ export const DefaultWebhookValidations = { } export const SlackIncomingWebhookUrl = 'https://slack.com/marketplace/A0F7XDUAZ-incoming-webhooks' + +// ------------ Common Configuration Constants ------------ + +export const BASE_CONFIG = [ + { + label: 'Name', + field: 'name', + size: null, + }, +] + +export const SES_TABLE_COLUMNS: TableProps['columns'] = [ + ...BASE_CONFIG, + { + label: 'Access Key Id', + field: 'accessKeyId', + size: null, + }, + { + label: "Sender's Email", + field: 'email', + size: null, + }, +] + +export const SMTP_TABLE_COLUMNS: TableProps['columns'] = [ + ...BASE_CONFIG, + { + label: 'Host', + field: 'host', + size: null, + }, + { + label: 'Port', + field: 'port', + size: null, + }, + { + label: "Sender's Email", + field: 'email', + size: null, + }, +] + +export const SLACK_WEBHOOK_TABLE_COLUMNS: TableProps< + SlackWebhookConfigurationTableRowType, + FiltersTypeEnum.STATE, + {} +>['columns'] = [ + ...BASE_CONFIG, + { + label: 'Webhook URL', + field: 'webhookUrl', + size: null, + }, +] diff --git a/src/components/notifications/notifications.util.tsx b/src/components/notifications/notifications.util.tsx index fbf8364c9f..8207368621 100644 --- a/src/components/notifications/notifications.util.tsx +++ b/src/components/notifications/notifications.util.tsx @@ -22,21 +22,26 @@ import { ReactComponent as CI } from '@Icons/ic-CI.svg' import { ReactComponent as CD } from '@Icons/ic-CD.svg' import { ReactComponent as Rocket } from '@Icons/ic-paper-rocket.svg' import { ReactComponent as Slack } from '@Icons/slack-logo.svg' -import { ReactComponent as SES } from '@Icons/ic-aws-ses.svg' import { ReactComponent as Webhook } from '@Icons/ic-CIWebhook.svg' -import { ReactComponent as SMTP } from '@Icons/ic-smtp.svg' import { commonSelectStyles, DynamicDataTableHeaderType, DynamicDataTableRowDataType, getUniqueId, + Icon, + IconBaseSizeType, ToastManager, ToastVariantType, - Tooltip, } 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, + SESFormType, + SMTPFormType, + WebhookDataRowType, + WebhookHeaderKeyType, +} from './types' import { REQUIRED_FIELD_MSG } from '@Config/constantMessaging' export const multiSelectStyles = { @@ -166,17 +171,17 @@ export const renderPipelineTypeIcon = (row) => { return } -export const getConfigTabIcons = (tab: ConfigurationsTabTypes, size: number = 24) => { +export const getConfigTabIcons = (tab: ConfigurationsTabTypes, size: IconBaseSizeType = 24) => { switch (tab) { case ConfigurationsTabTypes.SMTP: - return + return case ConfigurationsTabTypes.SLACK: - return + return case ConfigurationsTabTypes.WEBHOOK: - return + return case ConfigurationsTabTypes.SES: default: - return + return } } @@ -224,8 +229,6 @@ export const getSMTPDefaultConfiguration = (shouldBeDefault: boolean): SMTPFormT isLoading: false, }) - - export const renderDefaultTag = (isDefault: boolean) => { if (isDefault) { return Default @@ -353,3 +356,4 @@ export const getValidationFormConfig = (formConfig) => { ) return { allValid, formValidations } } + diff --git a/src/components/notifications/types.tsx b/src/components/notifications/types.tsx index 092c76f169..cf35c12a69 100644 --- a/src/components/notifications/types.tsx +++ b/src/components/notifications/types.tsx @@ -303,3 +303,22 @@ export interface NotificationTabState { singleDeletedId: number disableEdit: boolean } + +export interface BaseConfigurationTableRowType { + name: React.ReactNode +} + +export interface SESConfigurationTableRowType extends BaseConfigurationTableRowType { + accessKeyId: string + email: string +} + +export interface SMTPConfigurationTableRowType extends BaseConfigurationTableRowType { + host: string + port: string + email: string +} + +export interface SlackWebhookConfigurationTableRowType extends BaseConfigurationTableRowType { + webhookUrl: string +} diff --git a/src/config/constantMessaging.ts b/src/config/constantMessaging.ts index 7b4fab911f..152c7b03b4 100644 --- a/src/config/constantMessaging.ts +++ b/src/config/constantMessaging.ts @@ -67,10 +67,6 @@ export const enum DeleteComponentsName { LinkedBuildPipeline = 'linked build pipeline', MaterialView = 'git repository', Node = 'node', - SlackConfigurationTab = 'slack', - SesConfigurationTab = 'ses', - SMTPConfigurationTab = 'smtp', - WebhookConfigurationTab = 'webhook', Preset = 'preset value', Project = 'project', Override = 'override',