--- /dev/null
+/*
+ * 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 * as React from 'react';
+import ComponentContainerNotFound from './ComponentContainerNotFound';
+import ComponentNav from './nav/component/ComponentNav';
+import { Branch, Component } from '../types';
+import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
+import { getBranches } from '../../api/branches';
+import { getComponentData } from '../../api/components';
+import { getComponentNavigation } from '../../api/nav';
+
+interface Props {
+ children: any;
+ location: {
+ query: { branch?: string; id: string };
+ };
+}
+
+interface State {
+ branches: Branch[];
+ loading: boolean;
+ component: Component | null;
+}
+
+export default class ComponentContainer extends React.PureComponent<Props, State> {
+ mounted: boolean;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = { branches: [], loading: true, component: null };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchComponent();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.location.query.id !== this.props.location.query.id) {
+ this.fetchComponent();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ addQualifier = (component: Component) => ({
+ ...component,
+ qualifier: component.breadcrumbs[component.breadcrumbs.length - 1].qualifier
+ });
+
+ fetchComponent() {
+ const { branch, id } = this.props.location.query;
+ this.setState({ loading: true });
+
+ const onError = (error: any) => {
+ if (this.mounted) {
+ if (error.response && error.response.status === 403) {
+ handleRequiredAuthorization();
+ } else {
+ this.setState({ loading: false });
+ }
+ }
+ };
+
+ Promise.all([getComponentNavigation(id), getComponentData(id, branch)]).then(([nav, data]) => {
+ const component = this.addQualifier({ ...nav, ...data });
+ this.fetchBranches(component).then(branches => {
+ if (this.mounted) {
+ this.setState({ loading: false, branches, component });
+ }
+ }, onError);
+ }, onError);
+ }
+
+ fetchBranches = (component: Component) => {
+ const project = component.breadcrumbs.find((c: Component) => c.qualifier === 'TRK');
+ return project ? getBranches(project.key) : Promise.resolve([]);
+ };
+
+ handleComponentChange = (changes: {}) => {
+ if (this.mounted) {
+ this.setState(state => ({ component: { ...state.component, ...changes } }));
+ }
+ };
+
+ handleBranchesChange = () => {
+ if (this.mounted && this.state.component) {
+ this.fetchBranches(this.state.component).then(
+ branches => {
+ if (this.mounted) {
+ this.setState({ branches });
+ }
+ },
+ () => {}
+ );
+ }
+ };
+
+ render() {
+ const { query } = this.props.location;
+ const { branches, component, loading } = this.state;
+
+ if (loading) {
+ return <i className="spinner" />;
+ }
+
+ if (!component) {
+ return <ComponentContainerNotFound />;
+ }
+
+ const branch = branches.find(b => (query.branch ? b.name === query.branch : b.isMain));
+ const isFile = ['FIL', 'UTS'].includes(component.qualifier);
+ const configuration = component.configuration || {};
+
+ return (
+ <div>
+ {!isFile &&
+ <ComponentNav
+ branches={branches}
+ currentBranch={branch}
+ component={component}
+ conf={configuration}
+ location={this.props.location}
+ />}
+ {React.cloneElement(this.props.children, {
+ branch,
+ branches,
+ component: component,
+ onBranchesChange: this.handleBranchesChange,
+ onComponentChange: this.handleComponentChange
+ })}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 * 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>
+ </div>
+ );
+ }
+}
+++ /dev/null
-/*
- * 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 * as React from 'react';
-import ProjectContainerNotFound from './ProjectContainerNotFound';
-import ComponentNav from './nav/component/ComponentNav';
-import { Branch, Component } from '../types';
-import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
-import { getBranches } from '../../api/branches';
-import { getComponentData } from '../../api/components';
-import { getComponentNavigation } from '../../api/nav';
-
-interface Props {
- children: any;
- location: {
- query: { branch?: string; id: string };
- };
-}
-
-interface State {
- branches: Branch[];
- loading: boolean;
- component: Component | null;
-}
-
-export default class ProjectContainer extends React.PureComponent<Props, State> {
- mounted: boolean;
-
- constructor(props: Props) {
- super(props);
- this.state = { branches: [], loading: true, component: null };
- }
-
- componentDidMount() {
- this.mounted = true;
- this.fetchProject();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.location.query.id !== this.props.location.query.id) {
- this.fetchProject();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- addQualifier = (component: Component) => ({
- ...component,
- qualifier: component.breadcrumbs[component.breadcrumbs.length - 1].qualifier
- });
-
- fetchProject() {
- const { branch, id } = this.props.location.query;
- this.setState({ loading: true });
-
- const onError = (error: any) => {
- if (this.mounted) {
- if (error.response && error.response.status === 403) {
- handleRequiredAuthorization();
- } else {
- this.setState({ loading: false });
- }
- }
- };
-
- Promise.all([getComponentNavigation(id), getComponentData(id, branch)]).then(([nav, data]) => {
- const component = this.addQualifier({ ...nav, ...data });
- this.fetchBranches(component).then(branches => {
- if (this.mounted) {
- this.setState({ loading: false, branches, component });
- }
- }, onError);
- }, onError);
- }
-
- fetchBranches = (component: Component) => {
- const project = component.breadcrumbs.find((c: Component) => c.qualifier === 'TRK');
- return project ? getBranches(project.key) : Promise.resolve([]);
- };
-
- handleProjectChange = (changes: {}) => {
- if (this.mounted) {
- this.setState(state => ({ component: { ...state.component, ...changes } }));
- }
- };
-
- handleBranchesChange = () => {
- if (this.mounted && this.state.component) {
- this.fetchBranches(this.state.component).then(
- branches => {
- if (this.mounted) {
- this.setState({ branches });
- }
- },
- () => {}
- );
- }
- };
-
- render() {
- const { query } = this.props.location;
- const { branches, component, loading } = this.state;
-
- if (loading) {
- return <i className="spinner" />;
- }
-
- const branch = branches.find(b => (query.branch ? b.name === query.branch : b.isMain));
-
- if (!component || !branch) {
- return <ProjectContainerNotFound />;
- }
-
- const isFile = ['FIL', 'UTS'].includes(component.qualifier);
- const configuration = component.configuration || {};
-
- return (
- <div>
- {!isFile &&
- <ComponentNav
- branches={branches}
- currentBranch={branch}
- component={component}
- conf={configuration}
- location={this.props.location}
- />}
- {React.cloneElement(this.props.children, {
- branch,
- branches,
- component: component,
- onBranchesChange: this.handleBranchesChange,
- onComponentChange: this.handleProjectChange
- })}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * 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 * as React from 'react';
-import { Link } from 'react-router';
-import { translate } from '../../helpers/l10n';
-
-export default class ProjectContainerNotFound 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>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * 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.
+ */
+jest.mock('../../../api/branches', () => ({ getBranches: jest.fn() }));
+jest.mock('../../../api/components', () => ({ getComponentData: jest.fn() }));
+jest.mock('../../../api/nav', () => ({ getComponentNavigation: jest.fn() }));
+
+// mock this, because some of its children are using redux store
+jest.mock('../nav/component/ComponentNav', () => ({
+ default: () => null
+}));
+
+import * as React from 'react';
+import { shallow, mount } from 'enzyme';
+import ComponentContainer from '../ComponentContainer';
+import { getBranches } from '../../../api/branches';
+import { getComponentData } from '../../../api/components';
+import { getComponentNavigation } from '../../../api/nav';
+import { doAsync } from '../../../helpers/testUtils';
+
+const Inner = () => <div />;
+
+beforeEach(() => {
+ (getBranches as jest.Mock<any>).mockClear();
+ (getComponentData as jest.Mock<any>).mockClear();
+ (getComponentNavigation as jest.Mock<any>).mockClear();
+});
+
+it('changes component', () => {
+ const wrapper = shallow(
+ <ComponentContainer location={{ query: { id: 'foo' } }}>
+ <Inner />
+ </ComponentContainer>
+ );
+ (wrapper.instance() as ComponentContainer).mounted = true;
+ wrapper.setState({
+ branches: [{ isMain: true }],
+ component: { qualifier: 'TRK', visibility: 'public' },
+ loading: false
+ });
+
+ (wrapper.find(Inner).prop('onComponentChange') as Function)({ visibility: 'private' });
+ expect(wrapper.state().component).toEqual({ qualifier: 'TRK', visibility: 'private' });
+});
+
+it("loads branches for module's project", () => {
+ (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
+ (getComponentData as jest.Mock<any>).mockImplementation(() => Promise.resolve({}));
+ (getComponentNavigation as jest.Mock<any>).mockImplementation(() =>
+ Promise.resolve({
+ breadcrumbs: [
+ { key: 'projectKey', name: 'project', qualifier: 'TRK' },
+ { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
+ ]
+ })
+ );
+
+ mount(
+ <ComponentContainer location={{ query: { id: 'moduleKey' } }}>
+ <Inner />
+ </ComponentContainer>
+ );
+
+ return doAsync().then(() => {
+ expect(getBranches).toBeCalledWith('projectKey');
+ expect(getComponentData).toBeCalledWith('moduleKey', undefined);
+ expect(getComponentNavigation).toBeCalledWith('moduleKey');
+ });
+});
+
+it("doesn't load branches portfolio", () => {
+ (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
+ (getComponentData as jest.Mock<any>).mockImplementation(() => Promise.resolve({}));
+ (getComponentNavigation as jest.Mock<any>).mockImplementation(() =>
+ Promise.resolve({
+ breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }]
+ })
+ );
+
+ const wrapper = mount(
+ <ComponentContainer location={{ query: { id: 'portfolioKey' } }}>
+ <Inner />
+ </ComponentContainer>
+ );
+
+ return doAsync().then(() => {
+ expect(getBranches).not.toBeCalled();
+ expect(getComponentData).toBeCalledWith('portfolioKey', undefined);
+ expect(getComponentNavigation).toBeCalledWith('portfolioKey');
+ expect(wrapper.find(Inner).exists()).toBeTruthy();
+ });
+});
+
+it('updates branches on change', () => {
+ (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
+ const wrapper = shallow(
+ <ComponentContainer location={{ query: { id: 'portfolioKey' } }}>
+ <Inner />
+ </ComponentContainer>
+ );
+ (wrapper.instance() as ComponentContainer).mounted = true;
+ wrapper.setState({
+ branches: [{ isMain: true }],
+ component: { breadcrumbs: [{ key: 'projectKey', name: 'project', qualifier: 'TRK' }] },
+ loading: false
+ });
+ (wrapper.find(Inner).prop('onBranchesChange') as Function)();
+ expect(getBranches).toBeCalledWith('projectKey');
+});
+++ /dev/null
-/*
- * 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.
- */
-jest.mock('../../../api/branches', () => ({ getBranches: jest.fn() }));
-jest.mock('../../../api/components', () => ({ getComponentData: jest.fn() }));
-jest.mock('../../../api/nav', () => ({ getComponentNavigation: jest.fn() }));
-
-import * as React from 'react';
-import { shallow, mount } from 'enzyme';
-import ProjectContainer from '../ProjectContainer';
-import { getBranches } from '../../../api/branches';
-import { getComponentData } from '../../../api/components';
-import { getComponentNavigation } from '../../../api/nav';
-import { doAsync } from '../../../helpers/testUtils';
-
-beforeEach(() => {
- (getBranches as jest.Mock<any>).mockClear();
- (getComponentData as jest.Mock<any>).mockClear();
- (getComponentNavigation as jest.Mock<any>).mockClear();
-});
-
-it('changes component', () => {
- const Inner = () => <div />;
-
- const wrapper = shallow(
- <ProjectContainer location={{ query: { id: 'foo' } }}>
- <Inner />
- </ProjectContainer>
- );
- (wrapper.instance() as ProjectContainer).mounted = true;
- wrapper.setState({
- branches: [{ isMain: true }],
- component: { qualifier: 'TRK', visibility: 'public' },
- loading: false
- });
-
- (wrapper.find(Inner).prop('onComponentChange') as Function)({ visibility: 'private' });
- expect(wrapper.state().component).toEqual({ qualifier: 'TRK', visibility: 'private' });
-});
-
-it("loads branches for module's project", () => {
- (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
- (getComponentData as jest.Mock<any>).mockImplementation(() => Promise.resolve({}));
- (getComponentNavigation as jest.Mock<any>).mockImplementation(() =>
- Promise.resolve({
- breadcrumbs: [
- { key: 'projectKey', name: 'project', qualifier: 'TRK' },
- { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
- ]
- })
- );
-
- mount(
- <ProjectContainer location={{ query: { id: 'moduleKey' } }}>
- <div />
- </ProjectContainer>
- );
-
- return doAsync().then(() => {
- expect(getBranches).toBeCalledWith('projectKey');
- expect(getComponentData).toBeCalledWith('moduleKey', undefined);
- expect(getComponentNavigation).toBeCalledWith('moduleKey');
- });
-});
-
-it("doesn't load branches portfolio", () => {
- (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
- (getComponentData as jest.Mock<any>).mockImplementation(() => Promise.resolve({}));
- (getComponentNavigation as jest.Mock<any>).mockImplementation(() =>
- Promise.resolve({
- breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }]
- })
- );
-
- mount(
- <ProjectContainer location={{ query: { id: 'portfolioKey' } }}>
- <div />
- </ProjectContainer>
- );
-
- return doAsync().then(() => {
- expect(getBranches).not.toBeCalled();
- expect(getComponentData).toBeCalledWith('portfolioKey', undefined);
- expect(getComponentNavigation).toBeCalledWith('portfolioKey');
- });
-});
-
-it('updates branches on change', () => {
- (getBranches as jest.Mock<any>).mockImplementation(() => Promise.resolve([]));
- const Inner = () => <div />;
- const wrapper = shallow(
- <ProjectContainer location={{ query: { id: 'portfolioKey' } }}>
- <Inner />
- </ProjectContainer>
- );
- (wrapper.instance() as ProjectContainer).mounted = true;
- wrapper.setState({
- branches: [{ isMain: true }],
- component: { breadcrumbs: [{ key: 'projectKey', name: 'project', qualifier: 'TRK' }] },
- loading: false
- });
- (wrapper.find(Inner).prop('onBranchesChange') as Function)();
- expect(getBranches).toBeCalledWith('projectKey');
-});
--- /dev/null
+/*
+ * 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 * as React from 'react';
+import ProjectPageExtension from './ProjectPageExtension';
+import { Component } from '../../types';
+
+interface Props {
+ component: Component;
+ location: { query: { id: string } };
+}
+
+export default function PortfolioDashboard(props: Props) {
+ return (
+ <ProjectPageExtension
+ {...props}
+ params={{ pluginKey: 'governance', extensionKey: 'governance' }}
+ />
+ );
+}
+++ /dev/null
-/*
- * 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.
- */
-// @flow
-import React from 'react';
-import ProjectPageExtension from './ProjectPageExtension';
-
-export default function ViewDashboard(props /*: Object */) {
- return (
- <ProjectPageExtension
- location={props.location}
- params={{ pluginKey: 'governance', extensionKey: 'governance' }}
- />
- );
-}
interface Props {
branches: Branch[];
- currentBranch: Branch;
+ currentBranch?: Branch;
component: Component;
conf: ComponentConfiguration;
location: {};
breadcrumbs={this.props.component.breadcrumbs}
/>
- <ComponentNavBranch
- branches={this.props.branches}
- currentBranch={this.props.currentBranch}
- // to close dropdown on any location change
- location={this.props.location}
- project={this.props.component}
- />
+ {this.props.currentBranch &&
+ <ComponentNavBranch
+ branches={this.props.branches}
+ currentBranch={this.props.currentBranch}
+ // to close dropdown on any location change
+ location={this.props.location}
+ project={this.props.component}
+ />}
<ComponentNavMeta
branch={this.props.currentBranch}
];
interface Props {
- branch: Branch;
+ branch?: Branch;
component: Component;
conf: ComponentConfiguration;
location?: any;
}
renderDashboardLink() {
- if (isShortLivingBranch(this.props.branch)) {
+ if (this.props.branch && isShortLivingBranch(this.props.branch)) {
return null;
}
<Link
to={{
pathname,
- query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
}}
activeClassName="active">
{translate('overview.page')}
<Link
to={{
pathname: '/code',
- query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
}}
activeClassName="active">
{this.isView() || this.isApplication()
return null;
}
- if (isShortLivingBranch(this.props.branch)) {
+ if (this.props.branch && isShortLivingBranch(this.props.branch)) {
return null;
}
<Link
to={{
pathname: '/project/activity',
- query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
}}
activeClassName="active">
{translate('project_activity.page')}
to={{
pathname: '/project/issues',
query: {
- branch: getBranchName(this.props.branch),
+ branch: this.props.branch && getBranchName(this.props.branch),
id: this.props.component.key,
resolved: 'false'
}
}
renderComponentMeasuresLink() {
- if (isShortLivingBranch(this.props.branch)) {
+ if (this.props.branch && isShortLivingBranch(this.props.branch)) {
return null;
}
<Link
to={{
pathname: '/component_measures',
- query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
}}
activeClassName="active">
{translate('layout.measures')}
}
renderAdministration() {
- if (isShortLivingBranch(this.props.branch)) {
+ if (this.props.branch && isShortLivingBranch(this.props.branch)) {
return null;
}
}
renderAdministrationLinks() {
- return isLongLivingBranch(this.props.branch)
+ return this.props.branch && isLongLivingBranch(this.props.branch)
? [this.renderSettingsLink()]
: [
this.renderSettingsLink(),
<Link
to={{
pathname: '/project/settings',
- query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
}}
activeClassName="active">
{translate('project_settings.page')}
import { isShortLivingBranch } from '../../../../helpers/branches';
interface Props {
- branch: Branch;
+ branch?: Branch;
component: Component;
conf: ComponentConfiguration;
incremental?: boolean;
);
}
- if (props.component.analysisDate && props.branch.isMain) {
+ if (props.component.analysisDate && (!props.branch || props.branch.isMain)) {
metaList.push(
<li key="analysisDate">
<DateTimeFormatter date={props.component.analysisDate} />
);
}
- if (props.component.version && props.branch.isMain) {
+ if (props.component.version && (!props.branch || props.branch.isMain)) {
metaList.push(
<li key="version">
Version {props.component.version}
);
}
- if (isShortLivingBranch(props.branch)) {
+ if (props.branch && isShortLivingBranch(props.branch)) {
metaList.push(
<li className="navbar-context-meta-branch" key="branch-status">
<BranchStatus branch={props.branch} />
import ProjectAdminContainer from '../components/ProjectAdminContainer';
import ProjectPageExtension from '../components/extensions/ProjectPageExtension';
import ProjectAdminPageExtension from '../components/extensions/ProjectAdminPageExtension';
-import ViewDashboard from '../components/extensions/ViewDashboard';
+import PortfolioDashboard from '../components/extensions/PortfolioDashboard';
import PortfoliosPage from '../components/extensions/PortfoliosPage';
import AdminContainer from '../components/AdminContainer';
import GlobalPageExtension from '../components/extensions/GlobalPageExtension';
<Route
getComponent={() =>
- import('../components/ProjectContainer').then(i => i.default)}>
+ import('../components/ComponentContainer').then(i => i.default)}>
<Route path="code" childRoutes={codeRoutes} />
<Route path="component_measures" childRoutes={componentMeasuresRoutes} />
<Route path="custom_measures" childRoutes={customMeasuresRoutes} />
{projectAdminRoutes}
</Route>
<Route path="project_roles" childRoutes={projectPermissionsRoutes} />
- <Route path="portfolio" component={ViewDashboard} />
+ <Route path="portfolio" component={PortfolioDashboard} />
</Route>
<Route component={AdminContainer}>
import { Component, Branch } from '../../../app/types';
interface Props {
- branch: Branch;
+ branch?: Branch;
component: Component;
location: { query: { [x: string]: string } };
}
this.setState({ loading: true });
const isPortfolio = ['VW', 'SVW'].includes(component.qualifier);
- retrieveComponentChildren(component.key, isPortfolio, getBranchName(branch))
+ retrieveComponentChildren(component.key, isPortfolio, branch && getBranchName(branch))
.then(() => {
addComponent(component);
this.handleUpdate();
this.setState({ loading: true });
const isPortfolio = ['VW', 'SVW'].includes(this.props.component.qualifier);
- retrieveComponent(componentKey, isPortfolio, getBranchName(this.props.branch))
+ retrieveComponent(
+ componentKey,
+ isPortfolio,
+ this.props.branch && getBranchName(this.props.branch)
+ )
.then(r => {
if (this.mounted) {
if (['FIL', 'UTS'].includes(r.component.qualifier)) {
return;
}
const isPortfolio = ['VW', 'SVW'].includes(this.props.component.qualifier);
- loadMoreChildren(baseComponent.key, page + 1, isPortfolio, getBranchName(this.props.branch))
+ loadMoreChildren(
+ baseComponent.key,
+ page + 1,
+ isPortfolio,
+ this.props.branch && getBranchName(this.props.branch)
+ )
.then(r => {
if (this.mounted) {
this.setState({
total,
sourceViewer
} = this.state;
- const branchName = getBranchName(branch);
+ const branchName = branch && getBranchName(branch);
const shouldShowBreadcrumbs = breadcrumbs.length > 1;
import '../style.css';
/*:: type Props = {|
- branch: {},
+ branch?: {},
component: Component,
currentUser: { isLoggedIn: boolean },
location: { pathname: string, query: RawQuery },
const filteredKeys = metricsKey.filter(
key => !metrics[key].hidden && !['DATA', 'DISTRIB'].includes(metrics[key].type)
);
- fetchMeasures(component.key, filteredKeys, getBranchName(branch)).then(
+ fetchMeasures(component.key, filteredKeys, branch && getBranchName(branch)).then(
({ measures, leakPeriod }) => {
if (this.mounted) {
this.setState({
});
this.props.router.push({
pathname: this.props.location.pathname,
- query: { ...query, branch: getBranchName(this.props.branch), id: this.props.component.key }
+ query: {
+ ...query,
+ branch: this.props.branch && getBranchName(this.props.branch),
+ id: this.props.component.key
+ }
});
};
{metric != null &&
<MeasureContentContainer
- branch={getBranchName(branch)}
+ branch={branch && getBranchName(branch)}
className="layout-page-main"
currentUser={this.props.currentUser}
rootComponent={component}
{metric == null &&
hasBubbleChart(query.metric) &&
<MeasureOverviewContainer
- branch={getBranchName(branch)}
+ branch={branch && getBranchName(branch)}
className="layout-page-main"
rootComponent={component}
currentUser={this.props.currentUser}
/*::
type Props = {
- branch: { name: string },
+ branch?: { name: string },
component: {
analysisDate?: string,
id: string,
if (['FIL', 'UTS'].includes(component.qualifier)) {
return (
<div className="page page-limited">
- <SourceViewer branch={getBranchName(branch)} component={component.key} />
+ <SourceViewer branch={branch && getBranchName(branch)} component={component.key} />
</div>
);
}
/*::
type Props = {
- branch: { name: string },
+ branch?: { name: string },
component: Component,
onComponentChange: {} => void
};
return getMeasuresAndMeta(component.key, METRICS, {
additionalFields: 'metrics,periods',
- branch: getBranchName(branch)
+ branch: branch && getBranchName(branch)
}).then(
r => {
if (this.mounted) {
const metrics = uniq(HISTORY_METRICS_LIST.concat(graphMetrics));
return getAllTimeMachineData(component.key, metrics, {
- branch: getBranchName(branch)
+ branch: branch && getBranchName(branch)
}).then(r => {
if (this.mounted) {
const history /*: History */ = {};
const leakPeriod =
component.qualifier === 'APP' ? this.getApplicationLeakPeriod() : getLeakPeriod(periods);
- const branchName = getBranchName(branch);
+ const branchName = branch && getBranchName(branch);
const domainProps = {
branch: branchName,
component,
/*::
type Props = {
- branch: {},
+ branch?: {},
location: { pathname: string, query: RawQuery },
component: {
configuration?: { showHistory: boolean },
}
this.context.router.replace({
pathname: props.location.pathname,
- query: { ...serializeUrlQuery(newQuery), branch: getBranchName(props.branch) }
+ query: {
+ ...serializeUrlQuery(newQuery),
+ branch: props.branch && getBranchName(props.branch)
+ }
});
}
}
[string]: string
} */
) => {
- const parameters = { project, p, ps, branch: getBranchName(this.props.branch) };
+ const parameters = {
+ project,
+ p,
+ ps,
+ branch: this.props.branch && getBranchName(this.props.branch)
+ };
return api
.getProjectActivity({ ...parameters, ...additional })
.then(({ analyses, paging }) => ({
return Promise.resolve([]);
}
return getAllTimeMachineData(this.props.component.key, metrics, {
- branch: getBranchName(this.props.branch)
+ branch: this.props.branch && getBranchName(this.props.branch)
}).then(
({ measures }) =>
measures.map(measure => ({
pathname: this.props.location.pathname,
query: {
...query,
- branch: getBranchName(this.props.branch),
+ branch: this.props.branch && getBranchName(this.props.branch),
id: this.props.component.key
}
});
export default class DefinitionsList extends React.PureComponent {
static propTypes = {
- branch: PropTypes.object,
+ branch: PropTypes.string,
component: PropTypes.object,
settings: PropTypes.array.isRequired
};