feat(owners): display email in owner selectors (#37906)

This commit is contained in:
Michael S. Molina
2026-02-13 09:01:05 -03:00
committed by GitHub
parent 0c0d915391
commit e3e2bece6b
25 changed files with 407 additions and 70 deletions

View File

@@ -39,6 +39,12 @@ import rison from 'rison';
import { useSingleViewResource } from 'src/views/CRUD/hooks';
import withToasts from 'src/components/MessageToasts/withToasts';
import Owner from 'src/types/Owner';
import {
OwnerSelectLabel,
OWNER_TEXT_LABEL_PROP,
OWNER_EMAIL_PROP,
OWNER_OPTION_FILTER_PROPS,
} from 'src/features/owners/OwnerSelectLabel';
// import { Form as AntdForm } from 'src/components/Form';
import { propertyComparator } from '@superset-ui/core/components/Select/utils';
import {
@@ -980,9 +986,18 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
endpoint: `/api/v1/report/related/created_by?q=${query}`,
}).then(response => ({
data: response.json.result.map(
(item: { value: number; text: string }) => ({
(item: {
value: number;
text: string;
extra: { email?: string };
}) => ({
value: item.value,
label: item.text,
label: OwnerSelectLabel({
name: item.text,
email: item.extra?.email,
}),
[OWNER_TEXT_LABEL_PROP]: item.text,
[OWNER_EMAIL_PROP]: item.extra?.email ?? '',
}),
),
totalCount: response.json.count,
@@ -1850,7 +1865,12 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
? [
{
value: currentUser.userId,
label: `${currentUser.firstName} ${currentUser.lastName}`,
label: OwnerSelectLabel({
name: `${currentUser.firstName} ${currentUser.lastName}`,
email: currentUser.email,
}),
[OWNER_TEXT_LABEL_PROP]: `${currentUser.firstName} ${currentUser.lastName}`,
[OWNER_EMAIL_PROP]: currentUser.email ?? '',
},
]
: [],
@@ -1936,12 +1956,21 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
label: (resource.database as DatabaseObject).database_name,
}
: undefined,
owners: (alert?.owners || []).map(owner => ({
value: (owner as MetaObject).value || owner.id,
label:
owners: (resource.owners || []).map(owner => {
const ownerName =
(owner as MetaObject).label ||
`${(owner as Owner).first_name} ${(owner as Owner).last_name}`,
})),
`${(owner as Owner).first_name} ${(owner as Owner).last_name}`;
return {
value: (owner as MetaObject).value || owner.id,
label: OwnerSelectLabel({
name: typeof ownerName === 'string' ? ownerName : '',
email: (owner as Owner).email,
}),
[OWNER_TEXT_LABEL_PROP]:
typeof ownerName === 'string' ? ownerName : '',
[OWNER_EMAIL_PROP]: (owner as Owner).email ?? '',
};
}),
validator_config_json:
resource.validator_type === 'not null'
? {
@@ -2108,6 +2137,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
options={loadOwnerOptions}
onChange={onOwnersChange}
data-test="owners-select"
optionFilterProps={OWNER_OPTION_FILTER_PROPS}
/>
</ModalFormField>
<ModalFormField label={t('Description')}>

View File

@@ -17,6 +17,7 @@
* under the License.
*/
import type { ReactNode } from 'react';
import Owner from 'src/types/Owner';
import { NotificationFormats } from 'src/features/reports/types';
@@ -85,8 +86,9 @@ export type Recipient = {
export type MetaObject = {
id?: number;
label?: string;
label?: ReactNode;
value?: number | string;
[key: string]: unknown;
};
export type DashboardState = {

View File

@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 'spec/helpers/testing-library';
import { OwnerSelectLabel } from '.';
test('renders name and email', () => {
render(OwnerSelectLabel({ name: 'John Doe', email: 'jdoe@example.com' }));
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('jdoe@example.com')).toBeInTheDocument();
});
test('renders only name when email is undefined', () => {
render(OwnerSelectLabel({ name: 'Jane Smith' }));
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
test('renders only name when email is empty string', () => {
render(OwnerSelectLabel({ name: 'Jane Smith', email: '' }));
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
const container = screen.getByText('Jane Smith').parentElement;
expect(container?.children).toHaveLength(1);
});

View File

@@ -0,0 +1,62 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { styled } from '@apache-superset/core/ui';
const StyledLabelContainer = styled.div`
overflow: hidden;
text-overflow: ellipsis;
display: block;
`;
const StyledLabel = styled.span`
overflow: hidden;
text-overflow: ellipsis;
display: block;
`;
const StyledLabelDetail = styled.span`
${({ theme: { fontSizeSM, colorTextSecondary } }) => `
overflow: hidden;
text-overflow: ellipsis;
font-size: ${fontSizeSM}px;
color: ${colorTextSecondary};
line-height: 1.6;
display: block;
`}
`;
export const OWNER_TEXT_LABEL_PROP = 'textLabel';
export const OWNER_EMAIL_PROP = 'ownerEmail';
export const OWNER_OPTION_FILTER_PROPS = [
OWNER_TEXT_LABEL_PROP,
OWNER_EMAIL_PROP,
];
export const OwnerSelectLabel = ({
name,
email,
}: {
name: string;
email?: string;
}) => (
<StyledLabelContainer>
<StyledLabel>{name}</StyledLabel>
{email && <StyledLabelDetail>{email}</StyledLabelDetail>}
</StyledLabelContainer>
);