From: Grégoire Aubert Date: Tue, 5 Jun 2018 06:37:16 +0000 (+0200) Subject: SONAR-10804 Disable checkbox while loading in select lists X-Git-Tag: 7.5~1085 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=da184fadf1efad5936fbfa6a880e568366b95f77;p=sonarqube.git SONAR-10804 Disable checkbox while loading in select lists --- diff --git a/server/sonar-web/src/main/js/app/styles/init/icons.css b/server/sonar-web/src/main/js/app/styles/init/icons.css index b262be7a0e1..eba9e98a3d1 100644 --- a/server/sonar-web/src/main/js/app/styles/init/icons.css +++ b/server/sonar-web/src/main/js/app/styles/init/icons.css @@ -53,7 +53,7 @@ a[class*=' icon-'] { .icon-checkbox { display: inline-block; vertical-align: top; - padding: 2px; + padding: 1px 2px; box-sizing: border-box; } @@ -64,7 +64,9 @@ a[class*=' icon-'] { height: 10px; border: 1px solid var(--darkBlue); border-radius: 2px; - transition: all 0.2s ease; + transition-property: border-color, background-color, background-image; + transition-duration: 0.2s; + transition-timing-function: ease; } .icon-checkbox-checked:before { @@ -73,10 +75,6 @@ a[class*=' icon-'] { border-color: var(--blue); } -.ie9 .icon-checkbox-checked:before { - background-position: -3px 0; -} - .icon-checkbox-checked.icon-checkbox-single:before { background-image: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20stroke-linejoin%3D%22round%22%20stroke-miterlimit%3D%221.414%22%3E%3Cpath%20d%3D%22M10%204.698C10%204.312%209.688%204%209.302%204H4.698C4.312%204%204%204.312%204%204.698v4.604c0%20.386.312.698.698.698h4.604c.386%200%20.698-.312.698-.698V4.698z%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E'); } diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx index 84ed6c38d7c..50f5672de0e 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx @@ -84,10 +84,6 @@ export default class App extends React.PureComponent { }; renderContent() { - if (this.state.loading) { - return ; - } - if (this.state.notFound) { return ; } @@ -131,7 +127,7 @@ export default class App extends React.PureComponent {
- {this.renderContent()} + {this.renderContent()};
diff --git a/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx b/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx index 8fa07588bb2..8ca761df26d 100644 --- a/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx +++ b/server/sonar-web/src/main/js/components/SelectList/SelectListListElement.tsx @@ -66,6 +66,7 @@ export default class SelectListListElement extends React.PureComponent {this.props.renderElement(this.props.element)} diff --git a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap b/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap index 17bbd55a5cf..76640ae0089 100644 --- a/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/SelectList/__tests__/__snapshots__/SelectListListElement-test.tsx.snap @@ -7,6 +7,7 @@ exports[`should display a loader when checking 1`] = ` @@ -26,6 +27,7 @@ exports[`should display a loader when checking 2`] = ` diff --git a/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx b/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx index ffc8b0668b7..d762f197886 100644 --- a/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx +++ b/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx @@ -76,6 +76,6 @@ export default class DeferredSpinner extends React.PureComponent { this.props.customSpinner || ); } - return (this.props.children as JSX.Element) || null; + return this.props.children || null; } } diff --git a/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.js b/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.js deleted file mode 100644 index 9a44f75f49b..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { mount } from 'enzyme'; -import DeferredSpinner from '../DeferredSpinner'; - -jest.useFakeTimers(); - -it('renders spinner after timeout', () => { - const spinner = mount(); - expect(spinner).toMatchSnapshot(); - jest.runAllTimers(); - spinner.update(); - expect(spinner).toMatchSnapshot(); -}); - -it('add custom className', () => { - const spinner = mount(); - jest.runAllTimers(); - spinner.update(); - expect(spinner).toMatchSnapshot(); -}); - -it('renders children before timeout', () => { - const spinner = mount( - -
foo
-
- ); - expect(spinner).toMatchSnapshot(); - jest.runAllTimers(); - spinner.update(); - expect(spinner).toMatchSnapshot(); -}); - -it('is controlled by loading prop', () => { - const spinner = mount( - -
foo
-
- ); - expect(spinner).toMatchSnapshot(); - spinner.setProps({ loading: true }); - expect(spinner).toMatchSnapshot(); - jest.runAllTimers(); - spinner.update(); - expect(spinner).toMatchSnapshot(); - spinner.setProps({ loading: false }); - expect(spinner).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.tsx new file mode 100644 index 00000000000..dc463192149 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/__tests__/DeferredSpinner-test.tsx @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 * as React from 'react'; +import { mount } from 'enzyme'; +import DeferredSpinner from '../DeferredSpinner'; + +jest.useFakeTimers(); + +it('renders spinner after timeout', () => { + const spinner = mount(); + expect(spinner).toMatchSnapshot(); + jest.runAllTimers(); + spinner.update(); + expect(spinner).toMatchSnapshot(); +}); + +it('add custom className', () => { + const spinner = mount(); + jest.runAllTimers(); + spinner.update(); + expect(spinner).toMatchSnapshot(); +}); + +it('renders children before timeout', () => { + const spinner = mount( + +
foo
+
+ ); + expect(spinner).toMatchSnapshot(); + jest.runAllTimers(); + spinner.update(); + expect(spinner).toMatchSnapshot(); +}); + +it('is controlled by loading prop', () => { + const spinner = mount( + +
foo
+
+ ); + expect(spinner).toMatchSnapshot(); + spinner.setProps({ loading: true }); + expect(spinner).toMatchSnapshot(); + jest.runAllTimers(); + spinner.update(); + expect(spinner).toMatchSnapshot(); + spinner.setProps({ loading: false }); + expect(spinner).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.js.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.js.snap deleted file mode 100644 index 51d17f504c7..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.js.snap +++ /dev/null @@ -1,92 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`add custom className 1`] = ` - - - -`; - -exports[`is controlled by loading prop 1`] = ` - -
- foo -
-
-`; - -exports[`is controlled by loading prop 2`] = ` - -
- foo -
-
-`; - -exports[`is controlled by loading prop 3`] = ` - - - -`; - -exports[`is controlled by loading prop 4`] = ` - -
- foo -
-
-`; - -exports[`renders children before timeout 1`] = ` - -
- foo -
-
-`; - -exports[`renders children before timeout 2`] = ` - - - -`; - -exports[`renders spinner after timeout 1`] = ` - -`; - -exports[`renders spinner after timeout 2`] = ` - - - -`; diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap new file mode 100644 index 00000000000..51d17f504c7 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`add custom className 1`] = ` + + + +`; + +exports[`is controlled by loading prop 1`] = ` + +
+ foo +
+
+`; + +exports[`is controlled by loading prop 2`] = ` + +
+ foo +
+
+`; + +exports[`is controlled by loading prop 3`] = ` + + + +`; + +exports[`is controlled by loading prop 4`] = ` + +
+ foo +
+
+`; + +exports[`renders children before timeout 1`] = ` + +
+ foo +
+
+`; + +exports[`renders children before timeout 2`] = ` + + + +`; + +exports[`renders spinner after timeout 1`] = ` + +`; + +exports[`renders spinner after timeout 2`] = ` + + + +`; diff --git a/server/sonar-web/src/main/js/components/controls/Checkbox.tsx b/server/sonar-web/src/main/js/components/controls/Checkbox.tsx index 42ebbe7da1f..f4602d3b7ab 100644 --- a/server/sonar-web/src/main/js/components/controls/Checkbox.tsx +++ b/server/sonar-web/src/main/js/components/controls/Checkbox.tsx @@ -19,6 +19,7 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; +import DeferredSpinner from '../common/DeferredSpinner'; interface Props { checked: boolean; @@ -26,6 +27,7 @@ interface Props { children?: React.ReactNode; className?: string; id?: string; + loading?: boolean; onCheck: (checked: boolean, id?: string) => void; thirdState?: boolean; } @@ -60,12 +62,18 @@ export default class Checkbox extends React.PureComponent { href="#" id={this.props.id} onClick={this.handleClick}> - + + + {this.props.children} ); } + if (this.props.loading) { + return ; + } + return ( { const checkbox = shallow( true} />); - expect(checkbox.is('.icon-checkbox-checked')).toBe(false); + expect(checkbox.is('.icon-checkbox-checked')).toBeFalsy(); }); it('should render checked', () => { const checkbox = shallow( true} />); - expect(checkbox.is('.icon-checkbox-checked')).toBe(true); + expect(checkbox.is('.icon-checkbox-checked')).toBeTruthy(); }); it('should render disabled', () => { const checkbox = shallow( true} />); - expect(checkbox.is('.icon-checkbox-disabled')).toBe(true); + expect(checkbox.is('.icon-checkbox-disabled')).toBeTruthy(); }); it('should render unchecked third state', () => { const checkbox = shallow( true} thirdState={true} />); - expect(checkbox.is('.icon-checkbox-single')).toBe(true); - expect(checkbox.is('.icon-checkbox-checked')).toBe(false); + expect(checkbox.is('.icon-checkbox-single')).toBeTruthy(); + expect(checkbox.is('.icon-checkbox-checked')).toBeFalsy(); }); it('should render checked third state', () => { const checkbox = shallow( true} thirdState={true} />); - expect(checkbox.is('.icon-checkbox-single')).toBe(true); - expect(checkbox.is('.icon-checkbox-checked')).toBe(true); + expect(checkbox.is('.icon-checkbox-single')).toBeTruthy(); + expect(checkbox.is('.icon-checkbox-checked')).toBeTruthy(); +}); + +it('should render with a spinner', () => { + const checkbox = shallow( true} />); + expect(checkbox.find('DeferredSpinner')).toBeTruthy(); }); it('should render children', () => { @@ -56,7 +61,18 @@ it('should render children', () => { ); expect(checkbox.hasClass('link-checkbox')).toBeTruthy(); - expect(checkbox.find('span')).toHaveLength(1); + expect(checkbox.find('span').exists()).toBeTruthy(); +}); + +it('should render children with a spinner', () => { + const checkbox = shallow( + true}> + foo + + ); + expect(checkbox.hasClass('link-checkbox')).toBeTruthy(); + expect(checkbox.find('span').exists()).toBeTruthy(); + expect(checkbox.find('DeferredSpinner').exists()).toBeTruthy(); }); it('should call onCheck', () => { @@ -84,5 +100,5 @@ it('should apply custom class', () => { const checkbox = shallow( true} /> ); - expect(checkbox.is('.customclass')).toBe(true); + expect(checkbox.is('.customclass')).toBeTruthy(); });