Full create for single and windowed annotations
parent
03d7f7457d
commit
7a77a0e653
|
@ -32,7 +32,7 @@ type annotationResponse struct {
|
|||
|
||||
func newAnnotationResponse(src chronograf.Source, a *chronograf.Annotation) annotationResponse {
|
||||
base := "/chronograf/v1/sources"
|
||||
return annotationResponse{
|
||||
res := annotationResponse{
|
||||
ID: a.ID,
|
||||
StartTime: a.StartTime.UTC().Format(timeMilliFormat),
|
||||
EndTime: a.EndTime.UTC().Format(timeMilliFormat),
|
||||
|
@ -42,6 +42,12 @@ func newAnnotationResponse(src chronograf.Source, a *chronograf.Annotation) anno
|
|||
Self: fmt.Sprintf("%s/%d/annotations/%s", base, src.ID, a.ID),
|
||||
},
|
||||
}
|
||||
|
||||
if a.EndTime.IsZero() {
|
||||
res.EndTime = ""
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type annotationsResponse struct {
|
||||
|
@ -204,9 +210,11 @@ func (ar *newAnnotationRequest) UnmarshalJSON(data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
ar.EndTime, err = time.Parse(timeMilliFormat, aux.EndTime)
|
||||
if err != nil {
|
||||
return err
|
||||
if aux.EndTime != "" {
|
||||
ar.EndTime, err = time.Parse(timeMilliFormat, aux.EndTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import * as api from 'shared/apis/annotation'
|
||||
|
||||
export const editingAnnotation = () => ({
|
||||
type: 'EDITING_ANNOTATION',
|
||||
})
|
||||
|
@ -53,3 +55,10 @@ export const addAnnotation = annotation => ({
|
|||
annotation,
|
||||
},
|
||||
})
|
||||
|
||||
export const addAnnotationAsync = (createUrl, annotation) => async dispatch => {
|
||||
dispatch(addAnnotation(annotation))
|
||||
const savedAnnotation = await api.createAnnotation(createUrl, annotation)
|
||||
dispatch(addAnnotation(savedAnnotation))
|
||||
dispatch(deleteAnnotation(annotation))
|
||||
}
|
||||
|
|
|
@ -18,14 +18,13 @@ export const getAnnotations = (graph, annotations = []) => {
|
|||
const [xStart, xEnd] = graph.xAxisRange()
|
||||
return annotations.reduce((acc, a) => {
|
||||
// Don't render if annotation.time is outside the graph
|
||||
const time = +a.time
|
||||
const duration = +a.duration
|
||||
const endTime = time + duration
|
||||
const time = +a.startTime
|
||||
const endTime = +a.endTime
|
||||
const endAnnotation = {
|
||||
...a,
|
||||
id: `${a.id}-end`,
|
||||
time: `${endTime}`,
|
||||
duration: '',
|
||||
startTime: `${endTime}`,
|
||||
endTime: '',
|
||||
}
|
||||
|
||||
if (time < xStart) {
|
||||
|
@ -41,7 +40,7 @@ export const getAnnotations = (graph, annotations = []) => {
|
|||
}
|
||||
|
||||
// If annotation does not have duration, include in array
|
||||
if (!duration) {
|
||||
if (!endTime) {
|
||||
return [...acc, a]
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import AJAX from 'src/utils/ajax'
|
||||
|
||||
const msToRFC = ms => ms && new Date(parseInt(ms, 10)).toISOString()
|
||||
const rfcToMS = rfc3339 => rfc3339 && JSON.stringify(Date.parse(rfc3339))
|
||||
const annoToMillisecond = anno => ({
|
||||
...anno,
|
||||
startTime: rfcToMS(anno.startTime),
|
||||
endTime: rfcToMS(anno.endTime),
|
||||
})
|
||||
const annoToRFC = anno => ({
|
||||
...anno,
|
||||
startTime: msToRFC(anno.startTime),
|
||||
endTime: msToRFC(anno.endTime),
|
||||
})
|
||||
|
||||
export const createAnnotation = async (url, newAnno) => {
|
||||
const data = annoToRFC(newAnno)
|
||||
const response = await AJAX({method: 'POST', url, data})
|
||||
return annoToMillisecond(response.data)
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
import React, {Component, PropTypes} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import uuid from 'node-uuid'
|
||||
|
||||
import OnClickOutside from 'shared/components/OnClickOutside'
|
||||
import * as schema from 'shared/schemas'
|
||||
import * as actions from 'shared/actions/annotations'
|
||||
|
||||
import {
|
||||
circleFlagStyle,
|
||||
|
@ -30,23 +33,27 @@ class NewAnnotation extends Component {
|
|||
|
||||
handleMouseUp = () => {
|
||||
const {
|
||||
onAddAnnotation,
|
||||
addAnnotation,
|
||||
onAddingAnnotationSuccess,
|
||||
tempAnnotation,
|
||||
onMouseLeaveTempAnnotation,
|
||||
dygraph,
|
||||
} = this.props
|
||||
const createUrl = this.context.source.links.annotations
|
||||
|
||||
// time on mouse down
|
||||
const startTime = dygraph.toDataXCoord(this.state.trueGraphX)
|
||||
const startTime = `${dygraph.toDataXCoord(this.state.trueGraphX)}`
|
||||
|
||||
if (this.state.mouseAction === 'dragging') {
|
||||
// time on mouse up
|
||||
const endTime = Number(tempAnnotation.startTime)
|
||||
const endTime = tempAnnotation.startTime
|
||||
|
||||
onAddAnnotation({
|
||||
addAnnotation(createUrl, {
|
||||
...tempAnnotation,
|
||||
startTime: `${startTime}`,
|
||||
endTime: `${endTime}`,
|
||||
startTime,
|
||||
endTime,
|
||||
text: 'hi',
|
||||
type: 'hi',
|
||||
})
|
||||
onAddingAnnotationSuccess()
|
||||
|
||||
|
@ -57,14 +64,18 @@ class NewAnnotation extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
onAddingAnnotationSuccess()
|
||||
onMouseLeaveTempAnnotation()
|
||||
onAddAnnotation({
|
||||
|
||||
addAnnotation(createUrl, {
|
||||
...tempAnnotation,
|
||||
id: uuid.v4(),
|
||||
startTime: `${startTime}`,
|
||||
startTime,
|
||||
endTime: '',
|
||||
text: 'hi',
|
||||
type: 'hi',
|
||||
})
|
||||
onAddingAnnotationSuccess()
|
||||
|
||||
return this.setState({
|
||||
isMouseOver: false,
|
||||
mouseAction: null,
|
||||
|
@ -171,13 +182,21 @@ class NewAnnotation extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const {bool, func, shape} = PropTypes
|
||||
const {bool, func, shape, string} = PropTypes
|
||||
|
||||
NewAnnotation.contextTypes = {
|
||||
source: shape({
|
||||
links: shape({
|
||||
annotations: string,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
NewAnnotation.propTypes = {
|
||||
dygraph: shape({}).isRequired,
|
||||
isTempHovering: bool,
|
||||
tempAnnotation: schema.annotation.isRequired,
|
||||
onAddAnnotation: func.isRequired,
|
||||
addAnnotation: func.isRequired,
|
||||
onDismissAddingAnnotation: func.isRequired,
|
||||
onAddingAnnotationSuccess: func.isRequired,
|
||||
onUpdateAnnotation: func.isRequired,
|
||||
|
@ -185,4 +204,8 @@ NewAnnotation.propTypes = {
|
|||
onMouseLeaveTempAnnotation: func.isRequired,
|
||||
}
|
||||
|
||||
export default OnClickOutside(NewAnnotation)
|
||||
const mdtp = dispatch => ({
|
||||
addAnnotation: bindActionCreators(actions.addAnnotationAsync, dispatch),
|
||||
})
|
||||
|
||||
export default connect(null, mdtp)(OnClickOutside(NewAnnotation))
|
||||
|
|
|
@ -6,7 +6,6 @@ export const annotation = shape({
|
|||
id: string.isRequired,
|
||||
startTime: string.isRequired,
|
||||
endTime: string.isRequired,
|
||||
name: string.isRequired,
|
||||
text: string.isRequired,
|
||||
type: string.isRequired,
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue