aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main')
-rw-r--r--server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx38
-rw-r--r--server/sonar-web/src/main/js/app/components/SimpleContainer.tsx38
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx42
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css8
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx20
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx (renamed from server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.tsx)92
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx16
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavHeader-test.tsx (renamed from server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.tsx)9
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap98
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap104
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap32
-rw-r--r--server/sonar-web/src/main/js/app/styles/components/page.css7
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/base.css2
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/icons.css1
-rw-r--r--server/sonar-web/src/main/js/app/styles/print.css7
-rw-r--r--server/sonar-web/src/main/js/app/styles/style.css5
-rw-r--r--server/sonar-web/src/main/js/app/types.ts25
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutApp.js4
-rw-r--r--server/sonar-web/src/main/js/apps/account/account.css2
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Password.js4
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Security.js4
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js46
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/Notifications.js7
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/Projects.js50
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap126
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap288
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx33
-rw-r--r--server/sonar-web/src/main/js/apps/account/profile/Profile.js36
-rw-r--r--server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs142
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js58
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/App.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Search.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/App.js4
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list.hbs26
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs2
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs2
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/App.js6
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/PageActions.js6
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/Search.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/style.css1
-rw-r--r--server/sonar-web/src/main/js/apps/metrics/templates/metrics-layout.hbs2
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/MembersList.js30
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js154
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap74
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap638
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx32
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js8
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/List.js10
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/App.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/key/Key.js2
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/links/Table.js10
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap124
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityProfiles/Table.tsx24
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Table-test.tsx.snap160
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx54
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Projects-test.tsx.snap120
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatesApp.js4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/App.js11
-rw-r--r--server/sonar-web/src/main/js/apps/users/UsersList.tsx54
-rw-r--r--server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap118
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/Action.tsx40
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap82
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/styles/web-api.css5
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/styles.css2
-rw-r--r--server/sonar-web/src/main/js/components/common/BranchStatus.css3
-rw-r--r--server/sonar-web/src/main/js/components/common/BranchStatus.tsx10
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap42
-rw-r--r--server/sonar-web/src/main/js/components/controls/Favorite.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx9
-rw-r--r--server/sonar-web/src/main/js/components/controls/FavoriteIssueFilter.js42
-rw-r--r--server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx20
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx12
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Favorite-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/components/nav/ContextNavBar.css5
-rw-r--r--server/sonar-web/src/main/js/helpers/urls.ts14
94 files changed, 1767 insertions, 1720 deletions
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx
index e87bea11cce..c097f03da96 100644
--- a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx
+++ b/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx
@@ -21,32 +21,16 @@ import * as React from 'react';
import { Link } from 'react-router';
import { translate } from '../../helpers/l10n';
-export default class ComponentContainerNotFound extends React.PureComponent {
- componentDidMount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
- }
-
- componentWillUnmount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
- }
-
- render() {
- return (
- <div id="bd" className="page-wrapper-simple">
- <div id="nonav" className="page-simple">
- <h2 className="big-spacer-bottom">{translate('dashboard.project_not_found')}</h2>
- <p className="spacer-bottom">{translate('dashboard.project_not_found.2')}</p>
- <p>
- <Link to="/">Go back to the homepage</Link>
- </p>
- </div>
+export default function ComponentContainerNotFound() {
+ return (
+ <div id="bd" className="page-wrapper-simple">
+ <div id="nonav" className="page-simple">
+ <h2 className="big-spacer-bottom">{translate('dashboard.project_not_found')}</h2>
+ <p className="spacer-bottom">{translate('dashboard.project_not_found.2')}</p>
+ <p>
+ <Link to="/">Go back to the homepage</Link>
+ </p>
</div>
- );
- }
+ </div>
+ );
}
diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
index 4e5e35b7cce..8c2efc977af 100644
--- a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
+++ b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
@@ -27,35 +27,19 @@ interface Props {
hideLoggedInInfo?: boolean;
}
-export default class SimpleContainer extends React.PureComponent<Props> {
- componentDidMount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
- }
+export default function SimpleContainer(props: Props) {
+ return (
+ <div className="global-container">
+ <div className="page-wrapper" id="container">
+ <NavBar className="navbar-global" height={theme.globalNavHeightRaw} />
- componentWillUnmount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
- }
-
- render() {
- return (
- <div className="global-container">
- <div className="page-wrapper" id="container">
- <NavBar className="navbar-global" height={theme.globalNavHeightRaw} />
-
- <div id="bd" className="page-wrapper-simple">
- <div id="nonav" className="page-simple">
- {this.props.children}
- </div>
+ <div id="bd" className="page-wrapper-simple">
+ <div id="nonav" className="page-simple">
+ {props.children}
</div>
</div>
- <GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} />
</div>
- );
- }
+ <GlobalFooterContainer hideLoggedInInfo={props.hideLoggedInInfo} />
+ </div>
+ );
}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx b/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx
index 154b674f6b9..1cad19e3d20 100644
--- a/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx
+++ b/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx
@@ -20,34 +20,18 @@
import * as React from 'react';
import { Link } from 'react-router';
-export default class ExtensionNotFound extends React.PureComponent {
- componentDidMount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
- }
-
- componentWillUnmount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
- }
-
- render() {
- return (
- <div id="bd" className="page-wrapper-simple">
- <div id="nonav" className="page-simple">
- <h2 className="big-spacer-bottom">The page you were looking for does not exist.</h2>
- <p className="spacer-bottom">
- You may have mistyped the address or the page may have moved.
- </p>
- <p>
- <Link to="/">Go back to the homepage</Link>
- </p>
- </div>
+export default function ExtensionNotFound() {
+ return (
+ <div id="bd" className="page-wrapper-simple">
+ <div id="nonav" className="page-simple">
+ <h2 className="big-spacer-bottom">The page you were looking for does not exist.</h2>
+ <p className="spacer-bottom">
+ You may have mistyped the address or the page may have moved.
+ </p>
+ <p>
+ <Link to="/">Go back to the homepage</Link>
+ </p>
</div>
- );
- }
+ </div>
+ );
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
index fd0f3a46df1..f9488b415e3 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
@@ -1,9 +1,9 @@
.navbar-context-branches {
- display: inline-block;
- vertical-align: top;
- padding: var(--gridSize) 0;
+ display: inline-flex;
+ justify-content: center;
+ line-height: calc(2 * var(--gridSize));
margin-left: calc(2 * var(--gridSize));
- line-height: 16px;
+ font-size: var(--baseFontSize);
}
.navbar-context-meta-branch-menu-item {
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
index ff2205adbb6..7d4cd235925 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
@@ -18,8 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import ComponentNavBranch from './ComponentNavBranch';
-import ComponentNavBreadcrumbs from './ComponentNavBreadcrumbs';
+import ComponentNavHeader from './ComponentNavHeader';
import ComponentNavMeta from './ComponentNavMeta';
import ComponentNavMenu from './ComponentNavMenu';
import ComponentNavBgTaskNotif from './ComponentNavBgTaskNotif';
@@ -111,16 +110,13 @@ export default class ComponentNav extends React.PureComponent<Props, State> {
id="context-navigation"
height={notifComponent ? theme.contextNavHeightRaw + 20 : theme.contextNavHeightRaw}
notif={notifComponent}>
- <ComponentNavBreadcrumbs component={this.props.component} />
- {this.props.currentBranch && (
- <ComponentNavBranch
- branches={this.props.branches}
- component={this.props.component}
- currentBranch={this.props.currentBranch}
- // to close dropdown on any location change
- location={this.props.location}
- />
- )}
+ <ComponentNavHeader
+ branches={this.props.branches}
+ component={this.props.component}
+ currentBranch={this.props.currentBranch}
+ // to close dropdown on any location change
+ location={this.props.location}
+ />
<ComponentNavMeta branch={this.props.currentBranch} component={this.props.component} />
<ComponentNavMenu
branch={this.props.currentBranch}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx
index c8a75e8a105..e042b010d2e 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx
@@ -20,7 +20,8 @@
import * as React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
-import { Component, Organization } from '../../../types';
+import ComponentNavBranch from './ComponentNavBranch';
+import { Component, Organization, Branch, Breadcrumb } from '../../../types';
import QualifierIcon from '../../../../components/shared/QualifierIcon';
import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer';
import OrganizationAvatar from '../../../../components/common/OrganizationAvatar';
@@ -36,46 +37,16 @@ interface StateProps {
}
interface OwnProps {
+ branches: Branch[];
component: Component;
+ currentBranch?: Branch;
+ location?: any;
}
interface Props extends StateProps, OwnProps {}
-export function ComponentNavBreadcrumbs(props: Props) {
+export function ComponentNavHeader(props: Props) {
const { component, organization, shouldOrganizationBeDisplayed } = props;
- const { breadcrumbs } = component;
-
- const lastItem = breadcrumbs[breadcrumbs.length - 1];
-
- const items: JSX.Element[] = [];
- breadcrumbs.forEach((item, index) => {
- const isPath = item.qualifier === 'DIR';
- const itemName = isPath ? collapsePath(item.name, 15) : limitComponentName(item.name);
-
- if (index === 0) {
- items.push(
- <QualifierIcon
- className="spacer-right"
- key={`qualifier-${item.key}`}
- qualifier={lastItem.qualifier}
- />
- );
- }
-
- items.push(
- <Link
- className="link-base-color link-no-underline"
- key={`name-${item.key}`}
- title={item.name}
- to={getProjectUrl(item.key)}>
- {itemName}
- </Link>
- );
-
- if (index < breadcrumbs.length - 1) {
- items.push(<span className="slash-separator" key={`separator-${item.key}`} />);
- }
- });
return (
<header className="navbar-context-header">
@@ -84,28 +55,59 @@ export function ComponentNavBreadcrumbs(props: Props) {
organization={organization && shouldOrganizationBeDisplayed ? organization : undefined}
/>
{organization &&
- shouldOrganizationBeDisplayed && <OrganizationAvatar organization={organization} />}
- {organization &&
shouldOrganizationBeDisplayed && (
- <OrganizationLink
- organization={organization}
- className="link-base-color link-no-underline spacer-left">
- {organization.name}
- </OrganizationLink>
+ <>
+ <OrganizationAvatar organization={organization} />
+ <OrganizationLink
+ organization={organization}
+ className="link-base-color link-no-underline spacer-left">
+ {organization.name}
+ </OrganizationLink>
+ <span className="slash-separator" />
+ </>
)}
- {organization && shouldOrganizationBeDisplayed && <span className="slash-separator" />}
- {items}
+ {renderBreadcrumbs(component.breadcrumbs)}
{component.visibility === 'private' && (
<PrivateBadge className="spacer-left" qualifier={component.qualifier} />
)}
+ {props.currentBranch && (
+ <ComponentNavBranch
+ branches={props.branches}
+ component={component}
+ currentBranch={props.currentBranch}
+ // to close dropdown on any location change
+ location={props.location}
+ />
+ )}
</header>
);
}
+function renderBreadcrumbs(breadcrumbs: Breadcrumb[]) {
+ const lastItem = breadcrumbs[breadcrumbs.length - 1];
+ return breadcrumbs.map((item, index) => {
+ const isPath = item.qualifier === 'DIR';
+ const itemName = isPath ? collapsePath(item.name, 15) : limitComponentName(item.name);
+
+ return (
+ <React.Fragment key={item.key}>
+ {index === 0 && <QualifierIcon className="spacer-right" qualifier={lastItem.qualifier} />}
+ <Link
+ className="link-base-color link-no-underline"
+ title={item.name}
+ to={getProjectUrl(item.key)}>
+ {itemName}
+ </Link>
+ {index < breadcrumbs.length - 1 && <span className="slash-separator" />}
+ </React.Fragment>
+ );
+ });
+}
+
const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => ({
organization:
ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization),
shouldOrganizationBeDisplayed: areThereCustomOrganizations(state)
});
-export default connect(mapStateToProps)(ComponentNavBreadcrumbs);
+export default connect(mapStateToProps)(ComponentNavHeader);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
index 01be74777a6..3b080ac9d4b 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { connect } from 'react-redux';
-import { Branch, Component, CurrentUser, isLoggedIn } from '../../../types';
+import { Branch, Component, CurrentUser, isLoggedIn, HomePageType } from '../../../types';
import BranchStatus from '../../../../components/common/BranchStatus';
import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter';
import Favorite from '../../../../components/controls/Favorite';
@@ -60,14 +60,22 @@ export function ComponentNavMeta({ branch, component, currentUser }: Props) {
{isLoggedIn(currentUser) &&
mainBranch && (
<div className="navbar-context-meta-secondary">
- <Favorite component={component.key} favorite={Boolean(component.isFavorite)} />
+ <Favorite
+ component={component.key}
+ favorite={Boolean(component.isFavorite)}
+ qualifier={component.qualifier}
+ />
<HomePageSelect
className="spacer-left"
- currentPage={{ type: 'project', key: component.key }}
+ currentPage={{ type: HomePageType.Project, parameter: component.key }}
/>
</div>
)}
- {shortBranch && <BranchStatus branch={branch!} />}
+ {shortBranch && (
+ <div className="navbar-context-meta-secondary">
+ <BranchStatus branch={branch!} />
+ </div>
+ )}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx
index 26f876d34f0..4c30ef3b3a4 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx
@@ -29,9 +29,9 @@ jest.mock('../ComponentNavMeta', () => ({
}
}));
-jest.mock('../ComponentNavBreadcrumbs', () => ({
+jest.mock('../ComponentNavHeader', () => ({
// eslint-disable-next-line
- default: function ComponentNavBreadcrumbs() {
+ default: function ComponentNavHeader() {
return null;
}
}));
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavHeader-test.tsx
index 78a2eed1234..89d10f4ac78 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavHeader-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { ComponentNavBreadcrumbs } from '../ComponentNavBreadcrumbs';
+import { ComponentNavHeader } from '../ComponentNavHeader';
import { Visibility } from '../../../../types';
it('should not render breadcrumbs with one element', () => {
@@ -32,7 +32,7 @@ it('should not render breadcrumbs with one element', () => {
visibility: 'public'
};
const result = shallow(
- <ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} />
+ <ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} />
);
expect(result).toMatchSnapshot();
});
@@ -52,7 +52,8 @@ it('should render organization', () => {
projectVisibility: Visibility.Public
};
const result = shallow(
- <ComponentNavBreadcrumbs
+ <ComponentNavHeader
+ branches={[]}
component={component}
organization={organization}
shouldOrganizationBeDisplayed={true}
@@ -71,7 +72,7 @@ it('renders private badge', () => {
visibility: 'private'
};
const result = shallow(
- <ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} />
+ <ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} />
);
expect(result.find('PrivateBadge')).toHaveLength(1);
});
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
index 6fea2eff38e..25470b77544 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap
@@ -27,7 +27,8 @@ exports[`renders 1`] = `
/>
}
>
- <ComponentNavBreadcrumbs
+ <ComponentNavHeader
+ branches={Array []}
component={
Object {
"breadcrumbs": Array [
@@ -43,6 +44,7 @@ exports[`renders 1`] = `
"qualifier": "TRK",
}
}
+ location={Object {}}
/>
<ComponentNavMeta
component={
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap
deleted file mode 100644
index e907a97d1b5..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap
+++ /dev/null
@@ -1,98 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render breadcrumbs with one element 1`] = `
-<header
- className="navbar-context-header"
->
- <OrganizationHelmet
- title="My Project"
- />
- <QualifierIcon
- className="spacer-right"
- key="qualifier-my-project"
- qualifier="TRK"
- />
- <Link
- className="link-base-color link-no-underline"
- key="name-my-project"
- onlyActiveOnIndex={false}
- style={Object {}}
- title="My Project"
- to={
- Object {
- "pathname": "/dashboard",
- "query": Object {
- "branch": undefined,
- "id": "my-project",
- },
- }
- }
- >
- My Project
- </Link>
-</header>
-`;
-
-exports[`should render organization 1`] = `
-<header
- className="navbar-context-header"
->
- <OrganizationHelmet
- organization={
- Object {
- "key": "foo",
- "name": "The Foo Organization",
- "projectVisibility": "public",
- }
- }
- title="My Project"
- />
- <OrganizationAvatar
- organization={
- Object {
- "key": "foo",
- "name": "The Foo Organization",
- "projectVisibility": "public",
- }
- }
- />
- <OrganizationLink
- className="link-base-color link-no-underline spacer-left"
- organization={
- Object {
- "key": "foo",
- "name": "The Foo Organization",
- "projectVisibility": "public",
- }
- }
- >
- The Foo Organization
- </OrganizationLink>
- <span
- className="slash-separator"
- />
- <QualifierIcon
- className="spacer-right"
- key="qualifier-my-project"
- qualifier="TRK"
- />
- <Link
- className="link-base-color link-no-underline"
- key="name-my-project"
- onlyActiveOnIndex={false}
- style={Object {}}
- title="My Project"
- to={
- Object {
- "pathname": "/dashboard",
- "query": Object {
- "branch": undefined,
- "id": "my-project",
- },
- }
- }
- >
- My Project
- </Link>
-</header>
-`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap
new file mode 100644
index 00000000000..eb990ac6401
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap
@@ -0,0 +1,104 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should not render breadcrumbs with one element 1`] = `
+<header
+ className="navbar-context-header"
+>
+ <OrganizationHelmet
+ title="My Project"
+ />
+ <React.Fragment
+ key="my-project"
+ >
+ <QualifierIcon
+ className="spacer-right"
+ qualifier="TRK"
+ />
+ <Link
+ className="link-base-color link-no-underline"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ title="My Project"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": undefined,
+ "id": "my-project",
+ },
+ }
+ }
+ >
+ My Project
+ </Link>
+ </React.Fragment>
+</header>
+`;
+
+exports[`should render organization 1`] = `
+<header
+ className="navbar-context-header"
+>
+ <OrganizationHelmet
+ organization={
+ Object {
+ "key": "foo",
+ "name": "The Foo Organization",
+ "projectVisibility": "public",
+ }
+ }
+ title="My Project"
+ />
+ <React.Fragment>
+ <OrganizationAvatar
+ organization={
+ Object {
+ "key": "foo",
+ "name": "The Foo Organization",
+ "projectVisibility": "public",
+ }
+ }
+ />
+ <OrganizationLink
+ className="link-base-color link-no-underline spacer-left"
+ organization={
+ Object {
+ "key": "foo",
+ "name": "The Foo Organization",
+ "projectVisibility": "public",
+ }
+ }
+ >
+ The Foo Organization
+ </OrganizationLink>
+ <span
+ className="slash-separator"
+ />
+ </React.Fragment>
+ <React.Fragment
+ key="my-project"
+ >
+ <QualifierIcon
+ className="spacer-right"
+ qualifier="TRK"
+ />
+ <Link
+ className="link-base-color link-no-underline"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ title="My Project"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": undefined,
+ "id": "my-project",
+ },
+ }
+ }
+ >
+ My Project
+ </Link>
+ </React.Fragment>
+</header>
+`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
index 726f3168f9f..437ab7a3477 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
@@ -38,20 +38,24 @@ exports[`renders status of short-living branch 1`] = `
date="2017-01-02T00:00:00.000Z"
/>
</div>
- <BranchStatus
- branch={
- Object {
- "isMain": false,
- "mergeBranch": "master",
- "name": "feature",
- "status": Object {
- "bugs": 0,
- "codeSmells": 2,
- "vulnerabilities": 3,
- },
- "type": "SHORT",
+ <div
+ className="navbar-context-meta-secondary"
+ >
+ <BranchStatus
+ branch={
+ Object {
+ "isMain": false,
+ "mergeBranch": "master",
+ "name": "feature",
+ "status": Object {
+ "bugs": 0,
+ "codeSmells": 2,
+ "vulnerabilities": 3,
+ },
+ "type": "SHORT",
+ }
}
- }
- />
+ />
+ </div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/app/styles/components/page.css b/server/sonar-web/src/main/js/app/styles/components/page.css
index 53855c6747f..1ef923cf2b9 100644
--- a/server/sonar-web/src/main/js/app/styles/components/page.css
+++ b/server/sonar-web/src/main/js/app/styles/components/page.css
@@ -17,6 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+.white-page {
+ background-color: #fff !important;
+}
+
.global-container {
display: flex;
flex-direction: column;
@@ -150,7 +154,8 @@
padding-left: calc(50vw - 370px + 10px) !important;
}
-.page-footer-with-sidebar div {
+.page-footer-with-sidebar div,
+.page-footer-with-sidebar .page-footer-menu {
max-width: 980px;
}
diff --git a/server/sonar-web/src/main/js/app/styles/init/base.css b/server/sonar-web/src/main/js/app/styles/init/base.css
index 4b290fb3096..72a57e214d2 100644
--- a/server/sonar-web/src/main/js/app/styles/init/base.css
+++ b/server/sonar-web/src/main/js/app/styles/init/base.css
@@ -26,7 +26,7 @@
html,
body {
- background-color: #fff;
+ background-color: var(--barBackgroundColor);
}
body {
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 2033873f784..407f8237df7 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
@@ -485,6 +485,7 @@ a:hover > .icon-radio {
stroke-width: 1.41421356;
stroke-opacity: 1;
fill-opacity: 0;
+ vector-effect: non-scaling-stroke;
transition: all 0.2s ease;
}
diff --git a/server/sonar-web/src/main/js/app/styles/print.css b/server/sonar-web/src/main/js/app/styles/print.css
index 63fcfb1ee50..696c300636a 100644
--- a/server/sonar-web/src/main/js/app/styles/print.css
+++ b/server/sonar-web/src/main/js/app/styles/print.css
@@ -31,11 +31,10 @@
display: none !important;
}
- .dashboard-page,
- .dashboard-page body {
- background-color: #fff;
+ html,
+ body {
+ background-color: #fff !important;
}
-
.widget thead,
.widget tfoot {
display: table-row-group;
diff --git a/server/sonar-web/src/main/js/app/styles/style.css b/server/sonar-web/src/main/js/app/styles/style.css
index 921f952f4ee..a60b872bbc7 100644
--- a/server/sonar-web/src/main/js/app/styles/style.css
+++ b/server/sonar-web/src/main/js/app/styles/style.css
@@ -17,11 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-.dashboard-page,
-.dashboard-page body {
- background-color: var(--barBackgroundColor);
-}
-
.tabs {
height: 20px;
border-bottom: 1px solid #ddd;
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index 70df316dea2..f9f9be013ac 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -62,13 +62,15 @@ export interface Extension {
name: string;
}
+export interface Breadcrumb {
+ key: string;
+ name: string;
+ qualifier: string;
+}
+
export interface Component {
analysisDate?: string;
- breadcrumbs: Array<{
- key: string;
- name: string;
- qualifier: string;
- }>;
+ breadcrumbs: Breadcrumb[];
configuration?: ComponentConfiguration;
description?: string;
extensions?: Extension[];
@@ -141,13 +143,20 @@ export interface CurrentUser {
showOnboardingTutorial?: boolean;
}
+export enum HomePageType {
+ Project = 'PROJECT',
+ Organization = 'ORGANIZATION',
+ MyProjects = 'MY_PROJECTS',
+ MyIssues = 'MY_ISSUES'
+}
+
export interface HomePage {
- key?: string;
- type: string;
+ parameter?: string;
+ type: HomePageType;
}
export function isSameHomePage(a: HomePage, b: HomePage) {
- return a.type === b.type && a.key === b.key;
+ return a.type === b.type && a.parameter === b.parameter;
}
export interface LoggedInUser extends CurrentUser {
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
index 267d0fc7cf1..d0369971567 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
@@ -76,11 +76,15 @@ class AboutApp extends React.PureComponent {
window.location = 'https://about.sonarcloud.io';
} else {
this.loadData();
+ // $FlowFixMe
+ document.body.classList.add('white-page');
}
}
componentWillUnmount() {
this.mounted = false;
+ // $FlowFixMe
+ document.body.classList.remove('white-page');
}
loadProjects() {
diff --git a/server/sonar-web/src/main/js/apps/account/account.css b/server/sonar-web/src/main/js/apps/account/account.css
index 12c3cabf574..73d42282e13 100644
--- a/server/sonar-web/src/main/js/apps/account/account.css
+++ b/server/sonar-web/src/main/js/apps/account/account.css
@@ -8,7 +8,7 @@
padding-top: 20px;
padding-bottom: 20px;
border-bottom: 1px solid var(--barBorderColor);
- background-color: var(--barBackgroundColor);
+ background-color: #fff;
}
.account-nav {
diff --git a/server/sonar-web/src/main/js/apps/account/components/Password.js b/server/sonar-web/src/main/js/apps/account/components/Password.js
index dec082bc69b..6e3bb3c3c69 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Password.js
+++ b/server/sonar-web/src/main/js/apps/account/components/Password.js
@@ -70,10 +70,10 @@ export default class Password extends Component {
const { success, errors } = this.state;
return (
- <section>
+ <section className="boxed-group">
<h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
- <form onSubmit={this.handleChangePassword}>
+ <form className="boxed-group-inner" onSubmit={this.handleChangePassword}>
{success && (
<div className="alert alert-success">{translate('my_profile.password.changed')}</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/account/components/Security.js b/server/sonar-web/src/main/js/apps/account/components/Security.js
index d52a3b6e1ea..3006ca55f1a 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Security.js
+++ b/server/sonar-web/src/main/js/apps/account/components/Security.js
@@ -31,11 +31,7 @@ function Security(props) {
return (
<div className="account-body account-container">
<Helmet title={translate('my_account.security')} />
-
<Tokens user={user} />
-
- {user.local && <hr className="account-separator" />}
-
{user.local && <Password user={user} />}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
index d7ba3d35197..294c2c209c6 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
@@ -46,30 +46,32 @@ type Props = {
function GlobalNotifications(props /*: Props */) {
return (
- <section>
- <h2 className="spacer-bottom">{translate('my_profile.overall_notifications.title')}</h2>
+ <section className="boxed-group">
+ <h2>{translate('my_profile.overall_notifications.title')}</h2>
- <table className="form">
- <thead>
- <tr>
- <th />
- {props.channels.map(channel => (
- <th key={channel} className="text-center">
- <h4>{translate('notification.channel', channel)}</h4>
- </th>
- ))}
- </tr>
- </thead>
+ <div className="boxed-group-inner">
+ <table className="form">
+ <thead>
+ <tr>
+ <th />
+ {props.channels.map(channel => (
+ <th key={channel} className="text-center">
+ <h4>{translate('notification.channel', channel)}</h4>
+ </th>
+ ))}
+ </tr>
+ </thead>
- <NotificationsList
- notifications={props.notifications}
- channels={props.channels}
- types={props.types}
- checkboxId={(d, c) => `global-notification-${d}-${c}`}
- onAdd={props.addNotification}
- onRemove={props.removeNotification}
- />
- </table>
+ <NotificationsList
+ notifications={props.notifications}
+ channels={props.channels}
+ types={props.types}
+ checkboxId={(d, c) => `global-notification-${d}-${c}`}
+ onAdd={props.addNotification}
+ onRemove={props.removeNotification}
+ />
+ </table>
+ </div>
</section>
);
}
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
index aa2c8d1179e..6e5fed53bcc 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
@@ -40,13 +40,8 @@ class Notifications extends React.PureComponent {
return (
<div className="account-body account-container">
<Helmet title={translate('my_account.notifications')} />
-
- <p className="big-spacer-bottom">{translate('notification.dispatcher.information')}</p>
-
+ <p className="alert alert-info">{translate('notification.dispatcher.information')}</p>
<GlobalNotifications />
-
- <hr className="account-separator" />
-
<Projects />
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
index 14a7f74020c..5345b55591a 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
@@ -113,30 +113,32 @@ class Projects extends React.PureComponent {
const allProjects = [...this.props.projects, ...this.state.addedProjects];
return (
- <section>
- <h2 className="spacer-bottom">{translate('my_profile.per_project_notifications.title')}</h2>
-
- {allProjects.length === 0 && (
- <div className="note">{translate('my_account.no_project_notifications')}</div>
- )}
-
- {allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)}
-
- <div className="spacer-top panel bg-muted">
- <span className="text-middle spacer-right">
- {translate('my_account.set_notifications_for')}:
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- name="new_project"
- style={{ width: '300px' }}
- loadOptions={this.loadOptions}
- minimumInput={2}
- optionRenderer={this.renderOption}
- onChange={this.handleAddProject}
- placeholder={translate('my_account.search_project')}
- />
+ <section className="boxed-group">
+ <h2>{translate('my_profile.per_project_notifications.title')}</h2>
+
+ <div className="boxed-group-inner">
+ {allProjects.length === 0 && (
+ <div className="note">{translate('my_account.no_project_notifications')}</div>
+ )}
+
+ {allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)}
+
+ <div className="spacer-top panel bg-muted">
+ <span className="text-middle spacer-right">
+ {translate('my_account.set_notifications_for')}:
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ name="new_project"
+ style={{ width: '300px' }}
+ loadOptions={this.loadOptions}
+ minimumInput={2}
+ optionRenderer={this.renderOption}
+ onChange={this.handleAddProject}
+ placeholder={translate('my_account.search_project')}
+ />
+ </div>
</div>
</section>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
index 4a7d7d10c5a..64a62011d96 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
@@ -1,69 +1,73 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should match snapshot 1`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.overall_notifications.title
</h2>
- <table
- className="form"
+ <div
+ className="boxed-group-inner"
>
- <thead>
- <tr>
- <th />
- <th
- className="text-center"
- key="channel1"
- >
- <h4>
- notification.channel.channel1
- </h4>
- </th>
- <th
- className="text-center"
- key="channel2"
- >
- <h4>
- notification.channel.channel2
- </h4>
- </th>
- </tr>
- </thead>
- <NotificationsList
- channels={
- Array [
- "channel1",
- "channel2",
- ]
- }
- checkboxId={[Function]}
- notifications={
- Array [
- Object {
- "channel": "channel1",
- "type": "type1",
- },
- Object {
- "channel": "channel1",
- "type": "type2",
- },
- Object {
- "channel": "channel2",
- "type": "type2",
- },
- ]
- }
- onAdd={[Function]}
- onRemove={[Function]}
- types={
- Array [
- "type1",
- "type2",
- ]
- }
- />
- </table>
+ <table
+ className="form"
+ >
+ <thead>
+ <tr>
+ <th />
+ <th
+ className="text-center"
+ key="channel1"
+ >
+ <h4>
+ notification.channel.channel1
+ </h4>
+ </th>
+ <th
+ className="text-center"
+ key="channel2"
+ >
+ <h4>
+ notification.channel.channel2
+ </h4>
+ </th>
+ </tr>
+ </thead>
+ <NotificationsList
+ channels={
+ Array [
+ "channel1",
+ "channel2",
+ ]
+ }
+ checkboxId={[Function]}
+ notifications={
+ Array [
+ Object {
+ "channel": "channel1",
+ "type": "type1",
+ },
+ Object {
+ "channel": "channel1",
+ "type": "type2",
+ },
+ Object {
+ "channel": "channel2",
+ "type": "type2",
+ },
+ ]
+ }
+ onAdd={[Function]}
+ onRemove={[Function]}
+ types={
+ Array [
+ "type1",
+ "type2",
+ ]
+ }
+ />
+ </table>
+ </div>
</section>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
index 8541cc01be7..855ccecb356 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
@@ -10,14 +10,11 @@ exports[`should match snapshot 1`] = `
title="my_account.notifications"
/>
<p
- className="big-spacer-bottom"
+ className="alert alert-info"
>
notification.dispatcher.information
</p>
<Connect(GlobalNotifications) />
- <hr
- className="account-separator"
- />
<Connect(Projects) />
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
index 3d6b8b28eb1..7f2fb250868 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
@@ -1,178 +1,190 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render projects 1`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
Object {
- "width": "300px",
+ "key": "bar",
+ "name": "Bar",
}
}
/>
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
exports[`should render projects 2`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="qux"
- project={
- Object {
- "key": "qux",
- "name": "Qux",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
+ Object {
+ "key": "bar",
+ "name": "Bar",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="qux"
+ project={
Object {
- "width": "300px",
+ "key": "qux",
+ "name": "Qux",
}
}
/>
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
exports[`should render projects 3`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="qux"
- project={
- Object {
- "key": "qux",
- "name": "Qux",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
Object {
- "width": "300px",
+ "key": "foo",
+ "name": "Foo",
}
}
/>
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
+ Object {
+ "key": "bar",
+ "name": "Bar",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="qux"
+ project={
+ Object {
+ "key": "qux",
+ "name": "Qux",
+ }
+ }
+ />
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
index 5b0b8ccc367..42273f32553 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
@@ -21,12 +21,17 @@ import * as React from 'react';
import { sortBy } from 'lodash';
import OrganizationCard from './OrganizationCard';
import { Organization } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
interface Props {
organizations: Organization[];
}
export default function OrganizationsList({ organizations }: Props) {
+ if (organizations.length === 0) {
+ return <div>{translate('my_account.organizations.no_results')}</div>;
+ }
+
return (
<ul className="account-projects-list">
{sortBy(organizations, organization => organization.name.toLocaleLowerCase()).map(
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
index e6f34fbd8e2..d63555b1574 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
@@ -87,29 +87,22 @@ class UserOrganizations extends React.PureComponent<Props, State> {
<div className="account-body account-container">
<Helmet title={translate('my_account.organizations')} />
- <header className="page-header">
- <h2 className="page-title">{translate('my_account.organizations')}</h2>
+ <div className="boxed-group">
{canCreateOrganizations && (
- <div className="page-actions">
- <button onClick={this.handleCreateClick}>{translate('create')}</button>
+ <div className="clearfix">
+ <div className="boxed-group-actions">
+ <button onClick={this.handleCreateClick}>{translate('create')}</button>
+ </div>
</div>
)}
- {this.props.organizations.length > 0 ? (
- <div className="page-description">
- {translate('my_account.organizations.description')}
- </div>
- ) : (
- <div className="page-description">
- {translate('my_account.organizations.no_results')}
- </div>
- )}
- </header>
-
- {this.state.loading ? (
- <i className="spinner" />
- ) : (
- <OrganizationsList organizations={this.props.organizations} />
- )}
+ <div className="boxed-group-inner">
+ {this.state.loading ? (
+ <i className="spinner" />
+ ) : (
+ <OrganizationsList organizations={this.props.organizations} />
+ )}
+ </div>
+ </div>
{this.state.createOrganization && (
<CreateOrganizationForm
diff --git a/server/sonar-web/src/main/js/apps/account/profile/Profile.js b/server/sonar-web/src/main/js/apps/account/profile/Profile.js
index 4996bfcd124..464f549d5bd 100644
--- a/server/sonar-web/src/main/js/apps/account/profile/Profile.js
+++ b/server/sonar-web/src/main/js/apps/account/profile/Profile.js
@@ -45,29 +45,31 @@ function Profile(props /*: Props */) {
return (
<div className="account-body account-container">
- <div className="spacer-bottom">
- {translate('login')}: <strong id="login">{user.login}</strong>
- </div>
+ <div className="boxed-group boxed-group-inner">
+ <div className="spacer-bottom">
+ {translate('login')}: <strong id="login">{user.login}</strong>
+ </div>
+
+ {!user.local &&
+ user.externalProvider !== 'sonarqube' && (
+ <div id="identity-provider" className="spacer-bottom">
+ <UserExternalIdentity user={user} />
+ </div>
+ )}
- {!user.local &&
- user.externalProvider !== 'sonarqube' && (
- <div id="identity-provider" className="spacer-bottom">
- <UserExternalIdentity user={user} />
+ {!!user.email && (
+ <div className="spacer-bottom">
+ {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
</div>
)}
- {!!user.email && (
- <div className="spacer-bottom">
- {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
- </div>
- )}
+ {!customOrganizations && <hr className="account-separator" />}
+ {!customOrganizations && <UserGroups groups={user.groups} />}
- {!customOrganizations && <hr className="account-separator" />}
- {!customOrganizations && <UserGroups groups={user.groups} />}
+ <hr />
- <hr className="account-separator" />
-
- <UserScmAccounts user={user} scmAccounts={user.scmAccounts} />
+ <UserScmAccounts user={user} scmAccounts={user.scmAccounts} />
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs b/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
index 2c8da3e0297..65bbf91e160 100644
--- a/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
+++ b/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
@@ -1,77 +1,81 @@
-<h2 class="spacer-bottom">{{t 'users.tokens'}}</h2>
+<div class="boxed-group">
+ <h2>{{t 'users.tokens'}}</h2>
-<div class="big-spacer-bottom big-spacer-right markdown">
- <p>{{t 'my_account.tokens_description'}}</p>
-</div>
+<div class="boxed-group-inner">
+ <div class="big-spacer-bottom big-spacer-right markdown">
+ <p>{{t 'my_account.tokens_description'}}</p>
+ </div>
-{{#notNull tokens}}
- <table class="data">
- <thead>
- <tr>
- <th>{{t 'name'}}</th>
- <th class="text-right">{{t 'created'}}</th>
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tbody>
- {{#each tokens}}
- <tr>
- <td>
- <div title="{{name}}">
- {{limitString name}}
- </div>
- </td>
- <td class="thin nowrap text-right">
- {{d createdAt}}
- </td>
- <td class="thin nowrap text-right">
- <div class="big-spacer-left">
- <form class="js-revoke-token-form" data-token="{{name}}">
- {{#if deleting}}
- <button class="button-red active input-small">{{t 'users.tokens.sure'}}</button>
- {{else}}
- <button class="button-red input-small">{{t 'users.tokens.revoke'}}</button>
- {{/if}}
- </form>
- </div>
- </td>
- </tr>
- {{else}}
+ {{#notNull tokens}}
+ <table class="data">
+ <thead>
<tr>
- <td colspan="3">
- <span class="note">{{t 'users.no_tokens'}}</span>
- </td>
+ <th>{{t 'name'}}</th>
+ <th class="text-right">{{t 'created'}}</th>
+ <th>&nbsp;</th>
</tr>
- {{/each}}
- </tbody>
- </table>
-{{/notNull}}
+ </thead>
+ <tbody>
+ {{#each tokens}}
+ <tr>
+ <td>
+ <div title="{{name}}">
+ {{limitString name}}
+ </div>
+ </td>
+ <td class="thin nowrap text-right">
+ {{d createdAt}}
+ </td>
+ <td class="thin nowrap text-right">
+ <div class="big-spacer-left">
+ <form class="js-revoke-token-form" data-token="{{name}}">
+ {{#if deleting}}
+ <button class="button-red active input-small">{{t 'users.tokens.sure'}}</button>
+ {{else}}
+ <button class="button-red input-small">{{t 'users.tokens.revoke'}}</button>
+ {{/if}}
+ </form>
+ </div>
+ </td>
+ </tr>
+ {{else}}
+ <tr>
+ <td colspan="3">
+ <span class="note">{{t 'users.no_tokens'}}</span>
+ </td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+ {{/notNull}}
-{{#each errors}}
- <div class="alert alert-danger">{{msg}}</div>
-{{/each}}
+ {{#each errors}}
+ <div class="alert alert-danger">{{msg}}</div>
+ {{/each}}
-<form class="js-generate-token-form spacer-top panel bg-muted">
- <label>{{t 'users.generate_new_token'}}:</label>
- <input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}">
- <button>{{t 'users.generate'}}</button>
-</form>
+ <form class="js-generate-token-form spacer-top panel bg-muted">
+ <label>{{t 'users.generate_new_token'}}:</label>
+ <input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}">
+ <button>{{t 'users.generate'}}</button>
+ </form>
-{{#if newToken}}
- <div class="panel panel-white big-spacer-top">
- <div class="alert alert-warning">
- {{tp 'users.tokens.new_token_created' newToken.name}}
- </div>
+ {{#if newToken}}
+ <div class="panel panel-white big-spacer-top">
+ <div class="alert alert-warning">
+ {{tp 'users.tokens.new_token_created' newToken.name}}
+ </div>
- <table class="data">
- <tr>
- <td class="thin">
- <button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button>
- </td>
- <td class="nowrap">
- <div class="monospaced text-success">{{newToken.token}}</div>
- </td>
- </tr>
- </table>
- </div>
-{{/if}}
+ <table class="data">
+ <tr>
+ <td class="thin">
+ <button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button>
+ </td>
+ <td class="nowrap">
+ <div class="monospaced text-success">{{newToken.token}}</div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ {{/if}}
+</div>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
index 0f0f843a1f5..56f9d0508db 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
@@ -49,34 +49,36 @@ export default class Tasks extends React.PureComponent {
});
return (
- <table className={className}>
- <thead>
- <tr>
- <th>{translate('background_tasks.table.status')}</th>
- <th>{translate('background_tasks.table.task')}</th>
- <th>{translate('background_tasks.table.id')}</th>
- <th>&nbsp;</th>
- <th className="text-right">{translate('background_tasks.table.submitted')}</th>
- <th className="text-right">{translate('background_tasks.table.started')}</th>
- <th className="text-right">{translate('background_tasks.table.finished')}</th>
- <th className="text-right">{translate('background_tasks.table.duration')}</th>
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tbody>
- {tasks.map((task, index, tasks) => (
- <Task
- key={task.id}
- task={task}
- tasks={tasks}
- component={component}
- onCancelTask={onCancelTask}
- onFilterTask={onFilterTask}
- previousTask={index > 0 ? tasks[index - 1] : undefined}
- />
- ))}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table className={className}>
+ <thead>
+ <tr>
+ <th>{translate('background_tasks.table.status')}</th>
+ <th>{translate('background_tasks.table.task')}</th>
+ <th>{translate('background_tasks.table.id')}</th>
+ <th>&nbsp;</th>
+ <th className="text-right">{translate('background_tasks.table.submitted')}</th>
+ <th className="text-right">{translate('background_tasks.table.started')}</th>
+ <th className="text-right">{translate('background_tasks.table.finished')}</th>
+ <th className="text-right">{translate('background_tasks.table.duration')}</th>
+ <th>&nbsp;</th>
+ </tr>
+ </thead>
+ <tbody>
+ {tasks.map((task, index, tasks) => (
+ <Task
+ key={task.id}
+ task={task}
+ tasks={tasks}
+ component={component}
+ onCancelTask={onCancelTask}
+ onFilterTask={onFilterTask}
+ previousTask={index > 0 ? tasks[index - 1] : undefined}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/code/components/App.tsx b/server/sonar-web/src/main/js/apps/code/components/App.tsx
index 77110f20481..0a5f41af961 100644
--- a/server/sonar-web/src/main/js/apps/code/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/code/components/App.tsx
@@ -200,7 +200,9 @@ export default class App extends React.PureComponent<Props, State> {
const shouldShowBreadcrumbs = breadcrumbs.length > 1;
- const componentsClassName = classNames('spacer-top', { 'new-loading': loading });
+ const componentsClassName = classNames('boxed-group', 'boxed-group-inner', 'spacer-top', {
+ 'new-loading': loading
+ });
return (
<div className="page page-limited">
diff --git a/server/sonar-web/src/main/js/apps/code/components/Search.tsx b/server/sonar-web/src/main/js/apps/code/components/Search.tsx
index 14539241c9a..fba3a124f5d 100644
--- a/server/sonar-web/src/main/js/apps/code/components/Search.tsx
+++ b/server/sonar-web/src/main/js/apps/code/components/Search.tsx
@@ -182,12 +182,14 @@ export default class Search extends React.PureComponent<Props, State> {
{loading && <i className="spinner spacer-left" />}
{results != null && (
- <Components
- branch={this.props.branch}
- components={results}
- rootComponent={component}
- selected={selected}
- />
+ <div className="boxed-group boxed-group-inner spacer-top">
+ <Components
+ branch={this.props.branch}
+ components={results}
+ rootComponent={component}
+ selected={selected}
+ />
+ </div>
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
index 7b8eb343c90..1c578244c01 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
@@ -44,6 +44,9 @@ class CodingRulesAppContainer extends React.PureComponent {
*/
componentDidMount() {
+ // $FlowFixMe
+ document.body.classList.add('white-page');
+
if (this.props.appState.organizationsEnabled && !this.props.params.organizationKey) {
// redirect to organization-level rules page
this.props.router.replace(
@@ -62,6 +65,9 @@ class CodingRulesAppContainer extends React.PureComponent {
}
componentWillUnmount() {
+ // $FlowFixMe
+ document.body.classList.remove('white-page');
+
if (this.stop) {
this.stop();
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.js b/server/sonar-web/src/main/js/apps/component-measures/components/App.js
index 84bd294f9e9..7611ea8b4c8 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/App.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/App.js
@@ -74,6 +74,8 @@ export default class App extends React.PureComponent {
componentDidMount() {
this.mounted = true;
+ // $FlowFixMe
+ document.body.classList.add('white-page');
this.props.fetchMetrics();
this.fetchMeasures(this.props);
key.setScope('measures-files');
@@ -95,6 +97,8 @@ export default class App extends React.PureComponent {
componentWillUnmount() {
this.mounted = false;
+ // $FlowFixMe
+ document.body.classList.remove('white-page');
key.deleteScope('measures-files');
const footer = document.getElementById('footer');
if (footer) {
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list.hbs
index 20ca1491fa3..97c513248eb 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list.hbs
+++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list.hbs
@@ -1,12 +1,14 @@
-<table class="data zebra">
- <thead>
- <tr>
- <th>{{t 'custom_measures.metric'}}</th>
- <th>{{t 'value'}}</th>
- <th>{{t 'description'}}</th>
- <th>{{t 'date'}}</th>
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tbody></tbody>
-</table>
+<div class="boxed-group boxed-group-inner">
+ <table class="data zebra">
+ <thead>
+ <tr>
+ <th>{{t 'custom_measures.metric'}}</th>
+ <th>{{t 'value'}}</th>
+ <th>{{t 'description'}}</th>
+ <th>{{t 'date'}}</th>
+ <th>&nbsp;</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs
index b96143e7caa..ac23f3c1f65 100644
--- a/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs
@@ -1,4 +1,4 @@
-<div>
+<div class="boxed-group boxed-group-inner">
{{#isNull organization}}
<div class="panel panel-vertical js-anyone">
<div class="display-inline-block text-top width-20">
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs
index e0d8614362f..ecf034da48e 100644
--- a/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs
@@ -1,4 +1,4 @@
-<div class="panel panel-vertical bordered-bottom spacer-bottom">
+<div class="big-spacer-bottom">
<form id="groups-search-form" class="search-box">
<input id="groups-search-query" class="search-box-input" type="text" name="q" placeholder="{{t 'search.search_by_name'}}" maxlength="100">
<svg class="search-box-magnifier" width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.js b/server/sonar-web/src/main/js/apps/issues/components/App.js
index cc68fbb41c9..c13b7a9b0ff 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/App.js
+++ b/server/sonar-web/src/main/js/apps/issues/components/App.js
@@ -151,6 +151,9 @@ export default class App extends React.PureComponent {
return;
}
+ // $FlowFixMe
+ document.body.classList.add('white-page');
+
const footer = document.getElementById('footer');
if (footer) {
footer.classList.add('page-footer-with-sidebar');
@@ -206,6 +209,9 @@ export default class App extends React.PureComponent {
componentWillUnmount() {
this.detachShortcuts();
+ // $FlowFixMe
+ document.body.classList.remove('white-page');
+
const footer = document.getElementById('footer');
if (footer) {
footer.classList.remove('page-footer-with-sidebar');
diff --git a/server/sonar-web/src/main/js/apps/issues/components/PageActions.js b/server/sonar-web/src/main/js/apps/issues/components/PageActions.js
index 2aaca8517e8..b800d271f3f 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/PageActions.js
+++ b/server/sonar-web/src/main/js/apps/issues/components/PageActions.js
@@ -22,6 +22,7 @@ import React from 'react';
import IssuesCounter from './IssuesCounter';
import ReloadButton from './ReloadButton';
/*:: import type { Paging } from '../utils'; */
+import { HomePageType } from '../../../app/types';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import HomePageSelect from '../../../components/controls/HomePageSelect';
import { translate } from '../../../helpers/l10n';
@@ -74,7 +75,10 @@ export default class PageActions extends React.PureComponent {
</div>
{this.props.canSetHome && (
- <HomePageSelect className="huge-spacer-left" currentPage={{ type: 'my-issues' }} />
+ <HomePageSelect
+ className="huge-spacer-left"
+ currentPage={{ type: HomePageType.MyIssues }}
+ />
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx b/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx
index 48924aba04e..c41ac4bf516 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx
@@ -79,7 +79,7 @@ export default class PluginsList extends React.PureComponent<Props> {
render() {
return (
- <div id="marketplace-plugins">
+ <div className="boxed-group boxed-group-inner" id="marketplace-plugins">
<ul>
{this.props.plugins.map(plugin => (
<li key={plugin.key} className="panel panel-vertical">
diff --git a/server/sonar-web/src/main/js/apps/marketplace/Search.tsx b/server/sonar-web/src/main/js/apps/marketplace/Search.tsx
index 1eaef17728e..c114ebb6643 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/Search.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/Search.tsx
@@ -48,7 +48,7 @@ export default class Search extends React.PureComponent<Props> {
}
];
return (
- <div id="marketplace-search" className="panel panel-vertical bordered-bottom spacer-bottom">
+ <div id="marketplace-search" className="big-spacer-bottom">
<div className="display-inline-block text-top nowrap abs-width-150 spacer-right">
<RadioToggle
name="marketplace-filter"
diff --git a/server/sonar-web/src/main/js/apps/marketplace/style.css b/server/sonar-web/src/main/js/apps/marketplace/style.css
index b435f1c3367..35aee754fed 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/style.css
+++ b/server/sonar-web/src/main/js/apps/marketplace/style.css
@@ -12,7 +12,6 @@
display: flex;
flex-direction: column;
justify-content: space-between;
- background-color: #f3f3f3;
margin-left: 8px;
margin-right: 8px;
}
diff --git a/server/sonar-web/src/main/js/apps/metrics/templates/metrics-layout.hbs b/server/sonar-web/src/main/js/apps/metrics/templates/metrics-layout.hbs
index 9aeeeede6b3..179ee3ed067 100644
--- a/server/sonar-web/src/main/js/apps/metrics/templates/metrics-layout.hbs
+++ b/server/sonar-web/src/main/js/apps/metrics/templates/metrics-layout.hbs
@@ -1,5 +1,5 @@
<div class="page page-limited">
<div id="metrics-header"></div>
- <div id="metrics-list"></div>
+ <div id="metrics-list" class="boxed-group boxed-group-inner"></div>
<div id="metrics-list-footer"></div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js
index c40344c98bd..af7bf261a15 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js
@@ -38,20 +38,22 @@ export default class MembersList extends React.PureComponent {
render() {
return (
- <table className="data zebra">
- <tbody>
- {this.props.members.map(member => (
- <MembersListItem
- key={member.login}
- member={member}
- organizationGroups={this.props.organizationGroups}
- organization={this.props.organization}
- removeMember={this.props.removeMember}
- updateMemberGroups={this.props.updateMemberGroups}
- />
- ))}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table className="data zebra">
+ <tbody>
+ {this.props.members.map(member => (
+ <MembersListItem
+ key={member.login}
+ member={member}
+ organizationGroups={this.props.organizationGroups}
+ organization={this.props.organization}
+ removeMember={this.props.removeMember}
+ updateMemberGroups={this.props.updateMemberGroups}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js
index 5f7a3c867ef..92ceb30e062 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js
@@ -107,87 +107,89 @@ class OrganizationEdit extends React.PureComponent {
<h1 className="page-title">{title}</h1>
</header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-field">
- <label htmlFor="organization-name">
- {translate('organization.name')}
- <em className="mandatory">*</em>
- </label>
- <input
- id="organization-name"
- name="name"
- required={true}
- type="text"
- maxLength="64"
- value={this.state.name}
- disabled={this.state.loading}
- onChange={e => this.setState({ name: e.target.value })}
- />
- <div className="modal-field-description">
- {translate('organization.name.description')}
- </div>
- </div>
- <div className="modal-field">
- <label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
- <input
- id="organization-avatar"
- name="avatar"
- type="text"
- maxLength="256"
- value={this.state.avatar}
- disabled={this.state.loading}
- onChange={this.handleAvatarInputChange}
- />
- <div className="modal-field-description">
- {translate('organization.avatar.description')}
+ <div className="boxed-group boxed-group-inner">
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-field">
+ <label htmlFor="organization-name">
+ {translate('organization.name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ id="organization-name"
+ name="name"
+ required={true}
+ type="text"
+ maxLength="64"
+ value={this.state.name}
+ disabled={this.state.loading}
+ onChange={e => this.setState({ name: e.target.value })}
+ />
+ <div className="modal-field-description">
+ {translate('organization.name.description')}
+ </div>
</div>
- {!!this.state.avatarImage && (
- <div className="spacer-top spacer-bottom">
- <div className="little-spacer-bottom">
- {translate('organization.avatar.preview')}
- {':'}
+ <div className="modal-field">
+ <label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
+ <input
+ id="organization-avatar"
+ name="avatar"
+ type="text"
+ maxLength="256"
+ value={this.state.avatar}
+ disabled={this.state.loading}
+ onChange={this.handleAvatarInputChange}
+ />
+ <div className="modal-field-description">
+ {translate('organization.avatar.description')}
+ </div>
+ {!!this.state.avatarImage && (
+ <div className="spacer-top spacer-bottom">
+ <div className="little-spacer-bottom">
+ {translate('organization.avatar.preview')}
+ {':'}
+ </div>
+ <img src={this.state.avatarImage} alt="" height={30} />
</div>
- <img src={this.state.avatarImage} alt="" height={30} />
+ )}
+ </div>
+ <div className="modal-field">
+ <label htmlFor="organization-description">{translate('description')}</label>
+ <textarea
+ id="organization-description"
+ name="description"
+ rows="3"
+ maxLength="256"
+ value={this.state.description}
+ disabled={this.state.loading}
+ onChange={e => this.setState({ description: e.target.value })}
+ />
+ <div className="modal-field-description">
+ {translate('organization.description.description')}
+ </div>
+ </div>
+ <div className="modal-field">
+ <label htmlFor="organization-url">{translate('organization.url')}</label>
+ <input
+ id="organization-url"
+ name="url"
+ type="text"
+ maxLength="256"
+ value={this.state.url}
+ disabled={this.state.loading}
+ onChange={e => this.setState({ url: e.target.value })}
+ />
+ <div className="modal-field-description">
+ {translate('organization.url.description')}
</div>
- )}
- </div>
- <div className="modal-field">
- <label htmlFor="organization-description">{translate('description')}</label>
- <textarea
- id="organization-description"
- name="description"
- rows="3"
- maxLength="256"
- value={this.state.description}
- disabled={this.state.loading}
- onChange={e => this.setState({ description: e.target.value })}
- />
- <div className="modal-field-description">
- {translate('organization.description.description')}
</div>
- </div>
- <div className="modal-field">
- <label htmlFor="organization-url">{translate('organization.url')}</label>
- <input
- id="organization-url"
- name="url"
- type="text"
- maxLength="256"
- value={this.state.url}
- disabled={this.state.loading}
- onChange={e => this.setState({ url: e.target.value })}
- />
- <div className="modal-field-description">
- {translate('organization.url.description')}
+ <div className="modal-field">
+ <button type="submit" disabled={this.state.loading}>
+ {translate('save')}
+ </button>
+ {this.state.loading && <i className="spinner spacer-left" />}
</div>
- </div>
- <div className="modal-field">
- <button type="submit" disabled={this.state.loading}>
- {translate('save')}
- </button>
- {this.state.loading && <i className="spinner spacer-left" />}
- </div>
- </form>
+ </form>
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap
index 4bc29637672..fc8f227d95e 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap
@@ -1,44 +1,48 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render a list of members of an organization 1`] = `
-<table
- className="data zebra"
+<div
+ className="boxed-group boxed-group-inner"
>
- <tbody>
- <MembersListItem
- key="admin"
- member={
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
+ <table
+ className="data zebra"
+ >
+ <tbody>
+ <MembersListItem
+ key="admin"
+ member={
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ }
}
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
}
- }
- />
- <MembersListItem
- key="john"
- member={
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
+ />
+ <MembersListItem
+ key="john"
+ member={
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "groupCount": 1,
+ "login": "john",
+ "name": "John Doe",
+ }
}
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
}
- }
- />
- </tbody>
-</table>
+ />
+ </tbody>
+ </table>
+</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap
index 9dc712473f2..9c18fd59ac8 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap
@@ -18,118 +18,122 @@ exports[`smoke test 1`] = `
organization.edit
</h1>
</header>
- <form
- onSubmit={[Function]}
+ <div
+ className="boxed-group boxed-group-inner"
>
- <div
- className="modal-field"
+ <form
+ onSubmit={[Function]}
>
- <label
- htmlFor="organization-name"
+ <div
+ className="modal-field"
>
- organization.name
- <em
- className="mandatory"
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={false}
+ id="organization-name"
+ maxLength="64"
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="Foo"
+ />
+ <div
+ className="modal-field-description"
>
- *
- </em>
- </label>
- <input
- disabled={false}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="Foo"
- />
+ organization.name.description
+ </div>
+ </div>
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.name.description
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={false}
+ id="organization-avatar"
+ maxLength="256"
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={false}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value=""
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.avatar.description
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={false}
+ id="organization-description"
+ maxLength="256"
+ name="description"
+ onChange={[Function]}
+ rows="3"
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.description.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={false}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value=""
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.description.description
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={false}
+ id="organization-url"
+ maxLength="256"
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={false}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value=""
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.url.description
+ <button
+ disabled={false}
+ type="submit"
+ >
+ save
+ </button>
</div>
- </div>
- <div
- className="modal-field"
- >
- <button
- disabled={false}
- type="submit"
- >
- save
- </button>
- </div>
- </form>
+ </form>
+ </div>
</div>
`;
@@ -151,133 +155,137 @@ exports[`smoke test 2`] = `
organization.edit
</h1>
</header>
- <form
- onSubmit={[Function]}
+ <div
+ className="boxed-group boxed-group-inner"
>
- <div
- className="modal-field"
+ <form
+ onSubmit={[Function]}
>
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- disabled={false}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.name.description
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={false}
+ id="organization-name"
+ maxLength="64"
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="New Foo"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.name.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={false}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value="foo-avatar"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.avatar.description
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={false}
+ id="organization-avatar"
+ maxLength="256"
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value="foo-avatar"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
+ <div
+ className="spacer-top spacer-bottom"
+ >
+ <div
+ className="little-spacer-bottom"
+ >
+ organization.avatar.preview
+ :
+ </div>
+ <img
+ alt=""
+ height={30}
+ src="foo-avatar-image"
+ />
+ </div>
</div>
<div
- className="spacer-top spacer-bottom"
+ className="modal-field"
>
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={false}
+ id="organization-description"
+ maxLength="256"
+ name="description"
+ onChange={[Function]}
+ rows="3"
+ value="foo-description"
+ />
<div
- className="little-spacer-bottom"
+ className="modal-field-description"
>
- organization.avatar.preview
- :
+ organization.description.description
</div>
- <img
- alt=""
- height={30}
- src="foo-avatar-image"
- />
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={false}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value="foo-description"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.description.description
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={false}
+ id="organization-url"
+ maxLength="256"
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value="foo-url"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={false}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.url.description
+ <button
+ disabled={false}
+ type="submit"
+ >
+ save
+ </button>
</div>
- </div>
- <div
- className="modal-field"
- >
- <button
- disabled={false}
- type="submit"
- >
- save
- </button>
- </div>
- </form>
+ </form>
+ </div>
</div>
`;
@@ -299,135 +307,139 @@ exports[`smoke test 3`] = `
organization.edit
</h1>
</header>
- <form
- onSubmit={[Function]}
+ <div
+ className="boxed-group boxed-group-inner"
>
- <div
- className="modal-field"
+ <form
+ onSubmit={[Function]}
>
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- disabled={true}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.name.description
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={true}
+ id="organization-name"
+ maxLength="64"
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="New Foo"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.name.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={true}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value="foo-avatar"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.avatar.description
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={true}
+ id="organization-avatar"
+ maxLength="256"
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value="foo-avatar"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
+ <div
+ className="spacer-top spacer-bottom"
+ >
+ <div
+ className="little-spacer-bottom"
+ >
+ organization.avatar.preview
+ :
+ </div>
+ <img
+ alt=""
+ height={30}
+ src="foo-avatar-image"
+ />
+ </div>
</div>
<div
- className="spacer-top spacer-bottom"
+ className="modal-field"
>
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={true}
+ id="organization-description"
+ maxLength="256"
+ name="description"
+ onChange={[Function]}
+ rows="3"
+ value="foo-description"
+ />
<div
- className="little-spacer-bottom"
+ className="modal-field-description"
>
- organization.avatar.preview
- :
+ organization.description.description
</div>
- <img
- alt=""
- height={30}
- src="foo-avatar-image"
- />
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={true}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value="foo-description"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.description.description
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={true}
+ id="organization-url"
+ maxLength="256"
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value="foo-url"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
</div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={true}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
<div
- className="modal-field-description"
+ className="modal-field"
>
- organization.url.description
+ <button
+ disabled={true}
+ type="submit"
+ >
+ save
+ </button>
+ <i
+ className="spinner spacer-left"
+ />
</div>
- </div>
- <div
- className="modal-field"
- >
- <button
- disabled={true}
- type="submit"
- >
- save
- </button>
- <i
- className="spinner spacer-left"
- />
- </div>
- </form>
+ </form>
+ </div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx
index 077cc4a67ee..eb49059477f 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx
@@ -18,15 +18,21 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { Organization } from '../../../app/types';
+import { connect } from 'react-redux';
+import { Organization, HomePageType } from '../../../app/types';
import HomePageSelect from '../../../components/controls/HomePageSelect';
import { translate } from '../../../helpers/l10n';
+import { getGlobalSettingValue } from '../../../store/rootReducer';
-interface Props {
+interface StateProps {
+ onSonarCloud: boolean;
+}
+
+interface Props extends StateProps {
organization: Organization;
}
-export default function OrganizationNavigationMeta({ organization }: Props) {
+export function OrganizationNavigationMeta({ onSonarCloud, organization }: Props) {
return (
<div className="navbar-context-meta">
{organization.url != null && (
@@ -41,9 +47,23 @@ export default function OrganizationNavigationMeta({ organization }: Props) {
<div className="text-muted">
<strong>{translate('organization.key')}:</strong> {organization.key}
</div>
- <div className="navbar-context-meta-secondary">
- <HomePageSelect currentPage={{ type: 'organization', key: organization.key }} />
- </div>
+ {onSonarCloud && (
+ <div className="navbar-context-meta-secondary">
+ <HomePageSelect
+ currentPage={{ type: HomePageType.Organization, parameter: organization.key }}
+ />
+ </div>
+ )}
</div>
);
}
+
+const mapStateToProps = (state: any): StateProps => {
+ const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled');
+
+ return {
+ onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true')
+ };
+};
+
+export default connect(mapStateToProps)(OrganizationNavigationMeta);
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx
index 5b69f2c4853..ef2d8fca1dd 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx
@@ -19,13 +19,14 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import OrganizationNavigationMeta from '../OrganizationNavigationMeta';
+import { OrganizationNavigationMeta } from '../OrganizationNavigationMeta';
import { Visibility } from '../../../../app/types';
it('renders', () => {
expect(
shallow(
<OrganizationNavigationMeta
+ onSonarCloud={true}
organization={{
key: 'foo',
name: 'Foo',
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
index eb04cc431fe..07512698807 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
@@ -14,7 +14,7 @@ exports[`render 1`] = `
}
}
/>
- <OrganizationNavigationMeta
+ <Connect(OrganizationNavigationMeta)
organization={
Object {
"key": "foo",
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap
index bdd7594127b..207f8fe1faf 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap
@@ -20,8 +20,8 @@ exports[`renders 1`] = `
<Connect(HomePageSelect)
currentPage={
Object {
- "key": "foo",
- "type": "organization",
+ "parameter": "foo",
+ "type": "ORGANIZATION",
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js
index d5cb1b15caf..16d88755c47 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js
+++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js
@@ -68,10 +68,6 @@ export default class OverviewApp extends React.PureComponent {
componentDidMount() {
this.mounted = true;
- const domElement = document.querySelector('html');
- if (domElement) {
- domElement.classList.add('dashboard-page');
- }
this.loadMeasures().then(this.loadHistory);
}
@@ -86,10 +82,6 @@ export default class OverviewApp extends React.PureComponent {
componentWillUnmount() {
this.mounted = false;
- const domElement = document.querySelector('html');
- if (domElement) {
- domElement.classList.remove('dashboard-page');
- }
}
loadMeasures() {
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/List.js b/server/sonar-web/src/main/js/apps/permission-templates/components/List.js
index 9448e9d5797..97182a9b41c 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/List.js
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/List.js
@@ -44,10 +44,12 @@ export default class List extends React.PureComponent {
));
return (
- <table id="permission-templates" className="data zebra permissions-table">
- <ListHeader organization={this.props.organization} permissions={this.props.permissions} />
- <tbody>{permissionTemplates}</tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table id="permission-templates" className="data zebra permissions-table">
+ <ListHeader organization={this.props.organization} permissions={this.props.permissions} />
+ <tbody>{permissionTemplates}</tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
index 189351ba346..798e2156ceb 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/HoldersList.tsx
@@ -92,14 +92,16 @@ export default class HoldersList extends React.PureComponent<Props> {
));
return (
- <table className="data zebra permissions-table">
- {this.renderTableHeader()}
- <tbody>
- {users.length === 0 && groups.length === 0 && this.renderEmpty()}
- {users}
- {groups}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table className="data zebra permissions-table">
+ {this.renderTableHeader()}
+ <tbody>
+ {users.length === 0 && groups.length === 0 && this.renderEmpty()}
+ {users}
+ {groups}
+ </tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx
index 9f1ee5f2a76..f4074fa61a1 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/App.tsx
@@ -50,10 +50,6 @@ export default class App extends React.PureComponent<Props, State> {
componentDidMount() {
this.mounted = true;
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
this.fetchData();
}
@@ -65,10 +61,6 @@ export default class App extends React.PureComponent<Props, State> {
componentWillUnmount() {
this.mounted = false;
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
}
fetchData() {
diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js b/server/sonar-web/src/main/js/apps/project-admin/key/Key.js
index e94839f6b2e..0288b2e9fb5 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/key/Key.js
@@ -101,7 +101,7 @@ class Key extends React.PureComponent {
)}
{hasModules && (
- <div>
+ <div className="boxed-group boxed-group-inner">
<div className="big-spacer-bottom">
<ul className="tabs">
<li>
diff --git a/server/sonar-web/src/main/js/apps/project-admin/links/Table.js b/server/sonar-web/src/main/js/apps/project-admin/links/Table.js
index 580413d4d1f..453c93ad44a 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/links/Table.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/links/Table.js
@@ -54,10 +54,12 @@ export default class Table extends React.PureComponent {
));
return (
- <table id="project-links" className="data zebra">
- {this.renderHeader()}
- <tbody>{linkRows}</tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table id="project-links" className="data zebra">
+ {this.renderHeader()}
+ <tbody>{linkRows}</tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
index 080842999d8..70c931e1cf7 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
@@ -94,8 +94,6 @@ export default class ProjectActivityAppContainer extends React.PureComponent {
componentDidMount() {
this.mounted = true;
- const elem = document.querySelector('html');
- elem && elem.classList.add('dashboard-page');
if (this.shouldRedirect()) {
const newQuery = { ...this.state.query, graph: getGraph() };
if (isCustomGraph(newQuery.graph)) {
@@ -129,8 +127,6 @@ export default class ProjectActivityAppContainer extends React.PureComponent {
componentWillUnmount() {
this.mounted = false;
- const elem = document.querySelector('html');
- elem && elem.classList.remove('dashboard-page');
}
addCustomEvent = (analysis /*: string */, name /*: string */, category /*: ?string */) =>
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx
index 19092afe655..f11038f2b18 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx
@@ -119,26 +119,30 @@ export default class App extends React.PureComponent<Props, State> {
{this.renderBranchLifeTime()}
</header>
- <table className="data zebra zebra-hover">
- <thead>
- <tr>
- <th>{translate('branch')}</th>
- <th className="thin nowrap text-right">{translate('status')}</th>
- <th className="thin nowrap text-right">{translate('branches.last_analysis_date')}</th>
- <th className="thin nowrap text-right">{translate('actions')}</th>
- </tr>
- </thead>
- <tbody>
- {sortBranchesAsTree(branches).map(branch => (
- <BranchRow
- branch={branch}
- component={component.key}
- key={branch.name}
- onChange={onBranchesChange}
- />
- ))}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table className="data zebra zebra-hover">
+ <thead>
+ <tr>
+ <th>{translate('branch')}</th>
+ <th className="thin nowrap text-right">{translate('status')}</th>
+ <th className="thin nowrap text-right">
+ {translate('branches.last_analysis_date')}
+ </th>
+ <th className="thin nowrap text-right">{translate('actions')}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {sortBranchesAsTree(branches).map(branch => (
+ <BranchRow
+ branch={branch}
+ component={component.key}
+ key={branch.name}
+ onChange={onBranchesChange}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap
index 4914db6ffce..e9d41bf777e 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -41,69 +41,73 @@ exports[`renders sorted list of branches 1`] = `
/>
</p>
</header>
- <table
- className="data zebra zebra-hover"
+ <div
+ className="boxed-group boxed-group-inner"
>
- <thead>
- <tr>
- <th>
- branch
- </th>
- <th
- className="thin nowrap text-right"
- >
- status
- </th>
- <th
- className="thin nowrap text-right"
- >
- branches.last_analysis_date
- </th>
- <th
- className="thin nowrap text-right"
- >
- actions
- </th>
- </tr>
- </thead>
- <tbody>
- <BranchRow
- branch={
- Object {
- "isMain": true,
- "name": "master",
+ <table
+ className="data zebra zebra-hover"
+ >
+ <thead>
+ <tr>
+ <th>
+ branch
+ </th>
+ <th
+ className="thin nowrap text-right"
+ >
+ status
+ </th>
+ <th
+ className="thin nowrap text-right"
+ >
+ branches.last_analysis_date
+ </th>
+ <th
+ className="thin nowrap text-right"
+ >
+ actions
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <BranchRow
+ branch={
+ Object {
+ "isMain": true,
+ "name": "master",
+ }
}
- }
- component="foo"
- key="master"
- onChange={[Function]}
- />
- <BranchRow
- branch={
- Object {
- "isMain": false,
- "mergeBranch": "master",
- "name": "branch-1.0",
- "type": "SHORT",
+ component="foo"
+ key="master"
+ onChange={[Function]}
+ />
+ <BranchRow
+ branch={
+ Object {
+ "isMain": false,
+ "mergeBranch": "master",
+ "name": "branch-1.0",
+ "type": "SHORT",
+ }
}
- }
- component="foo"
- key="branch-1.0"
- onChange={[Function]}
- />
- <BranchRow
- branch={
- Object {
- "isMain": false,
- "name": "branch-1.0",
- "type": "LONG",
+ component="foo"
+ key="branch-1.0"
+ onChange={[Function]}
+ />
+ <BranchRow
+ branch={
+ Object {
+ "isMain": false,
+ "name": "branch-1.0",
+ "type": "LONG",
+ }
}
- }
- component="foo"
- key="branch-1.0"
- onChange={[Function]}
- />
- </tbody>
- </table>
+ component="foo"
+ key="branch-1.0"
+ onChange={[Function]}
+ />
+ </tbody>
+ </table>
+ </div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/Table.tsx b/server/sonar-web/src/main/js/apps/projectQualityProfiles/Table.tsx
index 88f51601856..1e6374406ec 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/Table.tsx
+++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/Table.tsx
@@ -44,16 +44,18 @@ export default function Table(props: Props) {
));
return (
- <table className="data zebra">
- <thead>
- <tr>
- <th className="thin nowrap">{translate('language')}</th>
- <th className="thin nowrap">{translate('quality_profile')}</th>
- {/* keep one empty cell for the spinner */}
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tbody>{profileRows}</tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table className="data zebra">
+ <thead>
+ <tr>
+ <th className="thin nowrap">{translate('language')}</th>
+ <th className="thin nowrap">{translate('quality_profile')}</th>
+ {/* keep one empty cell for the spinner */}
+ <th>&nbsp;</th>
+ </tr>
+ </thead>
+ <tbody>{profileRows}</tbody>
+ </table>
+ </div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Table-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Table-test.tsx.snap
index 5ac9cea89da..b77fae2826b 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Table-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Table-test.tsx.snap
@@ -1,32 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders 1`] = `
-<table
- className="data zebra"
+<div
+ className="boxed-group boxed-group-inner"
>
- <thead>
- <tr>
- <th
- className="thin nowrap"
- >
- language
- </th>
- <th
- className="thin nowrap"
- >
- quality_profile
- </th>
- <th>
-  
- </th>
- </tr>
- </thead>
- <tbody>
- <ProfileRow
- key="java"
- onChangeProfile={[Function]}
- possibleProfiles={
- Array [
+ <table
+ className="data zebra"
+ >
+ <thead>
+ <tr>
+ <th
+ className="thin nowrap"
+ >
+ language
+ </th>
+ <th
+ className="thin nowrap"
+ >
+ quality_profile
+ </th>
+ <th>
+  
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <ProfileRow
+ key="java"
+ onChangeProfile={[Function]}
+ possibleProfiles={
+ Array [
+ Object {
+ "activeDeprecatedRuleCount": 0,
+ "activeRuleCount": 17,
+ "key": "foo-java",
+ "language": "java",
+ "languageName": "java",
+ "name": "foo-java",
+ "organization": "org",
+ },
+ Object {
+ "activeDeprecatedRuleCount": 0,
+ "activeRuleCount": 17,
+ "key": "bar-java",
+ "language": "java",
+ "languageName": "java",
+ "name": "bar-java",
+ "organization": "org",
+ },
+ Object {
+ "activeDeprecatedRuleCount": 0,
+ "activeRuleCount": 17,
+ "key": "baz-java",
+ "language": "java",
+ "languageName": "java",
+ "name": "baz-java",
+ "organization": "org",
+ },
+ ]
+ }
+ profile={
Object {
"activeDeprecatedRuleCount": 0,
"activeRuleCount": 17,
@@ -35,44 +68,26 @@ exports[`renders 1`] = `
"languageName": "java",
"name": "foo-java",
"organization": "org",
- },
- Object {
- "activeDeprecatedRuleCount": 0,
- "activeRuleCount": 17,
- "key": "bar-java",
- "language": "java",
- "languageName": "java",
- "name": "bar-java",
- "organization": "org",
- },
- Object {
- "activeDeprecatedRuleCount": 0,
- "activeRuleCount": 17,
- "key": "baz-java",
- "language": "java",
- "languageName": "java",
- "name": "baz-java",
- "organization": "org",
- },
- ]
- }
- profile={
- Object {
- "activeDeprecatedRuleCount": 0,
- "activeRuleCount": 17,
- "key": "foo-java",
- "language": "java",
- "languageName": "java",
- "name": "foo-java",
- "organization": "org",
+ }
+ }
+ />
+ <ProfileRow
+ key="js"
+ onChangeProfile={[Function]}
+ possibleProfiles={
+ Array [
+ Object {
+ "activeDeprecatedRuleCount": 0,
+ "activeRuleCount": 17,
+ "key": "foo-js",
+ "language": "js",
+ "languageName": "js",
+ "name": "foo-js",
+ "organization": "org",
+ },
+ ]
}
- }
- />
- <ProfileRow
- key="js"
- onChangeProfile={[Function]}
- possibleProfiles={
- Array [
+ profile={
Object {
"activeDeprecatedRuleCount": 0,
"activeRuleCount": 17,
@@ -81,21 +96,10 @@ exports[`renders 1`] = `
"languageName": "js",
"name": "foo-js",
"organization": "org",
- },
- ]
- }
- profile={
- Object {
- "activeDeprecatedRuleCount": 0,
- "activeRuleCount": 17,
- "key": "foo-js",
- "language": "js",
- "languageName": "js",
- "name": "foo-js",
- "organization": "org",
+ }
}
- }
- />
- </tbody>
-</table>
+ />
+ </tbody>
+ </table>
+</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
index 15dc8f4e7ca..b8c83faa629 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
@@ -70,11 +70,6 @@ export default class AllProjects extends React.PureComponent<Props, State> {
componentDidMount() {
this.mounted = true;
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
-
if (this.props.isFavorite && !isLoggedIn(this.props.currentUser)) {
handleRequiredAuthentication();
return;
@@ -95,11 +90,6 @@ export default class AllProjects extends React.PureComponent<Props, State> {
componentWillUnmount() {
this.mounted = false;
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
-
const footer = document.getElementById('footer');
if (footer) {
footer.classList.remove('page-footer-with-sidebar');
diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
index 3f347339ad0..0b7666c9816 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx
@@ -23,7 +23,7 @@ import SearchFilterContainer from '../filters/SearchFilterContainer';
import Tooltip from '../../../components/controls/Tooltip';
import PerspectiveSelect from './PerspectiveSelect';
import ProjectsSortingSelect from './ProjectsSortingSelect';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { CurrentUser, isLoggedIn, HomePageType } from '../../../app/types';
import HomePageSelect from '../../../components/controls/HomePageSelect';
import { translate } from '../../../helpers/l10n';
import { RawQuery } from '../../../helpers/query';
@@ -101,12 +101,12 @@ export default function PageHeader(props: Props) {
)}
</div>
- {props.onSonarCloud &&
- isLoggedIn(currentUser) &&
- props.isFavorite &&
- !props.organization && (
- <HomePageSelect className="huge-spacer-left" currentPage={{ type: 'my-projects' }} />
- )}
+ {props.isFavorite && (
+ <HomePageSelect
+ className="huge-spacer-left"
+ currentPage={{ type: HomePageType.MyProjects }}
+ />
+ )}
</header>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx
index 8a5b4f6d216..3c79acd0113 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeak.tsx
@@ -49,6 +49,7 @@ export default function ProjectCardLeak({ organization, project }: Props) {
className="spacer-right"
component={project.key}
favorite={project.isFavorite}
+ qualifier="TRK"
/>
)}
<h2 className="project-card-name">
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx
index d8ecbe86f66..79926daf027 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverall.tsx
@@ -48,6 +48,7 @@ export default function ProjectCardOverall({ organization, project }: Props) {
className="spacer-right"
component={project.key}
favorite={project.isFavorite}
+ qualifier="TRK"
/>
)}
<h2 className="project-card-name">
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx
index d3399685066..81a0bb7102f 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx
@@ -50,32 +50,34 @@ export default class Projects extends React.PureComponent<Props> {
render() {
return (
- <table
- className={classNames('data', 'zebra', { 'new-loading': !this.props.ready })}
- id="projects-management-page-projects">
- <thead>
- <tr>
- <th />
- <th>{translate('name')}</th>
- <th />
- <th>{translate('key')}</th>
- <th className="thin nowrap text-right">{translate('last_analysis')}</th>
- <th />
- </tr>
- </thead>
- <tbody>
- {this.props.projects.map(project => (
- <ProjectRow
- currentUser={this.props.currentUser}
- key={project.key}
- onApplyTemplate={this.handleApplyTemplate}
- onProjectCheck={this.onProjectCheck}
- project={project}
- selected={this.props.selection.includes(project.key)}
- />
- ))}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table
+ className={classNames('data', 'zebra', { 'new-loading': !this.props.ready })}
+ id="projects-management-page-projects">
+ <thead>
+ <tr>
+ <th />
+ <th>{translate('name')}</th>
+ <th />
+ <th>{translate('key')}</th>
+ <th className="thin nowrap text-right">{translate('last_analysis')}</th>
+ <th />
+ </tr>
+ </thead>
+ <tbody>
+ {this.props.projects.map(project => (
+ <ProjectRow
+ currentUser={this.props.currentUser}
+ key={project.key}
+ onApplyTemplate={this.handleApplyTemplate}
+ onProjectCheck={this.onProjectCheck}
+ project={project}
+ selected={this.props.selection.includes(project.key)}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Projects-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Projects-test.tsx.snap
index 7a3728a28ad..1503fed2c4e 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Projects-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Projects-test.tsx.snap
@@ -1,67 +1,71 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders list of projects 1`] = `
-<table
- className="data zebra new-loading"
- id="projects-management-page-projects"
+<div
+ className="boxed-group boxed-group-inner"
>
- <thead>
- <tr>
- <th />
- <th>
- name
- </th>
- <th />
- <th>
- key
- </th>
- <th
- className="thin nowrap text-right"
- >
- last_analysis
- </th>
- <th />
- </tr>
- </thead>
- <tbody>
- <ProjectRow
- currentUser={
- Object {
- "login": "foo",
+ <table
+ className="data zebra new-loading"
+ id="projects-management-page-projects"
+ >
+ <thead>
+ <tr>
+ <th />
+ <th>
+ name
+ </th>
+ <th />
+ <th>
+ key
+ </th>
+ <th
+ className="thin nowrap text-right"
+ >
+ last_analysis
+ </th>
+ <th />
+ </tr>
+ </thead>
+ <tbody>
+ <ProjectRow
+ currentUser={
+ Object {
+ "login": "foo",
+ }
}
- }
- key="a"
- onApplyTemplate={[Function]}
- onProjectCheck={[Function]}
- project={
- Object {
- "key": "a",
- "name": "A",
- "qualifier": "TRK",
- "visibility": "public",
+ key="a"
+ onApplyTemplate={[Function]}
+ onProjectCheck={[Function]}
+ project={
+ Object {
+ "key": "a",
+ "name": "A",
+ "qualifier": "TRK",
+ "visibility": "public",
+ }
}
- }
- selected={true}
- />
- <ProjectRow
- currentUser={
- Object {
- "login": "foo",
+ selected={true}
+ />
+ <ProjectRow
+ currentUser={
+ Object {
+ "login": "foo",
+ }
}
- }
- key="b"
- onApplyTemplate={[Function]}
- onProjectCheck={[Function]}
- project={
- Object {
- "key": "b",
- "name": "B",
- "qualifier": "TRK",
- "visibility": "public",
+ key="b"
+ onApplyTemplate={[Function]}
+ onProjectCheck={[Function]}
+ project={
+ Object {
+ "key": "b",
+ "name": "B",
+ "qualifier": "TRK",
+ "visibility": "public",
+ }
}
- }
- selected={false}
- />
- </tbody>
-</table>
+ selected={false}
+ />
+ </tbody>
+ </table>
+</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatesApp.js b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatesApp.js
index 0ec8d28794d..4386f8cca8c 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatesApp.js
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatesApp.js
@@ -37,6 +37,8 @@ export default class QualityGatesApp extends Component {
componentDidMount() {
this.fetchQualityGates();
+ // $FlowFixMe
+ document.body.classList.add('white-page');
const footer = document.getElementById('footer');
if (footer) {
footer.classList.add('page-footer-with-sidebar');
@@ -44,6 +46,8 @@ export default class QualityGatesApp extends Component {
}
componentWillUnmount() {
+ // $FlowFixMe
+ document.body.classList.remove('white-page');
const footer = document.getElementById('footer');
if (footer) {
footer.classList.remove('page-footer-with-sidebar');
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
index 8f8f056be4e..fda9bb7ed26 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
@@ -43,13 +43,6 @@ export default class App extends React.PureComponent<Props, State> {
mounted: boolean;
state: State = { loading: true };
- componentWillMount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
- }
-
componentDidMount() {
this.mounted = true;
this.loadData();
@@ -57,10 +50,6 @@ export default class App extends React.PureComponent<Props, State> {
componentWillUnmount() {
this.mounted = false;
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
}
fetchProfiles() {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js
index 7df88bb9fb7..a2c05ac3e3f 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/App.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/App.js
@@ -47,10 +47,6 @@ export default class App extends React.PureComponent {
state /*: State */ = { loaded: false };
componentDidMount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.add('dashboard-page');
- }
const componentKey = this.props.component ? this.props.component.key : null;
this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true }));
}
@@ -62,13 +58,6 @@ export default class App extends React.PureComponent {
}
}
- componentWillUnmount() {
- const html = document.querySelector('html');
- if (html) {
- html.classList.remove('dashboard-page');
- }
- }
-
render() {
if (!this.state.loaded) {
return null;
diff --git a/server/sonar-web/src/main/js/apps/users/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/UsersList.tsx
index a81a9441af3..9609acd0a9b 100644
--- a/server/sonar-web/src/main/js/apps/users/UsersList.tsx
+++ b/server/sonar-web/src/main/js/apps/users/UsersList.tsx
@@ -38,31 +38,33 @@ export default function UsersList({
users
}: Props) {
return (
- <table id="users-list" className="data zebra">
- <thead>
- <tr>
- <th />
- <th className="nowrap" />
- <th className="nowrap">{translate('my_profile.scm_accounts')}</th>
- {!organizationsEnabled && <th className="nowrap">{translate('my_profile.groups')}</th>}
- <th className="nowrap">{translate('users.tokens')}</th>
- <th className="nowrap">&nbsp;</th>
- </tr>
- </thead>
- <tbody>
- {users.map(user => (
- <UserListItem
- identityProvider={identityProviders.find(
- provider => user.externalProvider === provider.key
- )}
- isCurrentUser={currentUser.isLoggedIn && currentUser.login === user.login}
- key={user.login}
- onUpdateUsers={onUpdateUsers}
- organizationsEnabled={organizationsEnabled}
- user={user}
- />
- ))}
- </tbody>
- </table>
+ <div className="boxed-group boxed-group-inner">
+ <table id="users-list" className="data zebra">
+ <thead>
+ <tr>
+ <th />
+ <th className="nowrap" />
+ <th className="nowrap">{translate('my_profile.scm_accounts')}</th>
+ {!organizationsEnabled && <th className="nowrap">{translate('my_profile.groups')}</th>}
+ <th className="nowrap">{translate('users.tokens')}</th>
+ <th className="nowrap">&nbsp;</th>
+ </tr>
+ </thead>
+ <tbody>
+ {users.map(user => (
+ <UserListItem
+ identityProvider={identityProviders.find(
+ provider => user.externalProvider === provider.key
+ )}
+ isCurrentUser={currentUser.isLoggedIn && currentUser.login === user.login}
+ key={user.login}
+ onUpdateUsers={onUpdateUsers}
+ organizationsEnabled={organizationsEnabled}
+ user={user}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap
index 4b732ab0f36..64c13cf48e9 100644
--- a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap
@@ -1,64 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<table
- className="data zebra"
- id="users-list"
+<div
+ className="boxed-group boxed-group-inner"
>
- <thead>
- <tr>
- <th />
- <th
- className="nowrap"
- />
- <th
- className="nowrap"
- >
- my_profile.scm_accounts
- </th>
- <th
- className="nowrap"
- >
- users.tokens
- </th>
- <th
- className="nowrap"
- >
-  
- </th>
- </tr>
- </thead>
- <tbody>
- <UserListItem
- isCurrentUser={true}
- key="luke"
- onUpdateUsers={[Function]}
- organizationsEnabled={true}
- user={
- Object {
- "active": true,
- "local": false,
- "login": "luke",
- "name": "Luke",
- "scmAccounts": Array [],
+ <table
+ className="data zebra"
+ id="users-list"
+ >
+ <thead>
+ <tr>
+ <th />
+ <th
+ className="nowrap"
+ />
+ <th
+ className="nowrap"
+ >
+ my_profile.scm_accounts
+ </th>
+ <th
+ className="nowrap"
+ >
+ users.tokens
+ </th>
+ <th
+ className="nowrap"
+ >
+  
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <UserListItem
+ isCurrentUser={true}
+ key="luke"
+ onUpdateUsers={[Function]}
+ organizationsEnabled={true}
+ user={
+ Object {
+ "active": true,
+ "local": false,
+ "login": "luke",
+ "name": "Luke",
+ "scmAccounts": Array [],
+ }
}
- }
- />
- <UserListItem
- isCurrentUser={false}
- key="obi"
- onUpdateUsers={[Function]}
- organizationsEnabled={true}
- user={
- Object {
- "active": true,
- "local": false,
- "login": "obi",
- "name": "One",
- "scmAccounts": Array [],
+ />
+ <UserListItem
+ isCurrentUser={false}
+ key="obi"
+ onUpdateUsers={[Function]}
+ organizationsEnabled={true}
+ user={
+ Object {
+ "active": true,
+ "local": false,
+ "login": "obi",
+ "name": "One",
+ "scmAccounts": Array [],
+ }
}
- }
- />
- </tbody>
-</table>
+ />
+ </tbody>
+ </table>
+</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Action.tsx b/server/sonar-web/src/main/js/apps/web-api/components/Action.tsx
index f0b5eed39e6..5126f39b525 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/Action.tsx
+++ b/server/sonar-web/src/main/js/apps/web-api/components/Action.tsx
@@ -120,7 +120,7 @@ export default class Action extends React.PureComponent<Props, State> {
);
}
- return <hr />;
+ return null;
}
render() {
@@ -130,8 +130,8 @@ export default class Action extends React.PureComponent<Props, State> {
const actionKey = getActionKey(domain.path, action.key);
return (
- <div id={actionKey} className="web-api-action">
- <header className="web-api-action-header">
+ <div id={actionKey} className="boxed-group">
+ <header className="web-api-action-header boxed-group-header">
<Link
to={{ pathname: '/web_api/' + actionKey }}
className="spacer-right link-no-underline">
@@ -161,26 +161,28 @@ export default class Action extends React.PureComponent<Props, State> {
)}
</header>
- <div
- className="web-api-action-description markdown"
- dangerouslySetInnerHTML={{ __html: action.description }}
- />
+ <div className="boxed-group-inner">
+ <div
+ className="web-api-action-description markdown"
+ dangerouslySetInnerHTML={{ __html: action.description }}
+ />
- {this.renderTabs()}
+ {this.renderTabs()}
- {showParams &&
- action.params && (
- <Params
- params={action.params}
- showDeprecated={this.props.showDeprecated}
- showInternal={this.props.showInternal}
- />
- )}
+ {showParams &&
+ action.params && (
+ <Params
+ params={action.params}
+ showDeprecated={this.props.showDeprecated}
+ showInternal={this.props.showInternal}
+ />
+ )}
- {showResponse &&
- action.hasResponseExample && <ResponseExample domain={domain} action={action} />}
+ {showResponse &&
+ action.hasResponseExample && <ResponseExample domain={domain} action={action} />}
- {showChangelog && <ActionChangelog changelog={action.changelog} />}
+ {showChangelog && <ActionChangelog changelog={action.changelog} />}
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap
index 02cc7f1b708..ac543cd86e3 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap
@@ -91,11 +91,11 @@ exports[`should display the response example 1`] = `
exports[`should render correctly 1`] = `
<div
- className="web-api-action"
+ className="boxed-group"
id="foo/foo"
>
<header
- className="web-api-action-header"
+ className="web-api-action-header boxed-group-header"
>
<Link
className="spacer-right link-no-underline"
@@ -118,43 +118,47 @@ exports[`should render correctly 1`] = `
</h3>
</header>
<div
- className="web-api-action-description markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "Foo Desc",
- }
- }
- />
- <ul
- className="web-api-action-actions tabs"
+ className="boxed-group-inner"
>
- <li>
- <a
- className=""
- href="#"
- onClick={[Function]}
- >
- api_documentation.parameters
- </a>
- </li>
- <li>
- <a
- className=""
- href="#"
- onClick={[Function]}
- >
- api_documentation.response_example
- </a>
- </li>
- <li>
- <a
- className=""
- href="#"
- onClick={[Function]}
- >
- api_documentation.changelog
- </a>
- </li>
- </ul>
+ <div
+ className="web-api-action-description markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "Foo Desc",
+ }
+ }
+ />
+ <ul
+ className="web-api-action-actions tabs"
+ >
+ <li>
+ <a
+ className=""
+ href="#"
+ onClick={[Function]}
+ >
+ api_documentation.parameters
+ </a>
+ </li>
+ <li>
+ <a
+ className=""
+ href="#"
+ onClick={[Function]}
+ >
+ api_documentation.response_example
+ </a>
+ </li>
+ <li>
+ <a
+ className=""
+ href="#"
+ onClick={[Function]}
+ >
+ api_documentation.changelog
+ </a>
+ </li>
+ </ul>
+ </div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css b/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css
index c99b781ab07..ea4ec21da9d 100644
--- a/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css
+++ b/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css
@@ -26,10 +26,7 @@
}
.web-api-domain-actions {
-}
-
-.web-api-action {
- padding-top: 30px;
+ margin-top: calc(2 * var(--gridSize));
}
.web-api-action-title {
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/styles.css b/server/sonar-web/src/main/js/components/SourceViewer/styles.css
index 8c9498bec49..c69d07eb481 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/styles.css
+++ b/server/sonar-web/src/main/js/components/SourceViewer/styles.css
@@ -20,7 +20,7 @@
.source-viewer {
width: 100%;
min-height: 200px;
- border: 1px solid var(--barBorderColor);
+ border: 1px solid var(--gray80);
box-sizing: border-box;
background-color: #fff;
overflow-x: auto;
diff --git a/server/sonar-web/src/main/js/components/common/BranchStatus.css b/server/sonar-web/src/main/js/components/common/BranchStatus.css
index ccfccb351f1..ac0a177c6a5 100644
--- a/server/sonar-web/src/main/js/components/common/BranchStatus.css
+++ b/server/sonar-web/src/main/js/components/common/BranchStatus.css
@@ -1,5 +1,8 @@
.branch-status {
+ display: flex;
+ align-items: center;
min-width: 64px;
+ line-height: calc(2 * var(--gridSize));
text-align: right;
}
diff --git a/server/sonar-web/src/main/js/components/common/BranchStatus.tsx b/server/sonar-web/src/main/js/components/common/BranchStatus.tsx
index bb9069bc234..e0e4fa55b1d 100644
--- a/server/sonar-web/src/main/js/components/common/BranchStatus.tsx
+++ b/server/sonar-web/src/main/js/components/common/BranchStatus.tsx
@@ -44,26 +44,26 @@ export default function BranchStatus({ branch, concise = false }: Props) {
const indicatorColor = totalIssues > 0 ? 'red' : 'green';
return concise ? (
- <ul className="list-inline branch-status">
+ <ul className="branch-status">
<li>{totalIssues}</li>
<li className="spacer-left">
<StatusIndicator color={indicatorColor} size="small" />
</li>
</ul>
) : (
- <ul className="list-inline branch-status">
+ <ul className="branch-status">
<li className="spacer-right">
<StatusIndicator color={indicatorColor} size="small" />
</li>
- <li>
+ <li className="spacer-left">
{branch.status.bugs}
<BugIcon />
</li>
- <li>
+ <li className="spacer-left">
{branch.status.vulnerabilities}
<VulnerabilityIcon />
</li>
- <li>
+ <li className="spacer-left">
{branch.status.codeSmells}
<CodeSmellIcon />
</li>
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap
index 8833bab3ceb..d648e77db49 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap
@@ -16,7 +16,7 @@ exports[`renders status of long-living branches 2`] = `
exports[`renders status of short-living branches 1`] = `
<ul
- className="list-inline branch-status"
+ className="branch-status"
>
<li
className="spacer-right"
@@ -26,15 +26,21 @@ exports[`renders status of short-living branches 1`] = `
size="small"
/>
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
0
<BugIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
0
<VulnerabilityIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
0
<CodeSmellIcon />
</li>
@@ -43,7 +49,7 @@ exports[`renders status of short-living branches 1`] = `
exports[`renders status of short-living branches 2`] = `
<ul
- className="list-inline branch-status"
+ className="branch-status"
>
<li
className="spacer-right"
@@ -53,15 +59,21 @@ exports[`renders status of short-living branches 2`] = `
size="small"
/>
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
0
<BugIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
0
<VulnerabilityIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
1
<CodeSmellIcon />
</li>
@@ -70,7 +82,7 @@ exports[`renders status of short-living branches 2`] = `
exports[`renders status of short-living branches 3`] = `
<ul
- className="list-inline branch-status"
+ className="branch-status"
>
<li
className="spacer-right"
@@ -80,15 +92,21 @@ exports[`renders status of short-living branches 3`] = `
size="small"
/>
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
7
<BugIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
6
<VulnerabilityIcon />
</li>
- <li>
+ <li
+ className="spacer-left"
+ >
3
<CodeSmellIcon />
</li>
diff --git a/server/sonar-web/src/main/js/components/controls/Favorite.tsx b/server/sonar-web/src/main/js/components/controls/Favorite.tsx
index fb43626c05c..5ac11f9527a 100644
--- a/server/sonar-web/src/main/js/components/controls/Favorite.tsx
+++ b/server/sonar-web/src/main/js/components/controls/Favorite.tsx
@@ -25,13 +25,13 @@ interface Props {
className?: string;
component: string;
favorite: boolean;
+ qualifier: string;
}
-export default function Favorite({ favorite, component, ...other }: Props) {
+export default function Favorite({ component, ...other }: Props) {
return (
<FavoriteBase
{...other}
- favorite={favorite}
addFavorite={() => addFavorite(component)}
removeFavorite={() => removeFavorite(component)}
/>
diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx b/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
index f802e0885f7..a1f738dcba3 100644
--- a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
+++ b/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx
@@ -23,10 +23,11 @@ import Tooltip from './Tooltip';
import FavoriteIcon from '../icons-components/FavoriteIcon';
import { translate } from '../../helpers/l10n';
-interface Props {
+export interface Props {
addFavorite: () => Promise<void>;
className?: string;
favorite: boolean;
+ qualifier: string;
removeFavorite: () => Promise<void>;
}
@@ -83,10 +84,10 @@ export default class FavoriteBase extends React.PureComponent<Props, State> {
render() {
const tooltip = this.state.favorite
- ? translate('favorite.current')
- : translate('favorite.check');
+ ? translate('favorite.current', this.props.qualifier)
+ : translate('favorite.check', this.props.qualifier);
return (
- <Tooltip overlay={tooltip}>
+ <Tooltip overlay={tooltip} placement="left">
<a
className={classNames('display-inline-block', 'link-no-underline', this.props.className)}
href="#"
diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteIssueFilter.js b/server/sonar-web/src/main/js/components/controls/FavoriteIssueFilter.js
deleted file mode 100644
index c00c2993d04..00000000000
--- a/server/sonar-web/src/main/js/components/controls/FavoriteIssueFilter.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 React from 'react';
-import PropTypes from 'prop-types';
-import FavoriteBase from './FavoriteBase';
-import { toggleIssueFilter } from '../../api/issue-filters';
-
-export default class FavoriteIssueFilter extends React.PureComponent {
- static propTypes = {
- favorite: PropTypes.bool.isRequired,
- filter: PropTypes.shape({
- id: PropTypes.string.isRequired
- }).isRequired
- };
-
- render() {
- return (
- <FavoriteBase
- favorite={this.props.favorite}
- addFavorite={() => toggleIssueFilter(this.props.filter.id)}
- removeFavorite={() => toggleIssueFilter(this.props.filter.id)}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
index 9d68ef7e1fc..572e65cb5ae 100644
--- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
+++ b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
@@ -24,11 +24,12 @@ import Tooltip from './Tooltip';
import HomeIcon from '../icons-components/HomeIcon';
import { CurrentUser, isLoggedIn, HomePage, isSameHomePage } from '../../app/types';
import { translate } from '../../helpers/l10n';
-import { getCurrentUser } from '../../store/rootReducer';
+import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer';
import { setHomePage } from '../../store/users/actions';
interface StateProps {
currentUser: CurrentUser;
+ onSonarCloud: boolean;
}
interface DispatchProps {
@@ -48,9 +49,9 @@ class HomePageSelect extends React.PureComponent<Props> {
};
render() {
- const { currentPage, currentUser } = this.props;
+ const { currentPage, currentUser, onSonarCloud } = this.props;
- if (!isLoggedIn(currentUser)) {
+ if (!isLoggedIn(currentUser) || !onSonarCloud) {
return null;
}
@@ -59,7 +60,7 @@ class HomePageSelect extends React.PureComponent<Props> {
const tooltip = checked ? translate('homepage.current') : translate('homepage.check');
return (
- <Tooltip overlay={tooltip}>
+ <Tooltip overlay={tooltip} placement="left">
{checked ? (
<span className={classNames('display-inline-block', this.props.className)}>
<HomeIcon filled={checked} />
@@ -81,9 +82,14 @@ class HomePageSelect extends React.PureComponent<Props> {
}
}
-const mapStateToProps = (state: any): StateProps => ({
- currentUser: getCurrentUser(state)
-});
+const mapStateToProps = (state: any): StateProps => {
+ const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled');
+
+ return {
+ currentUser: getCurrentUser(state),
+ onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true')
+ };
+};
const mapDispatchToProps: DispatchProps = { setHomePage };
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx
index 0601fc5bd29..05bfc43bfa9 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx
@@ -22,5 +22,5 @@ import { shallow } from 'enzyme';
import Favorite from '../Favorite';
it('renders', () => {
- expect(shallow(<Favorite component="foo" favorite={true} />)).toMatchSnapshot();
+ expect(shallow(<Favorite component="foo" favorite={true} qualifier="TRK" />)).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx
index a6231ceb7ff..3d93e7f9159 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import FavoriteBase from '../FavoriteBase';
+import FavoriteBase, { Props } from '../FavoriteBase';
import { click } from '../../../helpers/testUtils';
it('should render favorite', () => {
@@ -46,8 +46,14 @@ it('should remove favorite', () => {
expect(removeFavorite).toBeCalled();
});
-function renderFavoriteBase(props?: any) {
+function renderFavoriteBase(props: Partial<Props> = {}) {
return shallow(
- <FavoriteBase favorite={true} addFavorite={jest.fn()} removeFavorite={jest.fn()} {...props} />
+ <FavoriteBase
+ favorite={true}
+ addFavorite={jest.fn()}
+ qualifier="TRK"
+ removeFavorite={jest.fn()}
+ {...props}
+ />
);
}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Favorite-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Favorite-test.tsx.snap
index dd978f6e724..592afbf9398 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Favorite-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Favorite-test.tsx.snap
@@ -4,6 +4,7 @@ exports[`renders 1`] = `
<FavoriteBase
addFavorite={[Function]}
favorite={true}
+ qualifier="TRK"
removeFavorite={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap
index bb842b986b0..8186fad3a49 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap
@@ -2,8 +2,8 @@
exports[`should render favorite 1`] = `
<Tooltip
- overlay="favorite.current"
- placement="bottom"
+ overlay="favorite.current.TRK"
+ placement="left"
>
<a
className="display-inline-block link-no-underline"
@@ -19,8 +19,8 @@ exports[`should render favorite 1`] = `
exports[`should render not favorite 1`] = `
<Tooltip
- overlay="favorite.check"
- placement="bottom"
+ overlay="favorite.check.TRK"
+ placement="left"
>
<a
className="display-inline-block link-no-underline"
diff --git a/server/sonar-web/src/main/js/components/nav/ContextNavBar.css b/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
index 81a469b239b..3042b4cf120 100644
--- a/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
+++ b/server/sonar-web/src/main/js/components/nav/ContextNavBar.css
@@ -1,6 +1,6 @@
.navbar-context,
.navbar-context .navbar-inner {
- background-color: var(--barBackgroundColor);
+ background-color: #fff;
z-index: 420;
}
@@ -14,7 +14,7 @@
}
.navbar-context-header {
- display: inline-flex;
+ display: flex;
align-items: center;
height: calc(4 * var(--gridSize));
font-size: var(--bigFontSize);
@@ -48,6 +48,7 @@
top: 36px;
right: 0;
padding: 0 20px;
+ white-space: nowrap;
}
.navbar-context-description {
diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts
index 10ab02703cb..f5e53d33c26 100644
--- a/server/sonar-web/src/main/js/helpers/urls.ts
+++ b/server/sonar-web/src/main/js/helpers/urls.ts
@@ -21,7 +21,7 @@ import { stringify } from 'querystring';
import { omitBy, isNil } from 'lodash';
import { isShortLivingBranch } from './branches';
import { getProfilePath } from '../apps/quality-profiles/utils';
-import { Branch, HomePage } from '../app/types';
+import { Branch, HomePage, HomePageType } from '../app/types';
interface Query {
[x: string]: string | undefined;
@@ -174,13 +174,13 @@ export function getOrganizationUrl(organization: string) {
export function getHomePageUrl(homepage: HomePage) {
switch (homepage.type) {
- case 'project':
- return getProjectUrl(homepage.key!);
- case 'organization':
- return getOrganizationUrl(homepage.key!);
- case 'my-projects':
+ case HomePageType.Project:
+ return getProjectUrl(homepage.parameter!);
+ case HomePageType.Organization:
+ return getOrganizationUrl(homepage.parameter!);
+ case HomePageType.MyProjects:
return '/projects';
- case 'my-issues':
+ case HomePageType.MyIssues:
return { pathname: '/issues', query: { resolved: 'false' } };
}