diff --git a/app/assets/javascripts/components/story/StoryCopyIdClipboard.js b/app/assets/javascripts/components/story/StoryCopyIdClipboard.js
new file mode 100644
index 000000000..33425d484
--- /dev/null
+++ b/app/assets/javascripts/components/story/StoryCopyIdClipboard.js
@@ -0,0 +1,17 @@
+import React from "react";
+import Clipboard from "react-clipboard.js";
+
+const StoryCopyIdClipboard = ({ id }) => {
+ return (
+
+ #{id}
+
+ );
+};
+
+export default StoryCopyIdClipboard;
diff --git a/app/assets/javascripts/templates/story.ejs b/app/assets/javascripts/templates/story.ejs
index 9accddcd7..552d0f34b 100644
--- a/app/assets/javascripts/templates/story.ejs
+++ b/app/assets/javascripts/templates/story.ejs
@@ -43,6 +43,7 @@
+
<% if (story.get('labels')) { %>
<% _.each(story.labels(), function(value) { %>
diff --git a/app/assets/javascripts/views/story_view.jsx b/app/assets/javascripts/views/story_view.jsx
index a467487fb..9b90d2348 100644
--- a/app/assets/javascripts/views/story_view.jsx
+++ b/app/assets/javascripts/views/story_view.jsx
@@ -22,6 +22,7 @@ import storyTemplate from 'templates/story.ejs';
import alertTemplate from 'templates/alert.ejs';
import storyHoverTemplate from 'templates/story_hover.ejs';
import noteTemplate from 'templates/note.ejs';
+import StoryCopyIdClipboard from '../components/story/StoryCopyIdClipboard';
const LOCAL_STORY_REGEXP = /(?!\s|\b)(#\d+)(?!\w)/g;
@@ -541,34 +542,28 @@ const StoryView = FormView.extend({
},
renderCollapsed: function(isGuest) {
-
this.$el.removeClass('editing');
this.$el.html(this.template({story: this.model, view: this}));
- this.$el.toggleClass('collapsed-iteration',
- !this.model.get('isVisible') &&
- !this.isSearchResult);
+ this.$el.toggleClass('collapsed-iteration', !this.model.get('isVisible') && !this.isSearchResult);
const stateButtons = this.$('[data-story-state-buttons]').get(0)
if(stateButtons) {
- ReactDOM.render(
- ,
- stateButtons
- );
+ ReactDOM.render(, stateButtons);
}
const estimateButtons = this.$('[data-story-estimate-buttons]').get(0)
if(estimateButtons) {
ReactDOM.render(
- ,
+ ,
estimateButtons
);
}
+ const copyStoryIdClipboardLink = this.$('[data-story-id-copy-clipboard]').get(0)
+ if(copyStoryIdClipboardLink) {
+ ReactDOM.render(, copyStoryIdClipboardLink)
+ }
+
if (isGuest) { this.$el.find('.state-actions').find('.transition').prop('disabled', true) }
},
diff --git a/app/assets/stylesheets/_screen.scss b/app/assets/stylesheets/_screen.scss
index 9474a044b..b678168f6 100644
--- a/app/assets/stylesheets/_screen.scss
+++ b/app/assets/stylesheets/_screen.scss
@@ -224,10 +224,14 @@ div.story-controls {
}
div.story-title {
- margin-left: 65px;
+ margin-left: 50px;
word-wrap: break-word;
}
+div.story-title div[data-story-id-copy-clipboard] {
+ display: inline;
+}
+
.unestimated div.story-title {
font-style: italic;
}
@@ -239,6 +243,19 @@ div.story-title abbr.initials {
border: none;
}
+div.story-title {
+ .story-id {
+ cursor: pointer;
+ color: $blue-4;
+ font-weight: bold;
+ border: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}
+
.input-group-btn .btn-clipboard-id {
padding-top: 6px;
}
diff --git a/spec/javascripts/components/story/story_copy_id_clipboard_spec.js b/spec/javascripts/components/story/story_copy_id_clipboard_spec.js
new file mode 100644
index 000000000..27bde9a9e
--- /dev/null
+++ b/spec/javascripts/components/story/story_copy_id_clipboard_spec.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import { mount, shallow } from 'enzyme';
+
+import StoryCopyIdClipboard from 'components/story/StoryCopyIdClipboard';
+
+describe('', function() {
+ beforeEach(function() {
+ sinon.stub(I18n, 't');
+ });
+
+ afterEach(function() {
+ I18n.t.restore();
+ });
+
+ it("should render story id text", function() {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('.story-id').at(0).text()).toBe('#70');
+ });
+
+ it("should render story id data-clipboard-text", function() {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-clipboard-text]')).toExist();
+ });
+
+ it("should render copy id title", function() {
+ shallow(
+
+ );
+ expect(I18n.t).toHaveBeenCalledWith('story.events.copy_id');
+ });
+
+});