type GetOrganizationNavigation = {
canAdmin: boolean,
- isDefault: boolean
+ canDelete: boolean,
+ canProvisionProjects: boolean,
+ isDefault: boolean,
+ pages: Array<{ key: string, name: string }>,
+ adminPages: Array<{ key: string, name: string }>
};
export const getOrganization = (key: string): Promise<GetOrganizationType> => {
--- /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 { connect } from 'react-redux';
+import Extension from './Extension';
+import ExtensionNotFound from './ExtensionNotFound';
+import { getOrganizationByKey } from '../../../store/rootReducer';
+import type { Organization } from '../../../store/organizations/duck';
+
+type Props = {
+ organization: Organization,
+ params: {
+ extensionKey: string,
+ organizationKey: string,
+ pluginKey: string
+ }
+};
+
+class OrganizationPageExtension extends React.PureComponent {
+ props: Props;
+
+ render() {
+ const { extensionKey, pluginKey } = this.props.params;
+ const { organization } = this.props;
+
+ let pages = organization.pages || [];
+ if (organization.canAdmin && organization.adminPages) {
+ pages = pages.concat(organization.adminPages);
+ }
+
+ const extension = pages.find(p => p.key === `${pluginKey}/${extensionKey}`);
+ return extension
+ ? <Extension extension={extension} options={{ organization }} />
+ : <ExtensionNotFound />;
+ }
+}
+
+const mapStateToProps = (state, ownProps: Props) => ({
+ organization: getOrganizationByKey(state, ownProps.params.organizationKey)
+});
+
+export default connect(mapStateToProps)(OrganizationPageExtension);
import { Link } from 'react-router';
import { translate } from '../../../helpers/l10n';
import OrganizationIcon from '../../../components/ui/OrganizationIcon';
+import type { Organization } from '../../../store/organizations/duck';
const ADMIN_PATHS = [
'edit',
export default class OrganizationNavigation extends React.Component {
props: {
location: { pathname: string },
- organization: {
- avatar?: string,
- description?: string,
- key: string,
- name: string,
- canAdmin?: boolean,
- canDelete?: boolean,
- url?: string
- }
+ organization: Organization
};
- renderAdministration() {
- const { organization, location } = this.props;
-
- const adminActive = ADMIN_PATHS.some(path =>
- location.pathname.endsWith(`organizations/${organization.key}/${path}`));
+ renderAdministration(adminActive: boolean) {
+ const { organization } = this.props;
return (
<li className={adminActive ? 'active' : ''}>
{translate('layout.settings')} <i className="icon-dropdown" />
</a>
<ul className="dropdown-menu">
+ {this.renderAdminExtensions()}
<li>
<Link to={`/organizations/${organization.key}/groups`} activeClassName="active">
{translate('user_groups.page')}
);
}
+ renderAdminExtensions() {
+ const extensions = this.props.organization.adminPages || [];
+ return extensions.map(this.renderExtension);
+ }
+
+ renderExtension = (extension: { key: string, name: string }) => {
+ const { organization } = this.props;
+ const pathname = `/organizations/${organization.key}/extension/${extension.key}`;
+ return (
+ <li key={extension.key}>
+ <Link to={pathname} activeClassName="active">
+ {extension.name}
+ </Link>
+ </li>
+ );
+ };
+
+ renderExtensions(moreActive: boolean) {
+ const extensions = this.props.organization.pages || [];
+ if (extensions.length > 0) {
+ return (
+ <li className={moreActive ? 'active' : ''}>
+ <a
+ className="dropdown-toggle"
+ id="organization-navigation-more"
+ data-toggle="dropdown"
+ href="#">
+ {translate('more')} <i className="icon-dropdown" />
+ </a>
+ <ul className="dropdown-menu">
+ {extensions.map(this.renderExtension)}
+ </ul>
+ </li>
+ );
+ } else {
+ return null;
+ }
+ }
+
render() {
const { organization, location } = this.props;
const isHomeActive = location.pathname === `organizations/${organization.key}/projects` ||
location.pathname === `organizations/${organization.key}/projects/favorite`;
+ const adminActive = ADMIN_PATHS.some(path =>
+ location.pathname.endsWith(`organizations/${organization.key}/${path}`));
+
+ const moreActive = !adminActive && location.pathname.includes('/extension/');
+
return (
<nav className="navbar navbar-context page-container" id="context-navigation">
<div className="navbar-context-inner">
{translate('coding_rules.page')}
</Link>
</li>
- {organization.canAdmin && this.renderAdministration()}
+ {this.renderExtensions(moreActive)}
+ {organization.canAdmin && this.renderAdministration(adminActive)}
</ul>
</div>
</div>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import OrganizationPage from './components/OrganizationPage';
+import OrganizationPageExtension from '../../app/components/extensions/OrganizationPageExtension';
import OrganizationProjects from './components/OrganizationProjects';
import OrganizationFavoriteProjects from './components/OrganizationFavoriteProjects';
import OrganizationRules from './components/OrganizationRules';
path: 'quality_profiles',
childRoutes: qualityProfilesRoutes
},
+ {
+ path: 'extension/:pluginKey/:extensionKey',
+ component: OrganizationPageExtension
+ },
{
component: OrganizationAdmin,
childRoutes: [
import { omit, uniq, without } from 'lodash';
export type Organization = {
+ adminPages?: Array<{ key: string, name: string }>,
avatar?: string,
canAdmin?: boolean,
canDelete?: boolean,
description?: string,
key: string,
name: string,
+ pages?: Array<{ key: string, name: string }>,
url?: string
};