box-sizing: border-box;
}
-.code-truncated {
- display: inline-block;
- vertical-align: text-top;
- max-width: 50vw;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
.code-name-cell {
max-width: 0;
}
-.code-name-cell .code-truncated {
- max-width: 100%;
+@media (max-width: 1200px) {
+ .code-name-cell .badge,
+ .code-name-cell .outline-badge {
+ display: none;
+ }
}
.code-search {
*/
import * as React from 'react';
import { Link } from 'react-router';
-import Truncated from './Truncated';
import * as theme from '../../../app/theme';
import QualifierIcon from '../../../components/icons-components/QualifierIcon';
import { getBranchLikeQuery } from '../../../helpers/branches';
import LongLivingBranchIcon from '../../../components/icons-components/LongLivingBranchIcon';
import { translate } from '../../../helpers/l10n';
-function getTooltip(component: T.ComponentMeasure) {
+export function getTooltip(component: T.ComponentMeasure) {
const isFile = component.qualifier === 'FIL' || component.qualifier === 'UTS';
if (isFile && component.path) {
return component.path + '\n\n' + component.key;
}
}
-function mostCommitPrefix(strings: string[]) {
+export function mostCommonPrefix(strings: string[]) {
const sortedStrings = strings.slice(0).sort();
const firstString = sortedStrings[0];
const firstStringLength = firstString.length;
return prefix.substr(0, prefix.length - lastPrefixPart.length);
}
-interface Props {
+export interface Props {
branchLike?: T.BranchLike;
canBrowse?: boolean;
component: T.ComponentMeasure;
rootComponent: T.ComponentMeasure;
}
-export default class ComponentName extends React.PureComponent<Props> {
- render() {
- const { branchLike, component, rootComponent, previous, canBrowse = false } = this.props;
- const areBothDirs = component.qualifier === 'DIR' && previous && previous.qualifier === 'DIR';
- const prefix =
- areBothDirs && previous !== undefined
- ? mostCommitPrefix([component.name + '/', previous.name + '/'])
- : '';
- const name = prefix ? (
- <span>
- <span style={{ color: theme.secondFontColor }}>{prefix}</span>
- <span>{component.name.substr(prefix.length)}</span>
- </span>
- ) : (
- component.name
- );
+export default function ComponentName({
+ branchLike,
+ component,
+ rootComponent,
+ previous,
+ canBrowse = false
+}: Props) {
+ const areBothDirs = component.qualifier === 'DIR' && previous && previous.qualifier === 'DIR';
+ const prefix =
+ areBothDirs && previous !== undefined
+ ? mostCommonPrefix([component.name + '/', previous.name + '/'])
+ : '';
+ const name = prefix ? (
+ <span>
+ <span style={{ color: theme.secondFontColor }}>{prefix}</span>
+ <span>{component.name.substr(prefix.length)}</span>
+ </span>
+ ) : (
+ component.name
+ );
- let inner = null;
+ let inner = null;
- if (component.refKey && component.qualifier !== 'SVW') {
- const branch = rootComponent.qualifier === 'APP' ? { branch: component.branch } : {};
- inner = (
- <Link
- className="link-with-icon"
- to={{ pathname: '/dashboard', query: { id: component.refKey, ...branch } }}>
- <QualifierIcon qualifier={component.qualifier} /> <span>{name}</span>
- </Link>
- );
- } else if (canBrowse) {
- const query = { id: rootComponent.key, ...getBranchLikeQuery(branchLike) };
- if (component.key !== rootComponent.key) {
- Object.assign(query, { selected: component.key });
- }
- inner = (
- <Link className="link-with-icon" to={{ pathname: '/code', query }}>
- <QualifierIcon qualifier={component.qualifier} /> <span>{name}</span>
- </Link>
- );
- } else {
- inner = (
- <span>
- <QualifierIcon qualifier={component.qualifier} /> {name}
- </span>
- );
+ if (component.refKey && component.qualifier !== 'SVW') {
+ const branch = rootComponent.qualifier === 'APP' ? { branch: component.branch } : {};
+ inner = (
+ <Link
+ className="link-with-icon"
+ to={{ pathname: '/dashboard', query: { id: component.refKey, ...branch } }}>
+ <QualifierIcon qualifier={component.qualifier} /> <span>{name}</span>
+ </Link>
+ );
+ } else if (canBrowse) {
+ const query = { id: rootComponent.key, ...getBranchLikeQuery(branchLike) };
+ if (component.key !== rootComponent.key) {
+ Object.assign(query, { selected: component.key });
}
+ inner = (
+ <Link className="link-with-icon" to={{ pathname: '/code', query }}>
+ <QualifierIcon qualifier={component.qualifier} /> <span>{name}</span>
+ </Link>
+ );
+ } else {
+ inner = (
+ <span>
+ <QualifierIcon qualifier={component.qualifier} /> {name}
+ </span>
+ );
+ }
- if (rootComponent.qualifier === 'APP') {
- inner = (
- <>
+ if (rootComponent.qualifier === 'APP') {
+ return (
+ <span className="max-width-100 display-inline-flex-center">
+ <span className="text-ellipsis" title={getTooltip(component)}>
{inner}
- {component.branch ? (
- <>
- <LongLivingBranchIcon className="spacer-left little-spacer-right" />
- <span className="note">{component.branch}</span>
- </>
- ) : (
- <span className="spacer-left outline-badge">{translate('branches.main_branch')}</span>
- )}
- </>
- );
- }
-
- return <Truncated title={getTooltip(component)}>{inner}</Truncated>;
+ </span>
+ {component.branch ? (
+ <span className="text-ellipsis spacer-left">
+ <LongLivingBranchIcon className="little-spacer-right" />
+ <span className="note">{component.branch}</span>
+ </span>
+ ) : (
+ <span className="spacer-left outline-badge flex-1">
+ {translate('branches.main_branch')}
+ </span>
+ )}
+ </span>
+ );
+ } else {
+ return (
+ <span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title={getTooltip(component)}>
+ {inner}
+ </span>
+ );
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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';
-
-interface Props {
- children: React.ReactNode;
- title: string;
-}
-
-export default function Truncated({ children, title }: Props) {
- return (
- <span className="code-truncated" title={title}>
- {children}
- </span>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 { shallow } from 'enzyme';
+import ComponentName, { getTooltip, mostCommonPrefix, Props } from '../ComponentName';
+import { mockMainBranch, mockComponentMeasure } from '../../../../helpers/testMocks';
+
+describe('#getTooltip', () => {
+ it('should correctly format component information', () => {
+ expect(getTooltip(mockComponentMeasure(true))).toMatchSnapshot();
+ expect(getTooltip(mockComponentMeasure(true, { qualifier: 'UTS' }))).toMatchSnapshot();
+ expect(getTooltip(mockComponentMeasure(true, { path: undefined }))).toMatchSnapshot();
+ expect(getTooltip(mockComponentMeasure(false))).toMatchSnapshot();
+ });
+});
+
+describe('#mostCommonPrefix', () => {
+ it('should correctly find the common path prefix', () => {
+ expect(mostCommonPrefix(['src/main/ts/tests', 'src/main/java/tests'])).toEqual('src/main/');
+ expect(mostCommonPrefix(['src/main/ts/app', 'src/main/ts/app'])).toEqual('src/main/ts/');
+ expect(mostCommonPrefix(['src/main/ts', 'lib/main/ts'])).toEqual('');
+ });
+});
+
+describe('#ComponentName', () => {
+ it('should render correctly for files', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ canBrowse: true })).toMatchSnapshot();
+ expect(
+ shallowRender({ rootComponent: mockComponentMeasure(false, { qualifier: 'TRK' }) })
+ ).toMatchSnapshot();
+ expect(
+ shallowRender({ rootComponent: mockComponentMeasure(false, { qualifier: 'APP' }) })
+ ).toMatchSnapshot();
+ expect(
+ shallowRender({
+ component: mockComponentMeasure(true, { branch: 'foo' }),
+ rootComponent: mockComponentMeasure(false, { qualifier: 'APP' })
+ })
+ ).toMatchSnapshot();
+ });
+
+ it('should render correctly for dirs', () => {
+ expect(
+ shallowRender({
+ component: mockComponentMeasure(false, { name: 'src/main/ts/app', qualifier: 'DIR' }),
+ previous: mockComponentMeasure(false, { name: 'src/main/ts/tests', qualifier: 'DIR' })
+ })
+ ).toMatchSnapshot();
+ expect(
+ shallowRender({
+ component: mockComponentMeasure(false, { name: 'src', qualifier: 'DIR' }),
+ previous: mockComponentMeasure(false, { name: 'lib', qualifier: 'DIR' })
+ })
+ ).toMatchSnapshot();
+ });
+
+ it('should render correctly for refs', () => {
+ expect(
+ shallowRender({
+ component: mockComponentMeasure(false, {
+ branch: 'foo',
+ refKey: 'src/main/ts/app',
+ qualifier: 'TRK'
+ })
+ })
+ ).toMatchSnapshot();
+ expect(
+ shallowRender({
+ component: mockComponentMeasure(false, {
+ branch: 'foo',
+ refKey: 'src/main/ts/app',
+ qualifier: 'TRK'
+ }),
+ rootComponent: mockComponentMeasure(false, { qualifier: 'APP' })
+ })
+ ).toMatchSnapshot();
+ });
+});
+
+function shallowRender(props: Partial<Props> = {}) {
+ return shallow(
+ <ComponentName
+ branchLike={mockMainBranch()}
+ component={mockComponentMeasure(true)}
+ rootComponent={mockComponentMeasure()}
+ {...props}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`#ComponentName should render correctly for dirs 1`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="src/main/ts/app
+
+foo"
+>
+ <span>
+ <QualifierIcon
+ qualifier="DIR"
+ />
+
+ <span>
+ <span
+ style={
+ Object {
+ "color": "#777",
+ }
+ }
+ >
+ src/main/ts/
+ </span>
+ <span>
+ app
+ </span>
+ </span>
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for dirs 2`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="src
+
+foo"
+>
+ <span>
+ <QualifierIcon
+ qualifier="DIR"
+ />
+
+ src
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for files 1`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="src/index.tsx
+
+foo:src/index.tsx"
+>
+ <span>
+ <QualifierIcon
+ qualifier="FIL"
+ />
+
+ index.tsx
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for files 2`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="src/index.tsx
+
+foo:src/index.tsx"
+>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/code",
+ "query": Object {
+ "id": "foo",
+ "selected": "foo:src/index.tsx",
+ },
+ }
+ }
+ >
+ <QualifierIcon
+ qualifier="FIL"
+ />
+
+ <span>
+ index.tsx
+ </span>
+ </Link>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for files 3`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="src/index.tsx
+
+foo:src/index.tsx"
+>
+ <span>
+ <QualifierIcon
+ qualifier="FIL"
+ />
+
+ index.tsx
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for files 4`] = `
+<span
+ className="max-width-100 display-inline-flex-center"
+>
+ <span
+ className="text-ellipsis"
+ title="src/index.tsx
+
+foo:src/index.tsx"
+ >
+ <span>
+ <QualifierIcon
+ qualifier="FIL"
+ />
+
+ index.tsx
+ </span>
+ </span>
+ <span
+ className="spacer-left outline-badge flex-1"
+ >
+ branches.main_branch
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for files 5`] = `
+<span
+ className="max-width-100 display-inline-flex-center"
+>
+ <span
+ className="text-ellipsis"
+ title="src/index.tsx
+
+foo:src/index.tsx"
+ >
+ <span>
+ <QualifierIcon
+ qualifier="FIL"
+ />
+
+ index.tsx
+ </span>
+ </span>
+ <span
+ className="text-ellipsis spacer-left"
+ >
+ <LongLivingBranchIcon
+ className="little-spacer-right"
+ />
+ <span
+ className="note"
+ >
+ foo
+ </span>
+ </span>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for refs 1`] = `
+<span
+ className="max-width-100 display-inline-block text-ellipsis"
+ title="Foo
+
+foo"
+>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "id": "src/main/ts/app",
+ },
+ }
+ }
+ >
+ <QualifierIcon
+ qualifier="TRK"
+ />
+
+ <span>
+ Foo
+ </span>
+ </Link>
+</span>
+`;
+
+exports[`#ComponentName should render correctly for refs 2`] = `
+<span
+ className="max-width-100 display-inline-flex-center"
+>
+ <span
+ className="text-ellipsis"
+ title="Foo
+
+foo"
+ >
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": "foo",
+ "id": "src/main/ts/app",
+ },
+ }
+ }
+ >
+ <QualifierIcon
+ qualifier="TRK"
+ />
+
+ <span>
+ Foo
+ </span>
+ </Link>
+ </span>
+ <span
+ className="text-ellipsis spacer-left"
+ >
+ <LongLivingBranchIcon
+ className="little-spacer-right"
+ />
+ <span
+ className="note"
+ >
+ foo
+ </span>
+ </span>
+</span>
+`;
+
+exports[`#getTooltip should correctly format component information 1`] = `
+"src/index.tsx
+
+foo:src/index.tsx"
+`;
+
+exports[`#getTooltip should correctly format component information 2`] = `
+"src/index.tsx
+
+foo:src/index.tsx"
+`;
+
+exports[`#getTooltip should correctly format component information 3`] = `
+"index.tsx
+
+foo:src/index.tsx"
+`;
+
+exports[`#getTooltip should correctly format component information 4`] = `
+"Foo
+
+foo"
+`;