Skip to content

Commit c03d868

Browse files
feat(Labels): add label assigner
1 parent cb3a1e7 commit c03d868

File tree

8 files changed

+115
-10
lines changed

8 files changed

+115
-10
lines changed

lib/common/components/FeedLabel.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,31 @@ export default class FeedLabel extends React.Component {
2828
}
2929

3030
render () {
31-
const {small, label} = this.props
31+
const {small, label, checked, onClick} = this.props
3232

3333
return (
3434
<div
35-
className={`feedLabel ${small ? 'small' : ''}`}
35+
className={`feedLabel ${small ? 'small' : ''} ${checked !== undefined ? 'clickable' : ''}`}
3636
style={{
3737
backgroundColor: label.color,
3838
color: getComplementaryColor(label.color, 55),
3939
borderColor: getComplementaryColor(label.color, 10)
4040
}}
4141
title={label.description}
42+
43+
onClick={() => onClick(label.id)}
44+
onKeyPress={() => onClick(label.id)}
45+
role='checkbox'
46+
aria-checked={checked}
47+
tabIndex={0}
4248
>
4349

4450
<div className='labelName'>
51+
{checked !== undefined
52+
? <div className='actionButtons'>
53+
<input type='checkbox' checked={checked} />
54+
</div>
55+
: ''}
4556
{label.adminOnly ? <Icon type='lock' /> : ''}
4657
<span>{label.name}</span>
4758
</div>

lib/manager/actions/feeds.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {isModuleEnabled} from '../../common/util/config'
88
import {fetchSnapshots} from '../../editor/actions/snapshots'
99
import type {Feed, NewFeed} from '../../types'
1010
import type {dispatchFn, getStateFn} from '../../types/reducers'
11+
import { stringifyLabels } from '../util'
1112

1213
import {fetchFeedSourceDeployments} from './deployments'
1314
import {fetchProject, fetchProjectWithFeeds} from './projects'
@@ -81,8 +82,9 @@ export function createFeedSource (newFeed: NewFeed) {
8182
export function updateFeedSource (feedSource: Feed, properties: {[string]: any}) {
8283
return function (dispatch: dispatchFn, getState: getStateFn) {
8384
dispatch(savingFeedSource())
84-
// Convert feed source labels to format wanted by datatools-server
85-
feedSource.labels = feedSource.labels.map(label => label.id)
85+
feedSource.labels = stringifyLabels(feedSource.labels)
86+
properties.labels = stringifyLabels(properties.labels)
87+
8688
return dispatch(secureFetch(`${FS_URL}/${feedSource.id}`, 'put', {...feedSource, ...properties}))
8789
// Re-fetch feed source with versions and snapshots.
8890
.then((res) => dispatch(fetchFeedSource(feedSource.id)))

lib/manager/components/GeneralSettings.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ import {
1717

1818
import * as feedsActions from '../actions/feeds'
1919
import {FREQUENCY_INTERVALS} from '../../common/constants'
20-
import FeedFetchFrequency from './FeedFetchFrequency'
21-
2220
import type {Feed, FetchFrequency, Project} from '../../types'
2321
import type {ManagerUserState} from '../../types/reducers'
22+
import LabelAssigner from '../containers/LabelAssigner'
23+
24+
import FeedFetchFrequency from './FeedFetchFrequency'
2425

2526
type Props = {
2627
confirmDeleteFeedSource: () => void,
@@ -108,7 +109,8 @@ export default class GeneralSettings extends Component<Props, State> {
108109
const {
109110
confirmDeleteFeedSource,
110111
disabled,
111-
feedSource
112+
feedSource,
113+
project
112114
} = this.props
113115
const {
114116
name,
@@ -199,6 +201,9 @@ export default class GeneralSettings extends Component<Props, State> {
199201
</ListGroupItem>
200202
</ListGroup>
201203
</Panel>
204+
<Panel header={<h3>Labels</h3>}>
205+
<LabelAssigner feedSource={feedSource} project={project} />
206+
</Panel>
202207
<Panel bsStyle='danger' header={<h3>Danger zone</h3>}>
203208
<ListGroup fill>
204209
<ListGroupItem>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// @flow
2+
3+
import React from 'react'
4+
5+
import FeedLabel from '../../common/containers/FeedLabel'
6+
import { stringifyLabels } from '../util'
7+
8+
// TODO: props
9+
export default class LabelAssigner extends React.Component {
10+
state = {};
11+
onLabelClick = (labelId) => {
12+
const {feedSource} = this.props
13+
const updatedLabels = stringifyLabels(feedSource.labels)
14+
15+
const labelIndex = updatedLabels.indexOf(labelId)
16+
17+
// Either remove the label from the list, or add it
18+
if (labelIndex < 0) {
19+
updatedLabels.push(labelId)
20+
} else {
21+
updatedLabels.splice(labelIndex, 1)
22+
}
23+
24+
this.props.updateFeedSource(feedSource, { labels: updatedLabels })
25+
}
26+
27+
render () {
28+
const { project, feedSource } = this.props
29+
const projectLabels = project.labels
30+
const fsLabelIds = feedSource.labels.map((label) => label.id)
31+
32+
return (
33+
<div className='feedLabelContainer large'>
34+
{projectLabels.map((label) => (
35+
<FeedLabel
36+
key={label.id}
37+
label={label}
38+
checked={fsLabelIds.find((id) => id === label.id) !== undefined}
39+
small
40+
onClick={this.onLabelClick}
41+
/>
42+
))}
43+
</div>
44+
)
45+
}
46+
}

lib/manager/components/LabelEditorModal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default class LabelEditorModal extends React.Component<LabelEditorModalPr
4343
return (
4444
<Modal show={this.state.showModal} onHide={this.close}>
4545
<Header>
46-
<Title>Editing {label.name ? 'Label' : 'New Label'}</Title>
46+
<Title>{label.name ? 'Edit Label' : 'Create New Label'}</Title>
4747
</Header>
4848

4949
<Body>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @flow
2+
3+
import { connect } from 'react-redux'
4+
5+
import { updateFeedSource } from '../actions/feeds'
6+
import LabelAssigner from '../components/LabelAssigner'
7+
8+
const mapStateToProps = (state, ownProps) => {
9+
return {
10+
}
11+
}
12+
13+
const mapDispatchToProps = {
14+
updateFeedSource
15+
}
16+
17+
export default connect(
18+
mapStateToProps,
19+
mapDispatchToProps
20+
)(LabelAssigner)

lib/manager/util/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import moment from 'moment'
44
import {get} from 'object-path'
55

6-
import {getVersionValidationSummaryByFilterStrategy} from './version'
7-
86
import type {
97
Bounds,
108
Feed,
@@ -20,6 +18,8 @@ import type {
2018
ProjectsState
2119
} from '../../types/reducers'
2220

21+
import {getVersionValidationSummaryByFilterStrategy} from './version'
22+
2323
/**
2424
* Sort function that compares a field that might be datetimes. If ascending is
2525
* set to false, the entities will be sorting in descending order. Empty entries
@@ -397,3 +397,10 @@ export function projectHasAtLeastOneFeedWithAPublishedVersion (project: ?Project
397397
export function validationState (val: ?boolean): ?string {
398398
return val ? undefined : 'error'
399399
}
400+
401+
export function stringifyLabels (labels: [any]) {
402+
// Convert feed source labels to id strings wanted by datatools-server,
403+
// but only if we have a label object
404+
if (!labels) return []
405+
return labels.map(label => label.id ? label.id : label)
406+
}

lib/style.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ td.feed-source-info {
152152
width: 100%;
153153
align-items: center;
154154
}
155+
.feedLabelContainer.large {
156+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
157+
grid-gap: 15px;
158+
}
155159
.feedSourceLabelRow {
156160
display: inline-flex;
157161
width: 100%;
@@ -169,6 +173,10 @@ td.feed-source-info {
169173
border: 1px solid;
170174

171175
padding: 5px 0 8px 0;
176+
height: 100%;
177+
}
178+
.feedLabel.clickable {
179+
cursor: pointer;
172180
}
173181
.feedLabel.small {
174182
/* removing bottom padding seems to be only way to account for the icon baseline fix */
@@ -189,6 +197,8 @@ td.feed-source-info {
189197
}
190198
.feedLabel.small .labelName {
191199
padding: 0;
200+
height: 100%;
201+
align-items: center;
192202
}
193203

194204
.feedLabel .labelName i {
@@ -201,6 +211,10 @@ td.feed-source-info {
201211
align-items: flex-end;
202212
flex-direction: column;
203213
}
214+
.feedLabel .actionButtons input[type="checkbox"] {
215+
margin: 0 5px 2px 0;
216+
padding: 0;
217+
}
204218
.feedLabel .actionButtons button {
205219
background: none;
206220
border: none;

0 commit comments

Comments
 (0)