Merge pull request #30695 from drodil/duplicate_origins_fix
fix: duplicate origins with multiple notification processors
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-notifications': patch
|
||||
---
|
||||
|
||||
Fix duplicate notification origins with multiple channels
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
ChannelSetting,
|
||||
isNotificationsEnabledFor,
|
||||
NotificationSettings,
|
||||
OriginSetting,
|
||||
@@ -30,7 +29,6 @@ import { NoBorderTableCell } from './NoBorderTableCell';
|
||||
import { useNotificationFormat } from './UserNotificationSettingsCard';
|
||||
|
||||
export const OriginRow = (props: {
|
||||
channel: ChannelSetting;
|
||||
origin: OriginSetting;
|
||||
settings: NotificationSettings;
|
||||
handleChange: (
|
||||
@@ -42,8 +40,7 @@ export const OriginRow = (props: {
|
||||
open: boolean;
|
||||
handleRowToggle: (originId: string) => void;
|
||||
}) => {
|
||||
const { channel, origin, settings, handleChange, open, handleRowToggle } =
|
||||
props;
|
||||
const { origin, settings, handleChange, open, handleRowToggle } = props;
|
||||
const { formatOriginName } = useNotificationFormat();
|
||||
return (
|
||||
<TableRow>
|
||||
@@ -67,7 +64,7 @@ export const OriginRow = (props: {
|
||||
{settings.channels.map(ch => (
|
||||
<NoBorderTableCell key={ch.id} align="center">
|
||||
<Tooltip
|
||||
title={`Enable or disable ${channel.id.toLocaleLowerCase(
|
||||
title={`Enable or disable ${ch.id.toLocaleLowerCase(
|
||||
'en-US',
|
||||
)} notifications from ${formatOriginName(origin.id)}`}
|
||||
>
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { UserNotificationSettingsPanel } from './UserNotificationSettingsPanel';
|
||||
import { NotificationFormatProvider } from './UserNotificationSettingsCard.tsx';
|
||||
|
||||
describe('UserNotificationSettingsPanel', () => {
|
||||
it('renders each origin only once even if present in multiple channels', () => {
|
||||
const settings = {
|
||||
channels: [
|
||||
{
|
||||
id: 'email',
|
||||
origins: [
|
||||
{
|
||||
id: 'origin-1',
|
||||
enabled: true,
|
||||
topics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'slack',
|
||||
origins: [
|
||||
{
|
||||
id: 'origin-1',
|
||||
enabled: false,
|
||||
topics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
render(
|
||||
<NotificationFormatProvider originMap={{}} topicMap={{}}>
|
||||
<UserNotificationSettingsPanel
|
||||
settings={settings}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
</NotificationFormatProvider>,
|
||||
);
|
||||
|
||||
const originRows = screen.getAllByText('Origin 1');
|
||||
expect(originRows).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
+37
-25
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { NotificationSettings } from '@backstage/plugin-notifications-common';
|
||||
import {
|
||||
NotificationSettings,
|
||||
OriginSetting,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
import Table from '@material-ui/core/Table';
|
||||
import MuiTableCell from '@material-ui/core/TableCell';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
@@ -109,6 +112,18 @@ export const UserNotificationSettingsPanel = (props: {
|
||||
);
|
||||
}
|
||||
|
||||
const uniqueOriginsMap = settings.channels
|
||||
.flatMap(channel => channel.origins)
|
||||
.reduce((map, origin) => {
|
||||
if (!map.has(origin.id)) {
|
||||
map.set(origin.id, origin);
|
||||
}
|
||||
return map;
|
||||
}, new Map<string, OriginSetting>())
|
||||
.values();
|
||||
|
||||
const uniqueOrigins = Array.from(uniqueOriginsMap);
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableHead>
|
||||
@@ -130,30 +145,27 @@ export const UserNotificationSettingsPanel = (props: {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{settings.channels.map(channel =>
|
||||
channel.origins.flatMap(origin => [
|
||||
<OriginRow
|
||||
key={origin.id}
|
||||
channel={channel}
|
||||
origin={origin}
|
||||
settings={settings}
|
||||
open={expandedRows.has(origin.id)}
|
||||
handleChange={handleChange}
|
||||
handleRowToggle={handleRowToggle}
|
||||
/>,
|
||||
...(expandedRows.has(origin.id)
|
||||
? origin.topics?.map(topic => (
|
||||
<TopicRow
|
||||
key={`${origin.id}-${topic.id}`}
|
||||
topic={topic}
|
||||
origin={origin}
|
||||
settings={settings}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
)) || []
|
||||
: []),
|
||||
]),
|
||||
)}
|
||||
{uniqueOrigins.flatMap(origin => [
|
||||
<OriginRow
|
||||
key={origin.id}
|
||||
origin={origin}
|
||||
settings={settings}
|
||||
open={expandedRows.has(origin.id)}
|
||||
handleChange={handleChange}
|
||||
handleRowToggle={handleRowToggle}
|
||||
/>,
|
||||
...(expandedRows.has(origin.id)
|
||||
? origin.topics?.map(topic => (
|
||||
<TopicRow
|
||||
key={`${origin.id}-${topic.id}`}
|
||||
topic={topic}
|
||||
origin={origin}
|
||||
settings={settings}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
)) || []
|
||||
: []),
|
||||
])}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user