* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { sortBy } from 'lodash';
import { Link } from 'react-router';
import { Project } from './types';
import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import Level from '../../../components/ui/Level';
import Tooltip from '../../../components/controls/Tooltip';
+import MetaLink from '../../overview/meta/MetaLink';
+import { orderLinks } from '../../project-admin/links/utils';
import { translateWithParameters, translate } from '../../../helpers/l10n';
interface Props {
project: Project;
}
+type ProjectLink = {
+ id: string;
+ name: string;
+ url: string;
+ type: string;
+};
+
export default function ProjectCard({ project }: Props) {
const isAnalyzed = project.lastAnalysisDate != null;
- const links = sortBy(project.links, 'type');
+
+ const { links } = project;
+ const orderedLinks: ProjectLink[] = orderLinks(
+ links.map((link, i) => {
+ const { href, name, type } = link;
+ return {
+ id: `link-${i}`,
+ name,
+ type,
+ url: href
+ };
+ })
+ );
return (
<div className="account-project-card clearfix">
{links.length > 0 && (
<div className="account-project-links">
<ul className="list-inline">
- {links.map(link => (
- <li key={link.type}>
- <a
- className="link-with-icon"
- href={link.href}
- title={link.name}
- target="_blank"
- rel="nofollow">
- <i className={`icon-color-link icon-${link.type}`} />
- </a>
- </li>
+ {orderedLinks.map(link => (
+ <MetaLink iconOnly={true} key={link.id} link={link} />
))}
</ul>
</div>
links: [{ name: 'n', type: 't', href: 'h' }]
};
const output = shallow(<ProjectCard project={project} />);
- expect(output.find('.account-project-links').find('li').length).toBe(1);
+ expect(output.find('MetaLink').length).toBe(1);
});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+
+type Link = {
+ id: string;
+ name: string;
+ url: string;
+ type: string;
+};
+
+interface Props {
+ iconOnly?: boolean;
+ link: Link;
+}
+
+export default class MetaLink extends React.Component<Props> {}
export default class MetaLink extends React.PureComponent {
/*:: props: {
+ iconOnly?: boolean,
link: Link
};
*/
}
render() {
- const { link } = this.props;
+ const { iconOnly, link } = this.props;
return (
<li>
className="link-with-icon"
href={link.url}
target="_blank"
- onClick={!isClickable(link) && this.handleClick}>
+ onClick={!isClickable(link) && this.handleClick}
+ title={link.name}>
{this.renderLinkIcon(link)}
-
- {link.name}
+ {!iconOnly && `\u00A0${link.name}`}
</a>
{this.state.expanded && (
<div className="little-spacer-top">
};
expect(shallow(<MetaLink link={link} />)).toMatchSnapshot();
+ expect(shallow(<MetaLink iconOnly={true} link={link} />)).toMatchSnapshot();
});
it('should expand and collapse link', () => {
href="scm:git:git@github.com"
onClick={[Function]}
target="_blank"
+ title="Foo"
>
<i
className="icon-color-link icon-detach"
/>
-
- Foo
+ Foo
</a>
</li>
`;
href="scm:git:git@github.com"
onClick={[Function]}
target="_blank"
+ title="Foo"
>
<i
className="icon-color-link icon-detach"
/>
-
- Foo
+ Foo
</a>
<div
className="little-spacer-top"
href="scm:git:git@github.com"
onClick={[Function]}
target="_blank"
+ title="Foo"
>
<i
className="icon-color-link icon-detach"
/>
-
- Foo
+ Foo
</a>
</li>
`;
href="http://example.com"
onClick={false}
target="_blank"
+ title="Foo"
+ >
+ <i
+ className="icon-color-link icon-detach"
+ />
+ Foo
+ </a>
+</li>
+`;
+
+exports[`should match snapshot 2`] = `
+<li>
+ <a
+ className="link-with-icon"
+ href="http://example.com"
+ onClick={false}
+ target="_blank"
+ title="Foo"
>
<i
className="icon-color-link icon-detach"
/>
-
- Foo
</a>
</li>
`;
const [provided, unknown] = partition(links, isProvided);
return [
...sortBy(provided, link => PROVIDED_TYPES.indexOf(link.type)),
- ...sortBy(unknown, link => link.name.toLowerCase())
+ ...sortBy(unknown, link => link.name && link.name.toLowerCase())
];
}