From 792921dfe50178050aa591ebcd4d7f62325684f0 Mon Sep 17 00:00:00 2001 From: Revanshu Paliwal Date: Wed, 17 Jan 2024 16:33:08 +0100 Subject: [PATCH] SONAR-21420 Migrate audit logs page to new UI --- .../src/components/buttons/Button.tsx | 15 ++ .../buttons/__tests__/ButtonPrimary-test.tsx | 36 +++++ .../js/app/components/GlobalContainer.tsx | 1 + .../components/AuditAppRenderer.tsx | 143 ++++++++++-------- .../audit-logs/components/DownloadButton.tsx | 15 +- .../components/__tests__/AuditApp-it.tsx | 45 ++++-- 6 files changed, 171 insertions(+), 84 deletions(-) create mode 100644 server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx diff --git a/server/sonar-web/design-system/src/components/buttons/Button.tsx b/server/sonar-web/design-system/src/components/buttons/Button.tsx index 80e58555a0b..6d17cd784f2 100644 --- a/server/sonar-web/design-system/src/components/buttons/Button.tsx +++ b/server/sonar-web/design-system/src/components/buttons/Button.tsx @@ -149,6 +149,21 @@ export const buttonStyle = (props: ThemedProps) => css` const BaseButtonLink = styled(BaseLink)` ${buttonStyle} + + /* + Workaround to apply disable style to button-link + as link does not have disabled attribute, using props instead + */ + + ${({ disabled, theme }) => + disabled + ? `&, &:hover, &:focus, &:active { + color: ${themeContrast('buttonDisabled')({ theme })}; + background-color: ${themeColor('buttonDisabled')({ theme })}; + border: ${themeBorder('default', 'buttonDisabledBorder')({ theme })}; + cursor: not-allowed; + }` + : undefined}; `; const BaseButton = styled.button` diff --git a/server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx b/server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx new file mode 100644 index 00000000000..af81f1dd7d1 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx @@ -0,0 +1,36 @@ +/* + * 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 { render, screen } from '@testing-library/react'; +import { ButtonPrimary } from '../ButtonPrimary'; + +it('renders ButtonPrimary correctly', () => { + render(Hello); + expect(screen.getByRole('button', { name: 'Hello' })).toBeInTheDocument(); +}); + +it('renders ButtonPrimary correctly when to is defined', () => { + render( + + Hello + , + ); + expect(screen.queryByRole('button', { name: 'Hello' })).not.toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'Hello' })).toBeInTheDocument(); +}); diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index 9e7b58e11f7..f08f3ccb9b1 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -83,6 +83,7 @@ const TEMP_PAGELIST_WITH_NEW_BACKGROUND_WHITE = [ '/admin/users', '/admin/settings/encryption', '/admin/extension/license/support', + '/admin/audit', ]; export default function GlobalContainer() { diff --git a/server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx b/server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx index 84c58aa20f8..7242e023fd0 100644 --- a/server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx @@ -17,13 +17,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { subDays } from 'date-fns'; +import { + DateRangePicker, + LargeCenteredLayout, + Link, + PageContentFontWrapper, + PopupZLevel, + RadioButton, + Title, +} from 'design-system'; import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import { FormattedMessage } from 'react-intl'; -import Link from '../../../components/common/Link'; -import DateRangeInput from '../../../components/controls/DateRangeInput'; -import Radio from '../../../components/controls/Radio'; import Suggestions from '../../../components/embed-docs-modal/Suggestions'; import { now } from '../../../helpers/dates'; import { translate } from '../../../helpers/l10n'; @@ -72,68 +79,74 @@ export default function AuditAppRenderer(props: AuditAppRendererProps) { const { dateRange, downloadStarted, housekeepingPolicy, selection } = props; return ( -
- - - -
-

{translate('audit_logs.page')}

-
- -

- {translate('audit_logs.page.description.1')} -
- - {translate('audit_logs.page.description.link')} - - ), - }} - /> -

- -
-

{translate('audit_logs.download')}

- -
    - {getRangeOptions(housekeepingPolicy).map((option) => ( -
  • - - {translate('audit_logs.range_option', option)} - -
  • - ))} -
- - + + + + + {translate('audit_logs.page')} + +

+ {translate('audit_logs.page.description.1')} +
+ + {translate('audit_logs.page.description.link')} + + ), + }} + /> +

+ +
+

{translate('audit_logs.download')}

+ +
    + {getRangeOptions(housekeepingPolicy).map((option) => ( +
  • + + {translate('audit_logs.range_option', option)} + +
  • + ))} +
+ + +
+ + -
- - -
+ + ); } diff --git a/server/sonar-web/src/main/js/apps/audit-logs/components/DownloadButton.tsx b/server/sonar-web/src/main/js/apps/audit-logs/components/DownloadButton.tsx index 132960224bc..718bc6ee853 100644 --- a/server/sonar-web/src/main/js/apps/audit-logs/components/DownloadButton.tsx +++ b/server/sonar-web/src/main/js/apps/audit-logs/components/DownloadButton.tsx @@ -17,8 +17,8 @@ * 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 { endOfDay, startOfDay, subDays } from 'date-fns'; +import { ButtonPrimary } from 'design-system/lib'; import * as React from 'react'; import { now } from '../../../helpers/dates'; import { translate } from '../../../helpers/l10n'; @@ -63,7 +63,7 @@ function getRangeParams(selection: RangeOption, dateRange?: { from?: Date; to?: }).toString(); } -export default function DownloadButton(props: DownloadButtonProps) { +export default function DownloadButton(props: Readonly) { const { dateRange, downloadStarted, selection } = props; const downloadDisabled = @@ -77,20 +77,19 @@ export default function DownloadButton(props: DownloadButtonProps) { return ( <> - {translate('download_verb')} - + {downloadStarted && ( -
+

{translate('audit_logs.download_start.sentence.1')}

{translate('audit_logs.download_start.sentence.2')}


diff --git a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx index 83ad423c2ce..31bd0f534ac 100644 --- a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx @@ -17,14 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { getDate, getMonth, getYear, subDays } from 'date-fns'; import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock'; import { now } from '../../../../helpers/dates'; -import { getMonthName } from '../../../../helpers/l10n'; +import { getShortMonthName } from '../../../../helpers/l10n'; import { renderAppWithAdminContext } from '../../../../helpers/testReactTestingUtils'; -import { byPlaceholderText, byRole, byText } from '../../../../helpers/testSelector'; +import { byPlaceholderText, byRole, byTestId, byText } from '../../../../helpers/testSelector'; import { AdminPageExtension } from '../../../../types/extension'; import { SettingsKey } from '../../../../types/settings'; import routes from '../../routes'; @@ -64,8 +63,8 @@ const ui = { downloadSentenceStart: byText('audit_logs.download_start.sentence.1'), startDateInput: byPlaceholderText('start_date'), endDateInput: byPlaceholderText('end_date'), - dateInputMonthSelect: byRole('combobox', { name: 'Month:' }), - dateInputYearSelect: byRole('combobox', { name: 'Year:' }), + dateInputMonthSelect: byTestId('month-select'), + dateInputYearSelect: byTestId('year-select'), }; let handler: SettingsServiceMock; @@ -113,15 +112,39 @@ it('should handle download button click', async () => { await user.click(ui.customRadio.get()); expect(ui.downloadButton.get()).toHaveAttribute('aria-disabled', 'true'); await user.click(ui.startDateInput.get()); + const monthSelector = ui.dateInputMonthSelect.byRole('combobox').get(); + await user.click(monthSelector); + await user.click( + ui.dateInputMonthSelect + .byText(getShortMonthName(getMonth(startDay))) + .getAll() + .slice(-1)[0], + ); + + const yearSelector = ui.dateInputYearSelect.byRole('combobox').get(); + await user.click(yearSelector); + await user.click( + ui.dateInputYearSelect.byText(getYear(startDay).toString()).getAll().slice(-1)[0], + ); + + await user.click(byText(getDate(startDay), { selector: 'button' }).get()); - await user.selectOptions(ui.dateInputMonthSelect.get(), getMonthName(getMonth(startDay))); - await user.selectOptions(ui.dateInputYearSelect.get(), getYear(startDay).toString()); - await user.click(screen.getByText(getDate(startDay))); await user.click(ui.endDateInput.get()); - await user.selectOptions(ui.dateInputMonthSelect.get(), getMonthName(getMonth(endDate))); - await user.selectOptions(ui.dateInputYearSelect.get(), getYear(endDate).toString()); - await user.click(screen.getByText(getDate(endDate))); + await user.click(monthSelector); + await user.click( + ui.dateInputMonthSelect + .byText(getShortMonthName(getMonth(endDate))) + .getAll() + .slice(-1)[0], + ); + + await user.click(yearSelector); + await user.click( + ui.dateInputYearSelect.byText(getYear(endDate).toString()).getAll().slice(-1)[0], + ); + + await user.click(byText(getDate(endDate), { selector: 'button' }).get()); expect(await ui.downloadButton.find()).toHaveAttribute('aria-disabled', 'false'); await user.click(downloadButton); -- 2.39.5