diff --git a/x-pack/legacy/plugins/code/common/commit_utils.test.ts b/x-pack/legacy/plugins/code/common/commit_utils.test.ts
new file mode 100644
index 0000000000000..9deb15e9a26e7
--- /dev/null
+++ b/x-pack/legacy/plugins/code/common/commit_utils.test.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { parseCommitMessage } from './commit_utils';
+
+describe('Commit Utils', () => {
+ describe('parseCommitMessage', () => {
+ it('parses the summary from a commit message', () => {
+ const message = "This is a summary\n\nAnd here's the body";
+ const { summary } = parseCommitMessage(message);
+
+ expect(summary).toEqual('This is a summary');
+ });
+
+ it('parses the body from a commit message', () => {
+ const message = "This is a summary\n\nAnd here's the body";
+ const { body } = parseCommitMessage(message);
+
+ expect(body).toEqual("And here's the body");
+ });
+
+ it('includes the second line as body, if erroneously present', () => {
+ const messageWithSecondLine = 'summary\nsecond\ndescription';
+ const { summary, body } = parseCommitMessage(messageWithSecondLine);
+
+ expect(summary).toEqual('summary');
+ expect(body).toEqual('second\ndescription');
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/code/common/commit_utils.ts b/x-pack/legacy/plugins/code/common/commit_utils.ts
new file mode 100644
index 0000000000000..4a5a6d9f2da5a
--- /dev/null
+++ b/x-pack/legacy/plugins/code/common/commit_utils.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+const parseCommitMessage: (message: string) => { summary: string; body: string } = message => {
+ const [summary, ...rest] = message.split('\n');
+ const body = rest.join('\n').trim();
+
+ return { summary, body };
+};
+
+export { parseCommitMessage };
diff --git a/x-pack/legacy/plugins/code/public/components/commits/__snapshots__/commit.test.tsx.snap b/x-pack/legacy/plugins/code/public/components/commits/__snapshots__/commit.test.tsx.snap
new file mode 100644
index 0000000000000..fc4db9ed95bf1
--- /dev/null
+++ b/x-pack/legacy/plugins/code/public/components/commits/__snapshots__/commit.test.tsx.snap
@@ -0,0 +1,235 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Commit component renders correctly for a commit 1`] = `
+
+
+
+
+
+
+
+
+ This is my commit message
+
+
+
+
+
+
+
+
+ Committed on 11/11/2222 by committer
+
+
+
+
+
+
+
+
+
+ This is the description
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/x-pack/legacy/plugins/code/public/components/commits/commit.test.tsx b/x-pack/legacy/plugins/code/public/components/commits/commit.test.tsx
new file mode 100644
index 0000000000000..1c87f7cc72235
--- /dev/null
+++ b/x-pack/legacy/plugins/code/public/components/commits/commit.test.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+import toJson from 'enzyme-to-json';
+
+import { Commit } from './commit';
+import { CommitInfo } from '../../../model/commit';
+
+describe('Commit component', () => {
+ test('renders correctly for a commit', () => {
+ const commitInfo: CommitInfo = {
+ updated: new Date(Date.UTC(2222, 10, 11)),
+ message: 'This is my commit message\n\nThis is the description',
+ author: 'author',
+ committer: 'committer',
+ id: '4ba67b8',
+ parents: ['9817575'],
+ treeId: '96440ceb55e04a99d33c1c8ee021400a680fbf74',
+ };
+ const wrapper = mount(
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+});
diff --git a/x-pack/legacy/plugins/code/public/components/commits/commit.tsx b/x-pack/legacy/plugins/code/public/components/commits/commit.tsx
new file mode 100644
index 0000000000000..31020f6598393
--- /dev/null
+++ b/x-pack/legacy/plugins/code/public/components/commits/commit.tsx
@@ -0,0 +1,119 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import {
+ EuiButtonIcon,
+ EuiButtonEmpty,
+ EuiFlexGroup,
+ EuiLink,
+ EuiPanel,
+ EuiText,
+ EuiTextColor,
+ EuiCopy,
+ EuiTitle,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { CommitInfo } from '../../../model/commit';
+import { PathTypes } from '../../common/types';
+import { RepositoryUtils } from '../../../common/repository_utils';
+import { parseCommitMessage } from '../../../common/commit_utils';
+
+const COMMIT_ID_LENGTH = 8;
+
+const RepoLink = ({ repoUri }: { repoUri: string }) => {
+ const repoOrg = RepositoryUtils.orgNameFromUri(repoUri);
+ const repoName = RepositoryUtils.repoNameFromUri(repoUri);
+ const repoPath = `#/${repoUri}`;
+
+ return (
+ <>
+
+ {repoOrg} / {repoName}
+
+
+ •
+
+ >
+ );
+};
+
+interface ActionProps {
+ repoUri: string;
+ commitId: string;
+}
+
+const copyLabel = i18n.translate('xpack.code.commits.copyCommitAriaLabel', {
+ defaultMessage: 'Copy the full commit ID',
+});
+const revisionLinkLabel = i18n.translate('xpack.code.commits.revisionLinkAriaLabel', {
+ defaultMessage: 'View the project at this commit',
+});
+
+const CommitActions = ({ commitId, repoUri }: ActionProps) => {
+ const revisionPath = `#/${repoUri}/${PathTypes.tree}/${commitId}`;
+
+ return (
+
+
+ {copy => }
+
+
+ {commitId}
+
+
+
+ );
+};
+
+interface Props {
+ commit: CommitInfo;
+ date: string;
+ repoUri: string;
+ showRepoLink: boolean;
+}
+
+export const Commit = (props: Props) => {
+ const { date, commit, repoUri, showRepoLink } = props;
+ const { message, committer, id } = commit;
+ const { summary, body } = parseCommitMessage(message);
+ const commitId = id.substring(0, COMMIT_ID_LENGTH);
+
+ return (
+
+
+
+
+ {summary}
+
+
+ {showRepoLink && }
+
+
+
+
+
+ {body}
+
+
+
+
+
+ );
+};
diff --git a/x-pack/legacy/plugins/code/public/components/diff_page/commit_link.tsx b/x-pack/legacy/plugins/code/public/components/commits/commit_link.tsx
similarity index 100%
rename from x-pack/legacy/plugins/code/public/components/diff_page/commit_link.tsx
rename to x-pack/legacy/plugins/code/public/components/commits/commit_link.tsx
diff --git a/x-pack/legacy/plugins/code/public/components/commits/group.tsx b/x-pack/legacy/plugins/code/public/components/commits/group.tsx
new file mode 100644
index 0000000000000..01c2844d38622
--- /dev/null
+++ b/x-pack/legacy/plugins/code/public/components/commits/group.tsx
@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTextColor } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { CommitInfo } from '../../../model/commit';
+import { Commit } from './commit';
+
+interface Props {
+ commits: CommitInfo[];
+ date: string;
+ repoUri: string;
+}
+
+export const CommitGroup = (props: Props) => {
+ const commitList = props.commits.map(commit => (
+
+ ));
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{commitList}
+
+ );
+};
diff --git a/x-pack/legacy/plugins/code/public/components/main/commit_history.tsx b/x-pack/legacy/plugins/code/public/components/commits/history.tsx
similarity index 57%
rename from x-pack/legacy/plugins/code/public/components/main/commit_history.tsx
rename to x-pack/legacy/plugins/code/public/components/commits/history.tsx
index e731c43fd439f..590e081dc2967 100644
--- a/x-pack/legacy/plugins/code/public/components/main/commit_history.tsx
+++ b/x-pack/legacy/plugins/code/public/components/commits/history.tsx
@@ -4,97 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import {
- EuiButton,
- EuiFlexGroup,
- EuiFlexItem,
- EuiLoadingSpinner,
- EuiPanel,
- EuiText,
- EuiTextColor,
-} from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n/react';
-
import _ from 'lodash';
import moment from 'moment';
import React from 'react';
import { connect } from 'react-redux';
import { i18n } from '@kbn/i18n';
+import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import { CommitGroup } from './group';
import { CommitInfo } from '../../../model/commit';
-import { CommitLink } from '../diff_page/commit_link';
import { RootState } from '../../reducers';
import { hasMoreCommitsSelector, treeCommitsSelector } from '../../selectors';
import { fetchMoreCommits } from '../../actions';
-const COMMIT_ID_LENGTH = 8;
-
-const Commit = (props: { commit: CommitInfo; date: string; repoUri: string }) => {
- const { date, commit } = props;
- const { message, committer, id } = commit;
- const commitId = id
- .split('')
- .slice(0, COMMIT_ID_LENGTH)
- .join('');
- return (
-
-
-
- {message}
-
-
-
- {committer} · {date}
-
-
-
-
-
-
-
- );
-};
-
-const CommitGroup = (props: { commits: CommitInfo[]; date: string; repoUri: string }) => {
- const commitList = props.commits.map(commit => (
-
- ));
- return (
-
-
-
-
-
-
-
-
-
- {' '}
- {}
-
-
-
-
-
-
{commitList}
-
- );
-};
-
-export const CommitHistoryLoading = () => (
+const CommitHistoryLoading = () => (
);
-export const PageButtons = (props: {
- loading?: boolean;
- disabled: boolean;
- onClick: () => void;
-}) => (
+const PageButtons = (props: { loading?: boolean; disabled: boolean; onClick: () => void }) => (