diff options
author | Revanshu Paliwal <revanshu.paliwal@sonarsource.com> | 2022-08-29 11:03:29 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-08-30 20:03:13 +0000 |
commit | a74e990dbbddbfac7c608a537304180d6869e406 (patch) | |
tree | 7e2161f511d589caa6d5739194ded629a5ed27b4 | |
parent | 7e53bc4c96453b744ebe478d912378c989ea7a78 (diff) | |
download | sonarqube-a74e990dbbddbfac7c608a537304180d6869e406.tar.gz sonarqube-a74e990dbbddbfac7c608a537304180d6869e406.zip |
SONAR-17228 Fixing scroll behaviour in setting tabs
5 files changed, 18 insertions, 24 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx index e292205d626..0e2c35c6d36 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx @@ -90,7 +90,8 @@ export function SettingsAppRenderer(props: SettingsAppRendererProps) { <div className="layout-page-main"> <div className="layout-page-main-inner"> - <div className="big-padded"> + {/* Adding a key to force re-rendering of the category content, so that it resets the scroll position */} + <div className="big-padded" key={selectedCategory}> {foundAdditionalCategory && shouldRenderAdditionalCategory ? ( foundAdditionalCategory.renderComponent({ categories, diff --git a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx index 64c255172c5..a133d64cc90 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx @@ -21,7 +21,6 @@ import { groupBy, sortBy } from 'lodash'; import * as React from 'react'; import { Location, withRouter } from '../../../components/hoc/withRouter'; import { sanitizeStringRestricted } from '../../../helpers/sanitize'; -import { scrollToElement } from '../../../helpers/scrolling'; import { SettingDefinitionAndValue } from '../../../types/settings'; import { Component } from '../../../types/types'; import { getSubCategoryDescription, getSubCategoryName } from '../utils'; @@ -36,16 +35,13 @@ export interface SubCategoryDefinitionsListProps { subCategory?: string; } -const SCROLL_OFFSET_TOP = 200; -const SCROLL_OFFSET_BOTTOM = 500; - export class SubCategoryDefinitionsList extends React.PureComponent< SubCategoryDefinitionsListProps > { componentDidUpdate(prevProps: SubCategoryDefinitionsListProps) { const { hash } = this.props.location; if (hash && prevProps.location.hash !== hash) { - const query = `[data-key=${hash.substr(1).replace(/[.#/]/g, '\\$&')}]`; + const query = `[data-key=${hash.substring(1).replace(/[.#/]/g, '\\$&')}]`; const element = document.querySelector<HTMLHeadingElement | HTMLLIElement>(query); this.scrollToSubCategoryOrDefinition(element); } @@ -54,12 +50,8 @@ export class SubCategoryDefinitionsList extends React.PureComponent< scrollToSubCategoryOrDefinition = (element: HTMLHeadingElement | HTMLLIElement | null) => { if (element) { const { hash } = this.props.location; - if (hash && hash.substr(1) === element.getAttribute('data-key')) { - scrollToElement(element, { - topOffset: SCROLL_OFFSET_TOP, - bottomOffset: SCROLL_OFFSET_BOTTOM, - smooth: true - }); + if (hash && hash.substring(1) === element.getAttribute('data-key')) { + element.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }); } } }; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx index 2bfbbf61873..78925da7276 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx @@ -20,7 +20,6 @@ import { mount, shallow } from 'enzyme'; import * as React from 'react'; import { mockSettingWithCategory } from '../../../../helpers/mocks/settings'; -import { scrollToElement } from '../../../../helpers/scrolling'; import { mockLocation } from '../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../helpers/testUtils'; import { @@ -37,24 +36,19 @@ it('should render correctly', () => { expect(shallowRender({ subCategory: 'qg' })).toMatchSnapshot('subcategory'); }); -it('should scroll if hash is defined', async () => { +it('should scroll if hash is defined and updated', async () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); const wrapper = shallowRender({ location: mockLocation({ hash: '#qg' }) }); await waitAndUpdate(wrapper); wrapper.find('h2').forEach(node => mount(node.getElement())); - expect(scrollToElement).toBeCalled(); -}); - -it('should scroll when hash is updated', async () => { - const wrapper = shallowRender({ location: mockLocation({ hash: '#qg' }) }); + expect(window.HTMLElement.prototype.scrollIntoView).toBeCalled(); wrapper.setProps({ location: mockLocation({ hash: '#email' }) }); - await waitAndUpdate(wrapper); - - expect(scrollToElement).toBeCalled(); + expect(window.HTMLElement.prototype.scrollIntoView).toBeCalled(); }); function shallowRender(props: Partial<SubCategoryDefinitionsListProps> = {}) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsAppRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsAppRenderer-test.tsx.snap index a40cc74b2c1..7de14af9ca2 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsAppRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsAppRenderer-test.tsx.snap @@ -49,6 +49,7 @@ exports[`should render almintegration correctly 1`] = ` > <div className="big-padded" + key="almintegration" > <withRouter(withAppStateContext(AlmIntegration)) categories={ @@ -133,6 +134,7 @@ exports[`should render default view correctly 1`] = ` > <div className="big-padded" + key="general" > <CategoryDefinitionsList category="general" @@ -241,6 +243,7 @@ exports[`should render exclusions correctly 1`] = ` > <div className="big-padded" + key="exclusions" > <AnalysisScope categories={ @@ -325,6 +328,7 @@ exports[`should render languages correctly 1`] = ` > <div className="big-padded" + key="languages" > <withRouter(Languages) categories={ @@ -409,6 +413,7 @@ exports[`should render new_code_period correctly 1`] = ` > <div className="big-padded" + key="new_code_period" > <NewCodePeriod /> </div> @@ -467,6 +472,7 @@ exports[`should render pull_request_decoration_binding correctly 1`] = ` > <div className="big-padded" + key="pull_request_decoration_binding" > <CategoryDefinitionsList category="pull_request_decoration_binding" diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx index 1dc541cf572..88dd2eb57fe 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx @@ -122,14 +122,15 @@ export default function Authentication(props: Props) { selected={currentTab} tabs={tabs} /> - + {/* Adding a key to force re-rendering of the tab container, so that it resets the scroll position */} <ScreenPositionHelper> {({ top }) => ( <div style={{ maxHeight: `calc(100vh - ${top + HEIGHT_ADJUSTMENT}px)` }} - className="bordered overflow-y-auto tabbed-definitions"> + className="bordered overflow-y-auto tabbed-definitions" + key={currentTab}> <div className="big-padded"> <Alert variant="info"> <FormattedMessage |