Ver código fonte

SONAR-22168 Align InputSelect

pull/3361/head
stanislavh 4 semanas atrás
pai
commit
422081485b
26 arquivos alterados com 254 adições e 184 exclusões
  1. 1
    1
      server/sonar-web/design-system/src/components/input/DatePickerCustomCalendarNavigation.tsx
  2. 16
    30
      server/sonar-web/design-system/src/components/input/DiscreetSelect.tsx
  3. 8
    18
      server/sonar-web/design-system/src/components/input/SearchSelect.tsx
  4. 6
    2
      server/sonar-web/design-system/src/components/input/SearchSelectDropdown.tsx
  5. 15
    18
      server/sonar-web/design-system/src/components/input/__tests__/DiscreetSelect-test.tsx
  6. 1
    1
      server/sonar-web/design-system/src/components/input/__tests__/SearchSelectDropdown-test.tsx
  7. 0
    1
      server/sonar-web/design-system/src/components/input/index.ts
  8. 1
    0
      server/sonar-web/design-system/src/sonar-aligned/components/index.ts
  9. 110
    0
      server/sonar-web/design-system/src/sonar-aligned/components/input/InputSelect.tsx
  10. 38
    88
      server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx
  11. 14
    2
      server/sonar-web/design-system/src/sonar-aligned/components/input/__tests__/InputSelect-test.tsx
  12. 22
    0
      server/sonar-web/design-system/src/sonar-aligned/components/input/index.ts
  13. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx
  14. 2
    2
      server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx
  15. 1
    1
      server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx
  16. 2
    2
      server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx
  17. 1
    4
      server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx
  18. 1
    1
      server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx
  19. 1
    1
      server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx
  20. 2
    2
      server/sonar-web/src/main/js/apps/issues/components/AssigneeSelect.tsx
  21. 2
    2
      server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx
  22. 1
    1
      server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
  23. 2
    2
      server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFilters.tsx
  24. 1
    1
      server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx
  25. 1
    1
      server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx
  26. 3
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx

+ 1
- 1
server/sonar-web/design-system/src/components/input/DatePickerCustomCalendarNavigation.tsx Ver arquivo

@@ -33,9 +33,9 @@ import {
useDayPicker,
} from 'react-day-picker';
import { useIntl } from 'react-intl';
import { InputSelect } from '../../sonar-aligned/components/input';
import { InteractiveIcon } from '../InteractiveIcon';
import { ChevronLeftIcon, ChevronRightIcon } from '../icons';
import { InputSelect } from './InputSelect';

const YEARS_TO_DISPLAY = 10;
const MONTHS_IN_A_YEAR = 12;

+ 16
- 30
server/sonar-web/design-system/src/components/input/DiscreetSelect.tsx Ver arquivo

@@ -18,44 +18,30 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import styled from '@emotion/styled';
import { GroupBase, OnChangeValue } from 'react-select';
import tw from 'twin.macro';
import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
import { InputSizeKeys } from '../../types/theme';
import { InputSelect, LabelValueSelectOption } from './InputSelect';
import { InputSelect, SelectProps } from '../../sonar-aligned/components/input';

interface Props<V> {
className?: string;
components?: Parameters<typeof InputSelect>[0]['components'];
type DiscreetProps<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
> = SelectProps<Option, IsMulti, Group> & {
customValue?: JSX.Element;
isDisabled?: boolean;
menuIsOpen?: boolean;
onMenuClose?: () => void;
onMenuOpen?: () => void;
options: Array<LabelValueSelectOption<V>>;
setValue: ({ value }: LabelValueSelectOption<V>) => void;
size?: InputSizeKeys;
value: V;
}
setValue: (value: OnChangeValue<Option, IsMulti>) => void;
};

export function DiscreetSelect<V>({
className,
customValue,
onMenuOpen,
options,
size = 'small',
setValue,
value,
...props
}: Props<V>) {
export function DiscreetSelect<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>({ customValue, size = 'small', setValue, ...props }: DiscreetProps<Option, IsMulti, Group>) {
return (
<StyledSelect
className={className}
<StyledSelect<Option, IsMulti, Group>
onChange={setValue}
onMenuOpen={onMenuOpen}
options={options}
placeholder={customValue}
size={size}
value={options.find((item) => item.value === value)}
{...props}
/>
);
@@ -121,4 +107,4 @@ const StyledSelect = styled(InputSelect)`
& .react-select__control--menu-is-open {
${tw`sw-border-none`};
}
`;
` as typeof InputSelect;

+ 8
- 18
server/sonar-web/design-system/src/components/input/SearchSelect.tsx Ver arquivo

@@ -19,35 +19,26 @@
*/
import classNames from 'classnames';
import { omit } from 'lodash';
import React, { RefObject } from 'react';
import React from 'react';
import { GroupBase, InputProps } from 'react-select';
import AsyncSelect, { AsyncProps } from 'react-select/async';
import Select from 'react-select/dist/declarations/src/Select';
import { INPUT_SIZES } from '../../helpers';
import { Key } from '../../helpers/keyboard';
import { SelectProps, selectStyle } from '../../sonar-aligned/components/input';
import { InputSearch } from './InputSearch';
import { LabelValueSelectOption, SelectProps, selectStyle } from './InputSelect';

type SearchSelectProps<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
> = SelectProps<V, Option, IsMulti, Group> & AsyncProps<Option, IsMulti, Group>;
> = SelectProps<Option, IsMulti, Group> & AsyncProps<Option, IsMulti, Group>;

export function SearchSelect<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>({
size = 'full',
selectRef,
...props
}: SearchSelectProps<V, Option, IsMulti, Group> & {
selectRef?: RefObject<Select<Option, IsMulti, Group>>;
}) {
const styles = selectStyle<V, Option, IsMulti, Group>({ size });
>({ size = 'full', selectRef, ...props }: SearchSelectProps<Option, IsMulti, Group>) {
const styles = selectStyle<Option, IsMulti, Group>({ size });
return (
<AsyncSelect<Option, IsMulti, Group>
{...omit(props, 'className', 'large')}
@@ -82,8 +73,7 @@ export function SearchSelect<
}

export function SearchSelectInput<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>(props: InputProps<Option, IsMulti, Group>) {

+ 6
- 2
server/sonar-web/design-system/src/components/input/SearchSelectDropdown.tsx Ver arquivo

@@ -30,10 +30,14 @@ import { AsyncProps } from 'react-select/async';
import Select from 'react-select/dist/declarations/src/Select';
import tw from 'twin.macro';
import { PopupPlacement, PopupZLevel, themeBorder } from '../../helpers';
import {
IconOption,
LabelValueSelectOption,
SelectProps,
} from '../../sonar-aligned/components/input';
import { InputSizeKeys } from '../../types/theme';
import { DropdownToggler } from '../DropdownToggler';
import { SearchHighlighterContext } from '../SearchHighlighter';
import { IconOption, LabelValueSelectOption, SelectProps } from './InputSelect';
import { SearchSelect } from './SearchSelect';
import { SearchSelectDropdownControl } from './SearchSelectDropdownControl';

@@ -48,7 +52,7 @@ export interface SearchSelectDropdownProps<
Option extends LabelValueSelectOption<V>,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
> extends SelectProps<V, Option, IsMulti, Group>,
> extends SelectProps<Option, IsMulti, Group>,
AsyncProps<Option, IsMulti, Group> {
className?: string;
controlAriaLabel?: string;

+ 15
- 18
server/sonar-web/design-system/src/components/input/__tests__/DiscreetSelect-test.tsx Ver arquivo

@@ -24,7 +24,7 @@ import { FCProps } from '../../../types/misc';
import { DiscreetSelect } from '../DiscreetSelect';

it('should render discreet select and invoke CB on value click', async () => {
const value = 'foo';
const value = options[0];
const setValue = jest.fn();

const user = userEvent.setup();
@@ -36,24 +36,21 @@ it('should render discreet select and invoke CB on value click', async () => {
expect(setValue).toHaveBeenCalled();
});

const options = [
{ label: 'foo-bar', value: 'foo', default: 1 },
{
label: 'bar-foo',
value: 'bar',
Icon: (
<span role="note" title="Icon">
Icon
</span>
),
},
];

function setupWithProps(props: Partial<FCProps<typeof DiscreetSelect>>) {
return render(
<DiscreetSelect
options={[
{ label: 'foo-bar', value: 'foo' },
{
label: 'bar-foo',
value: 'bar',
Icon: (
<span role="note" title="Icon">
Icon
</span>
),
},
]}
setValue={jest.fn()}
value="foo"
{...props}
/>,
<DiscreetSelect options={options} setValue={jest.fn()} value={options[0]} {...props} />,
);
}

+ 1
- 1
server/sonar-web/design-system/src/components/input/__tests__/SearchSelectDropdown-test.tsx Ver arquivo

@@ -20,8 +20,8 @@
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithContext } from '../../../helpers/testUtils';
import { LabelValueSelectOption } from '../../../sonar-aligned';
import { FCProps } from '../../../types/misc';
import { LabelValueSelectOption } from '../InputSelect';
import { SearchSelectDropdown } from '../SearchSelectDropdown';

const defaultOptions = [

+ 0
- 1
server/sonar-web/design-system/src/components/input/index.ts Ver arquivo

@@ -26,7 +26,6 @@ export * from './FormField';
export * from './InputField';
export * from './InputMultiSelect';
export * from './InputSearch';
export * from './InputSelect';
export * from './MultiSelectMenu';
export * from './RadioButton';
export * from './SearchSelect';

+ 1
- 0
server/sonar-web/design-system/src/sonar-aligned/components/index.ts Ver arquivo

@@ -24,4 +24,5 @@ export * from './MetricsRatingBadge';
export * from './Table';
export * from './ToggleButton';
export * from './buttons';
export * from './input';
export * from './typography';

+ 110
- 0
server/sonar-web/design-system/src/sonar-aligned/components/input/InputSelect.tsx Ver arquivo

@@ -0,0 +1,110 @@
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import classNames from 'classnames';
import { omit } from 'lodash';
import { useMemo } from 'react';
import ReactSelect, { GroupBase } from 'react-select';
import {
ClearIndicator,
DropdownIndicator,
IconOption,
SelectProps,
SingleValue,
selectStyle,
} from './SelectCommon';

export function InputSelect<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>({
size = 'medium',
className,
options,
getOptionLabel,
selectRef,
shouldSortOption = false,
...props
}: SelectProps<Option, IsMulti, Group>) {
const orderedOptions = useMemo(() => {
if (!options || options.length === 0) {
return options;
}

if (shouldSortOption) {
return (options as Option[]).sort((a, b) => {
const nameA = getOptionLabel?.(a).toUpperCase() ?? '';
const nameB = getOptionLabel?.(b).toUpperCase() ?? '';
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}

return 0;
});
}

return options;
}, [shouldSortOption, getOptionLabel, options]);

return (
<ReactSelect<Option, IsMulti, Group>
{...omit(props, 'className', 'large')}
className={classNames('react-select', className)}
classNamePrefix="react-select"
classNames={{
container: () => 'sw-relative sw-inline-block sw-align-middle',
placeholder: () => 'sw-truncate sw-leading-4',
menu: () => 'sw-z-dropdown-menu sw-ml-1/2 sw-mt-2',
menuList: () => 'sw-overflow-y-auto sw-py-2 sw-max-h-[12.25rem]',
clearIndicator: () => 'sw-p-0',
dropdownIndicator: () => classNames(props.isClearable && 'sw-p-0'),
control: ({ isDisabled }) =>
classNames(
'sw-box-border sw-rounded-2 sw-overflow-hidden',
isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
),
option: ({ isDisabled }) =>
classNames(
'it__select-option sw-py-2 sw-px-3 sw-cursor-pointer',
isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
),
...props.classNames,
}}
components={{
ClearIndicator,
Option: IconOption,
SingleValue,
DropdownIndicator,
IndicatorSeparator: null,
...props.components,
}}
getOptionLabel={getOptionLabel}
isClearable={props.isClearable ?? false}
isSearchable={props.isSearchable ?? false}
onMenuOpen={props.onMenuOpen}
options={orderedOptions}
ref={selectRef}
styles={selectStyle({ size })}
/>
);
}

server/sonar-web/design-system/src/components/input/InputSelect.tsx → server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx Ver arquivo

@@ -18,11 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { useTheme as themeInfo } from '@emotion/react';
import classNames from 'classnames';
import { omit } from 'lodash';
import { ReactNode } from 'react';
import { RefObject } from 'react';
import { useIntl } from 'react-intl';
import ReactSelect, {
import {
ClearIndicatorProps,
GroupBase,
Props as NamedProps,
@@ -30,45 +28,42 @@ import ReactSelect, {
StylesConfig,
components,
} from 'react-select';
import { INPUT_SIZES } from '../../helpers';
import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
import { InputSizeKeys } from '../../types/theme';
import { InteractiveIcon } from '../InteractiveIcon';
import { SearchHighlighter } from '../SearchHighlighter';
import Select from 'react-select/dist/declarations/src/Select';
import { InteractiveIcon } from '../../../components/InteractiveIcon';
import { SearchHighlighter } from '../../../components/SearchHighlighter';
import { ChevronDownIcon, CloseIcon } from '../../../components/icons';
import { INPUT_SIZES } from '../../../helpers';
import { themeBorder, themeColor, themeContrast } from '../../../helpers/theme';
import { InputSizeKeys } from '../../../types/theme';

import { ChevronDownIcon, CloseIcon } from '../icons';

export interface LabelValueSelectOption<V> {
Icon?: ReactNode;
label: string;
value: V;
}

interface ExtensionProps {
export interface ExtensionProps<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
> {
clearLabel?: string;
selectRef?: RefObject<Select<Option, IsMulti, Group>>;
shouldSortOption?: boolean;
size?: InputSizeKeys;
}

export type SelectProps<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
> = NamedProps<Option, IsMulti, Group> & ExtensionProps;
> = NamedProps<Option, IsMulti, Group> & ExtensionProps<Option, IsMulti, Group>;

export function IconOption<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>(props: OptionProps<Option, IsMulti, Group>) {
const {
data: { label, Icon },
} = props;
const { label, isSelected } = props;
const { Icon } = props.data as { Icon: JSX.Element };

return (
<components.Option {...props}>
<div className="sw-flex sw-items-center sw-gap-1">
<div aria-selected={isSelected} className="sw-flex sw-items-center sw-gap-1" role="option">
{Icon}
<SearchHighlighter>{label}</SearchHighlighter>
</div>
@@ -76,15 +71,13 @@ export function IconOption<
);
}

function SingleValue<
V,
Option extends LabelValueSelectOption<V>,
export function SingleValue<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>(props: OptionProps<Option, IsMulti, Group>) {
const {
data: { label, Icon },
} = props;
const label = props.selectProps.getOptionLabel(props.data);
const { Icon } = props.data as { Icon: JSX.Element };

return (
<components.SingleValue {...props}>
@@ -96,14 +89,13 @@ function SingleValue<
);
}

function ClearIndicator<
V,
Option extends LabelValueSelectOption<V>,
export function ClearIndicator<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>(
props: ClearIndicatorProps<Option, IsMulti, Group> & {
selectProps: SelectProps<V, Option, IsMulti, Group>;
selectProps: SelectProps<Option, IsMulti, Group>;
},
) {
const intl = useIntl();
@@ -123,9 +115,8 @@ function ClearIndicator<
);
}

function DropdownIndicator<
V,
Option extends LabelValueSelectOption<V>,
export function DropdownIndicator<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>(props: OptionProps<Option, IsMulti, Group>) {
@@ -138,55 +129,8 @@ function DropdownIndicator<
);
}

export function InputSelect<
V,
Option extends LabelValueSelectOption<V>,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>({ size = 'medium', className, ...props }: SelectProps<V, Option, IsMulti, Group>) {
return (
<ReactSelect<Option, IsMulti, Group>
{...omit(props, 'className', 'large')}
className={classNames('react-select', className)}
classNamePrefix="react-select"
classNames={{
container: () => 'sw-relative sw-inline-block sw-align-middle',
placeholder: () => 'sw-truncate sw-leading-4',
menu: () => 'sw-z-dropdown-menu sw-ml-1/2 sw-mt-2',
menuList: () => 'sw-overflow-y-auto sw-py-2 sw-max-h-[12.25rem]',
clearIndicator: () => 'sw-p-0',
dropdownIndicator: () => classNames(props.isClearable && 'sw-p-0'),
control: ({ isDisabled }) =>
classNames(
'sw-box-border sw-rounded-2 sw-overflow-hidden',
isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
),
option: ({ isDisabled }) =>
classNames(
'it__select-option sw-py-2 sw-px-3 sw-cursor-pointer',
isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
),
...props.classNames,
}}
components={{
ClearIndicator,
Option: IconOption,
SingleValue,
DropdownIndicator,
IndicatorSeparator: null,
...props.components,
}}
isClearable={props.isClearable ?? false}
isSearchable={props.isSearchable ?? false}
onMenuOpen={props.onMenuOpen}
styles={selectStyle({ size })}
/>
);
}

export function selectStyle<
V,
Option extends LabelValueSelectOption<V>,
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>,
>({ size }: { size: InputSizeKeys }): StylesConfig<Option, IsMulti, Group> {
@@ -231,3 +175,9 @@ export function selectStyle<
}),
};
}

export interface LabelValueSelectOption<V = string> {
Icon?: React.ReactNode;
label: string;
value: V;
}

server/sonar-web/design-system/src/components/input/__tests__/InputSelect-test.tsx → server/sonar-web/design-system/src/sonar-aligned/components/input/__tests__/InputSelect-test.tsx Ver arquivo

@@ -19,8 +19,8 @@
*/
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWithContext } from '../../../helpers/testUtils';
import { FCProps } from '../../../types/misc';
import { renderWithContext } from '../../../../helpers/testUtils';
import { FCProps } from '../../../../types/misc';
import { InputSelect } from '../InputSelect';

it('should render select input and be able to click and change', async () => {
@@ -68,6 +68,18 @@ it('should render select input with disabled prop', () => {
expect(screen.getByRole('combobox')).toBeDisabled();
});

it('should render the select options with sorting when shouldSortOption is true and getOptionLabel passed', async () => {
const { user } = setupWithProps({
shouldSortOption: true,
getOptionLabel: (o: { label: string }) => o.label,
});
await user.click(screen.getByRole('combobox'));
const options = screen.getAllByRole('option');
expect(options).toHaveLength(2);
expect(options[0]).toHaveTextContent('bar-foo');
expect(options[1]).toHaveTextContent('foo-bar');
});

function setupWithProps(props: Partial<FCProps<typeof InputSelect>>) {
return renderWithContext(
<InputSelect

+ 22
- 0
server/sonar-web/design-system/src/sonar-aligned/components/input/index.ts Ver arquivo

@@ -0,0 +1,22 @@
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

export * from './InputSelect';
export * from './SelectCommon';

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx Ver arquivo

@@ -32,7 +32,7 @@ interface StatusFilterProps {
export default function StatusFilter(props: Readonly<StatusFilterProps>) {
const { id, value, onChange } = props;

const options: LabelValueSelectOption<string>[] = [
const options: LabelValueSelectOption[] = [
{ value: STATUSES.ALL, label: translate('background_task.status.ALL') },
{
value: STATUSES.ALL_EXCEPT_PENDING,
@@ -46,7 +46,7 @@ export default function StatusFilter(props: Readonly<StatusFilterProps>) {
];

const handleChange = React.useCallback(
({ value }: LabelValueSelectOption<string>) => {
({ value }: LabelValueSelectOption) => {
onChange(value);
},
[onChange],

+ 2
- 2
server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx Ver arquivo

@@ -30,7 +30,7 @@ interface Props {
}

export default class TypesFilter extends React.PureComponent<Props> {
handleChange = ({ value }: LabelValueSelectOption<string>) => {
handleChange = ({ value }: LabelValueSelectOption) => {
this.props.onChange(value);
};

@@ -43,7 +43,7 @@ export default class TypesFilter extends React.PureComponent<Props> {
};
});

const allOptions: LabelValueSelectOption<string>[] = [
const allOptions: LabelValueSelectOption[] = [
{ value: ALL_TYPES, label: translate('background_task.type.ALL') },
...options,
];

+ 1
- 1
server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx Ver arquivo

@@ -224,7 +224,7 @@ export default function CustomRuleFormModal(props: Readonly<Props>) {
);

const StatusField = React.useMemo(() => {
const statusesOptions = RULE_STATUSES.map((status) => ({
const statusesOptions = RULE_STATUSES.map((status: Status) => ({
label: translate('rules.status', status),
value: status,
}));

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx Ver arquivo

@@ -304,7 +304,7 @@ export default function AzureProjectCreate({
function transformToOptions(
projects: AzureProject[],
repositories?: Dict<AzureRepository[]>,
): Array<GroupBase<LabelValueSelectOption<string>>> {
): Array<GroupBase<LabelValueSelectOption>> {
return projects.map(({ name: projectName }) => ({
label: projectName,
options:
@@ -314,6 +314,6 @@ function transformToOptions(
}));
}

function transformToOption({ name }: AzureRepository): LabelValueSelectOption<string> {
function transformToOption({ name }: AzureRepository): LabelValueSelectOption {
return { value: name, label: name };
}

+ 1
- 4
server/sonar-web/src/main/js/apps/create/project/BitbucketCloud/BitbucketCloudProjectCreate.tsx Ver arquivo

@@ -212,9 +212,6 @@ export default function BitbucketCloudProjectCreate(props: Readonly<Props>) {
);
}

function transformToOption({
name,
slug,
}: BitbucketCloudRepository): LabelValueSelectOption<string> {
function transformToOption({ name, slug }: BitbucketCloudRepository): LabelValueSelectOption {
return { value: slug, label: name };
}

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/Github/GitHubProjectCreate.tsx Ver arquivo

@@ -256,6 +256,6 @@ export default function GitHubProjectCreate(props: Readonly<Props>) {
function transformToOption({
key,
name,
}: GithubOrganization | GithubRepository): LabelValueSelectOption<string> {
}: GithubOrganization | GithubRepository): LabelValueSelectOption {
return { value: key, label: name };
}

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/Gitlab/GitlabProjectCreate.tsx Ver arquivo

@@ -200,6 +200,6 @@ export default function GitlabProjectCreate(props: Readonly<Props>) {
);
}

function transformToOption({ id, name }: GitlabProject): LabelValueSelectOption<string> {
function transformToOption({ id, name }: GitlabProject): LabelValueSelectOption {
return { value: id, label: name };
}

+ 2
- 2
server/sonar-web/src/main/js/apps/issues/components/AssigneeSelect.tsx Ver arquivo

@@ -33,10 +33,10 @@ export const MIN_QUERY_LENGTH = 2;
const UNASSIGNED = { value: '', label: translate('unassigned') };

export interface AssigneeSelectProps {
assignee?: SingleValue<LabelValueSelectOption<string>>;
assignee?: SingleValue<LabelValueSelectOption>;
className?: string;
issues: Issue[];
onAssigneeSelect: (assignee: SingleValue<LabelValueSelectOption<string>>) => void;
onAssigneeSelect: (assignee: SingleValue<LabelValueSelectOption>) => void;
inputId: string;
}


+ 2
- 2
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx Ver arquivo

@@ -54,7 +54,7 @@ interface Props {

interface FormFields {
addTags?: Array<string>;
assignee?: SingleValue<LabelValueSelectOption<string>>;
assignee?: SingleValue<LabelValueSelectOption>;
comment?: string;
notifications?: boolean;
removeTags?: Array<string>;
@@ -126,7 +126,7 @@ export class BulkChangeModal extends React.PureComponent<Props, State> {
return this.props.fetchIssues({ additionalFields: 'actions,transitions', ps: MAX_PAGE_SIZE });
};

handleAssigneeSelect = (assignee: SingleValue<LabelValueSelectOption<string>>) => {
handleAssigneeSelect = (assignee: SingleValue<LabelValueSelectOption>) => {
this.setState({ assignee });
};


+ 1
- 1
server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx Ver arquivo

@@ -89,7 +89,7 @@ export default class ApplyTemplate extends React.PureComponent<Props, State> {
}
};

handlePermissionTemplateChange = ({ value }: LabelValueSelectOption<string>) => {
handlePermissionTemplateChange = ({ value }: LabelValueSelectOption) => {
this.setState({ permissionTemplate: value });
};


+ 2
- 2
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFilters.tsx Ver arquivo

@@ -45,7 +45,7 @@ export default function ProjectActivityPageFilters(props: ProjectActivityPageFil
const eventTypes = isApp
? Object.values(ApplicationAnalysisEventCategory)
: Object.values(ProjectAnalysisEventCategory);
const options: LabelValueSelectOption<string>[] = eventTypes.map((category) => ({
const options: LabelValueSelectOption[] = eventTypes.map((category) => ({
label: translate('event.category', category),
value: category,
}));
@@ -64,7 +64,7 @@ export default function ProjectActivityPageFilters(props: ProjectActivityPageFil
aria-label={translate('project_activity.filter_events')}
className="sw-mr-8 sw-body-sm sw-w-abs-200"
isClearable
onChange={(data: LabelValueSelectOption<string>) => handleCategoryChange(data)}
onChange={(data: LabelValueSelectOption) => handleCategoryChange(data)}
options={options}
placeholder={translate('project_activity.filter_events')}
size="full"

+ 1
- 1
server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.tsx Ver arquivo

@@ -57,7 +57,7 @@ export default class PerspectiveSelect extends React.PureComponent<Props> {
<InputSelect
aria-labelledby="aria-projects-perspective"
className="sw-mr-4 sw-body-sm"
onChange={(data: LabelValueSelectOption<string>) => this.handleChange(data)}
onChange={(data: LabelValueSelectOption) => this.handleChange(data)}
options={options}
placeholder={translate('project_activity.filter_events')}
size="small"

+ 1
- 1
server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx Ver arquivo

@@ -130,7 +130,7 @@ export default class BulkApplyTemplateModal extends React.PureComponent<Props, S
}
};

handlePermissionTemplateChange = ({ value }: LabelValueSelectOption<string>) => {
handlePermissionTemplateChange = ({ value }: LabelValueSelectOption) => {
this.setState({ permissionTemplate: value });
};


+ 3
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx Ver arquivo

@@ -77,7 +77,9 @@ export default function QualityGatePermissionsAddModalRenderer(
noOptionsMessage={() => translate('no_results')}
onChange={props.onSelection}
loadOptions={props.handleSearch}
getOptionValue={({ value }) => (isUser(value) ? value.login : value.name)}
getOptionValue={({ value }: LabelValueSelectOption<UserBase | UserGroup>) =>
isUser(value) ? value.login : value.name
}
controlLabel={renderedSelection}
components={{
Option,

Carregando…
Cancelar
Salvar