Skip to content

Commit

Permalink
Merge c7b2976 into e961065
Browse files Browse the repository at this point in the history
  • Loading branch information
kostadriano committed Jan 10, 2019
2 parents e961065 + c7b2976 commit d47a67b
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 35 deletions.
1 change: 0 additions & 1 deletion app/assets/javascripts/actions/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export const updateStory = (story, projectId) =>
return Story.update(story._editing, projectId)
.then((story) => {
dispatch(updateStorySuccess(story));
dispatch(toggleStory(story.id));
});
}
return dispatch(toggleStory(story.id));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'

const labelSplit = (labels) => labels.split(',');
import * as Labels from '../../../models/beta/label';

const StoryLabel = ( { label } ) => (
<a href="#" className="Story__label" title={label}>{label}</a>
Expand All @@ -18,7 +17,7 @@ const CollapsedStoryLabels = ({ story }) => {

return (
<span className='Story__labels'>
{labelSplit(story.labels).map(label => (
{Labels.getNames(story.labels).map(label => (
<StoryLabel key={label} label={label} />
))}
</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import ReactTags from 'react-tag-autocomplete';
import PropTypes from 'prop-types';

class ExpandedStoryLabels extends React.Component {
constructor(props) {
super(props);

this.state = {
tags: props.labels
}

this.handleAddition = this.handleAddition.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}

handleDelete(index) {
const { onEdit } = this.props;
const tags = this.state.tags.filter((tag, tagIndex) => tagIndex !== index);

this.setState(
{ tags }, () => {
onEdit(this.state.tags)
}
);
}

handleAddition(tag) {
const { onEdit } = this.props;

this.setState(
{ tags: [...this.state.tags, tag] }, () => {
onEdit(this.state.tags)
}
);
}

render() {
return (
<div className="Story__section">
<div className="Story__section-title">
{I18n.t('activerecord.attributes.story.labels')}
</div>
{
<ReactTags
tags={this.state.tags}
handleDelete={this.handleDelete}
handleAddition={this.handleAddition}
allowNew={true}
placeholder={I18n.t('add new label')}
allowBackspace={false}
addOnBlur={true}
delimiterChars={[' ']}
autoresize={false} />
}
</div>
);
}
};

ExpandedStoryLabels.propTypes = {
labels: PropTypes.arrayOf(PropTypes.object).isRequired,
onEdit: PropTypes.func.isRequired
};

export default ExpandedStoryLabels;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ExpandedStoryDescription from './ExpandedStoryDescription';
import ExpandedStoryNotes from './ExpandedStoryNotes';
import ExpandedStoryState from './ExpandedStoryState';
import ExpandedStoryTitle from './ExpandedStoryTitle';
import ExpandedStoryLabels from './ExpandedStoryLabels';
import { deleteNote, createNote } from '../../../actions/note';
import { editStory, updateStory, deleteStory } from '../../../actions/story';
import { connect } from 'react-redux';
Expand All @@ -18,6 +19,7 @@ export const ExpandedStory = ({
onToggle,
editStory,
updateStory,
deleteStory,
project,
deleteNote,
createNote
Expand Down Expand Up @@ -53,6 +55,11 @@ export const ExpandedStory = ({
onEdit={(newAttributes) => editStory(story.id, newAttributes)}
/>

<ExpandedStoryLabels
labels={story.labels}
onEdit={(value) => editStory(story.id, { labels: value })}
/>

<ExpandedStoryDescription
story={story}
onEdit={(newAttributes) => editStory(story.id, newAttributes)}
Expand Down
19 changes: 19 additions & 0 deletions app/assets/javascripts/models/beta/label.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const splitLabels = (labels) => {
if (labels) {
return labels.split(',')
.map((label, index) => (
{
id: index,
name: label
}
))
}

return [];
};

export const joinLabels = (labels) =>
labels.map(label => label.name).join(',');

export const getNames = (labels) =>
labels.map(label => label.name);
17 changes: 7 additions & 10 deletions app/assets/javascripts/models/beta/projectBoard.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import httpService from '../../services/httpService';
import changeCase from'change-object-case';
import changeCase from 'change-object-case';
import * as Story from './story';

export function get(projectId) {
return httpService
.get(`/beta/project_boards/${projectId}`)
.then(({ data }) => changeCase.camelKeys(data, {recursive: true, arrayRecursive: true}))
.then(( projectBoard ) => ({
...projectBoard,
stories: projectBoard.stories.map((story) => ({
...story,
estimate: story.estimate || '',
collapsed: true
}))
}));
.then(({ data }) => changeCase.camelKeys(data, { recursive: true, arrayRecursive: true }))
.then((projectBoard) => ({
...projectBoard,
stories: projectBoard.stories.map(Story.deserialize)
}));
};
20 changes: 15 additions & 5 deletions app/assets/javascripts/models/beta/story.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { status, storyTypes } from "libs/beta/constants";
import httpService from '../../services/httpService';
import changeCase from 'change-object-case';
import * as Label from './label';

const compareValues = (a, b) => {
if (a > b) return 1;
Expand Down Expand Up @@ -70,15 +71,12 @@ export const states = [
];

export const update = (story, projectId) => {
const newStory = changeCase.snakeKeys(story);
const newStory = changeCase.snakeKeys(serialize(story));

return httpService
.put(`/projects/${projectId}/stories/${story.id}`, newStory)
.then(({ data }) => changeCase.camelKeys(data, { recursive: true, arrayRecursive: true }))
.then(({ story }) => ({
...story,
estimate: story.estimate || ''
}));
.then(({ story }) => deserialize(story));
};

export const deleteStory = (storyId, projectId) => {
Expand Down Expand Up @@ -119,3 +117,15 @@ export const editStory = (story, newAttributes) => {
}
};
};

export const deserialize = (story) => ({
...story,
labels: Label.splitLabels(story.labels),
estimate: story.estimate || '',
collapsed: true
});

export const serialize = (story) => ({
...story,
labels: Label.joinLabels(story.labels)
})
2 changes: 2 additions & 0 deletions app/assets/stylesheets/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ $lightgrey-14: #e6e6e6;
$lightgrey-15: #dfe1e2;
$lightgrey-16: #aaaaaa;
$lightgrey-17: #d3d3d3;
$lightgrey-18: #b1b1b1;
$lightgrey-19: #d1d1d1;

$blue: #2075F3;
$blue-2: #1976D2;
Expand Down
111 changes: 111 additions & 0 deletions app/assets/stylesheets/new_board/_react_tags.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
.react-tags {
position: relative;
padding: 6px 0 0 6px;
border: 1px solid $lightgrey-9;
border-radius: 3px;
background-color: $white;

font-size: 10px;
line-height: 1.2;
}

.react-tags.is-focused {
border-color: $lightgrey-18;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

.react-tags__selected {
display: inline;
}

.react-tags__selected-tag {
display: inline-block;
box-sizing: border-box;
margin: 0 6px 6px 0;
padding: 6px 8px;
border: 1px solid $lightgrey-17;
border-radius: 2px;
background: $lightgrey-10;

font-size: inherit;
line-height: inherit;
}

.react-tags__selected-tag:after {
content: '\2715';
color: $lightgrey-16;
margin-left: 8px;
}

.react-tags__selected-tag:hover,
.react-tags__selected-tag:focus {
border-color: $lightgrey-18;
}

.react-tags__search {
display: inline-block;

padding: 7px 2px;
margin-bottom: 6px;

max-width: 100%;
}

.react-tags__search input {
max-width: 100%;
height: 100%;

margin: 0;
padding: 0;
border: 0;
outline: none;

font-size: inherit;
line-height: inherit;
}

.react-tags__search input::-ms-clear {
display: none;
}

.react-tags__suggestions {
position: absolute;
top: 100%;
left: 0;
width: 100%;
}

.react-tags__suggestions ul {
margin: 4px -1px;
padding: 0;
list-style: none;
background: $white;
border: 1px solid $lightgrey-19;
border-radius: 2px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}

.react-tags__suggestions li {
border-bottom: 1px solid $lightgrey-13;
padding: 6px 8px;
}

.react-tags__suggestions li mark {
text-decoration: underline;
background: none;
font-weight: 600;
}

.react-tags__suggestions li:hover {
cursor: pointer;
background: $lightgrey-8;
}

.react-tags__suggestions li.is-active {
background: $lightgrey-15;
}

.react-tags__suggestions li.is-disabled {
opacity: 0.5;
cursor: auto;
}
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ en:
add: "Add"
remove: "Remove"
add user: "Add User"
add new label: "Add a new label"
add new member: "Add a new member"
all users: "All Users"
search user: "Search user"
Expand Down
1 change: 1 addition & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ es:
description: "Descripción"
add user: "Agregar usuario"
add new member: "Agregar un nuevo miembro"
add new label: "Agregar una nueva etiqueta"
all users: "Todos los usuarios"
search user: "Búsqueda de usuario"
remove user confirm: "¿Está seguro que desea eliminar %{email} de este proyecto?"
Expand Down
1 change: 1 addition & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pt-BR:
remove: "Remover"
add user: "Adicionar usuário"
add new member: "Adicionar um novo membro"
add new label: "Adicionar uma nova etiqueta"
all users: "Todos os usuários"
search user: "Procurar usuário"
remove user confirm: "Tem certeza de que deseja remover %{email} deste projeto?"
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"react-datepicker": "^0.46.0",
"react-dom": "^15.4.2",
"react-redux": "^5.0.6",
"react-tag-autocomplete": "^5.8.0",
"redux": "^3.7.2",
"redux-devtools-extension": "^2.13.2",
"redux-thunk": "^2.2.0",
Expand All @@ -86,6 +87,7 @@
"babel-plugin-istanbul": "^3.1.2",
"coveralls": "^2.11.14",
"enzyme": "^2.7.1",
"es6-promise": "^4.2.5",
"eslint": "^3.19.0",
"eslint-config-react-app": "^1.0.4",
"eslint-plugin-backbone": "^2.0.2",
Expand All @@ -107,7 +109,6 @@
"karma-webpack": "^1.8.0",
"react-addons-test-utils": "^15.4.2",
"react-test-renderer": "^15.5.4",
"sinon": "^2.0.0",
"es6-promise": "^4.2.5"
"sinon": "^2.0.0"
}
}
3 changes: 1 addition & 2 deletions spec/javascripts/actions/story_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('updateStory', () => {
});
});

it('dispatch toggleStory and updateStorySuccess when _isDirty', (done) => {
it('dispatch updateStorySuccess when _isDirty', (done) => {
const editedStory = {
...story,
_editing: {
Expand All @@ -66,7 +66,6 @@ describe('updateStory', () => {
const fakeDispatch = sinon.stub().resolves({});

Story.updateStory(editedStory, projectId)(fakeDispatch, null, { Story: FakeStory }).then(() => {
expect(fakeDispatch).toHaveBeenCalledWith(Story.toggleStory(editedStory.id));
expect(fakeDispatch).toHaveBeenCalledWith(Story.updateStorySuccess(story));

done();
Expand Down

0 comments on commit d47a67b

Please sign in to comment.