Merge pull request #1735 from influxdata/bugfix/cell-name

Bugfix Cell name edit cancel
pull/1751/head^2
Andrew Watkins 2017-07-21 13:41:36 -07:00 committed by GitHub
commit 8faab66415
10 changed files with 112 additions and 55 deletions

View File

@ -2,14 +2,15 @@
### Bug Fixes
1. [#1708](https://github.com/influxdata/chronograf/pull/1708): Fix z-index issue in dashboard cell context menu
1. [#1752](https://github.com/influxdata/chronograf/pull/1752): Clarify BoltPath server flag help text by making example the default path
1. [#1703](https://github.com/influxdata/chronograf/pull/1703): Fix cell name cancel not reverting to original name
### Features
1. [#1717](https://github.com/influxdata/chronograf/pull/1717): View server generated TICKscripts
1. [#1681](https://github.com/influxdata/chronograf/pull/1681): Add the ability to select Custom Time Ranges in the Hostpages, Data Explorer, and Dashboards.
1. [#1681](https://github.com/influxdata/chronograf/pull/1681): Add the ability to select Custom Time Ranges in the Hostpages, Data Explorer, and Dashboards
1. [#1752](https://github.com/influxdata/chronograf/pull/1752): Clarify BoltPath server flag help text by making example the default path
1. [#1738](https://github.com/influxdata/chronograf/pull/1738): Add shared secret JWT authorization to InfluxDB
### UI Improvements
1. [#1707](https://github.com/influxdata/chronograf/pull/1707): Polish alerts table in status page to wrap text less

View File

@ -11,6 +11,7 @@ import {
renameDashboardCell,
syncDashboardCell,
templateVariableSelected,
cancelEditCell,
} from 'src/dashboards/actions'
let state
@ -62,6 +63,13 @@ const c1 = {
isEditing: false,
name: 'Gigawatts',
}
const editingCell = {
i: 1,
isEditing: true,
name: 'Edit me',
}
const cells = [c1]
const tempVar = {
...d1.templates[0],
@ -180,4 +188,17 @@ describe('DataExplorer.Reducers.UI', () => {
expect(actual.dashboards[0].templates[0].values[1].selected).to.equal(false)
expect(actual.dashboards[0].templates[0].values[2].selected).to.equal(true)
})
it('can cancel cell editing', () => {
const dash = _.cloneDeep(d1)
dash.cells = [editingCell]
const actual = reducer(
{dashboards: [dash]},
cancelEditCell(dash.id, editingCell.i)
)
expect(actual.dashboards[0].cells[0].isEditing).to.equal(false)
expect(actual.dashboards[0].cells[0].name).to.equal(editingCell.name)
})
})

View File

@ -91,6 +91,14 @@ export const editDashboardCell = (dashboard, x, y, isEditing) => ({
},
})
export const cancelEditCell = (dashboardID, cellID) => ({
type: 'CANCEL_EDIT_CELL',
payload: {
dashboardID,
cellID,
},
})
export const renameDashboardCell = (dashboard, x, y, name) => ({
type: 'RENAME_DASHBOARD_CELL',
payload: {

View File

@ -23,6 +23,7 @@ const Dashboard = ({
onSummonOverlayTechnologies,
onSelectTemplate,
showTemplateControlBar,
onCancelEditCell,
}) => {
const cells = dashboard.cells.map(cell => {
const dashboardCell = {...cell}
@ -56,6 +57,7 @@ const Dashboard = ({
/>}
{cells.length
? <LayoutRenderer
onCancelEditCell={onCancelEditCell}
templates={templatesIncludingDashTime}
isEditable={true}
cells={cells}
@ -124,6 +126,7 @@ Dashboard.propTypes = {
onOpenTemplateManager: func.isRequired,
onSelectTemplate: func.isRequired,
showTemplateControlBar: bool,
onCancelEditCell: func,
}
export default Dashboard

View File

@ -10,7 +10,8 @@ import CellEditorOverlay from 'src/dashboards/components/CellEditorOverlay'
import DashboardHeader from 'src/dashboards/components/DashboardHeader'
import DashboardHeaderEdit from 'src/dashboards/components/DashboardHeaderEdit'
import Dashboard from 'src/dashboards/components/Dashboard'
import TemplateVariableManager from 'src/dashboards/components/TemplateVariableManager'
import TemplateVariableManager
from 'src/dashboards/components/TemplateVariableManager'
import {errorThrown as errorThrownAction} from 'shared/actions/errors'
@ -44,7 +45,6 @@ class DashboardPage extends Component {
this.handleCancelEditDashboard = ::this.handleCancelEditDashboard
this.handleDeleteDashboardCell = ::this.handleDeleteDashboardCell
this.handleOpenTemplateManager = ::this.handleOpenTemplateManager
this.handleRenameDashboardCell = ::this.handleRenameDashboardCell
this.handleUpdateDashboardCell = ::this.handleUpdateDashboardCell
this.handleCloseTemplateManager = ::this.handleCloseTemplateManager
this.handleSummonOverlayTechnologies = ::this
@ -82,8 +82,7 @@ class DashboardPage extends Component {
handleCloseTemplateManager(isEdited) {
if (
!isEdited ||
(isEdited && confirm('Do you want to close without saving?')) // eslint-disable-line no-alert
!isEdited || (isEdited && confirm('Do you want to close without saving?')) // eslint-disable-line no-alert
) {
this.setState({isTemplating: false})
}
@ -144,26 +143,12 @@ class DashboardPage extends Component {
}
}
handleRenameDashboardCell(x, y) {
return evt => {
this.props.dashboardActions.renameDashboardCell(
this.getActiveDashboard(),
x,
y,
evt.target.value
)
}
}
handleUpdateDashboardCell(newCell) {
return () => {
this.props.dashboardActions.editDashboardCell(
this.props.dashboardActions.updateDashboardCell(
this.getActiveDashboard(),
newCell.x,
newCell.y,
false
newCell
)
this.props.dashboardActions.putDashboard(this.getActiveDashboard())
}
}
@ -238,6 +223,13 @@ class DashboardPage extends Component {
this.props.templateControlBarVisibilityToggled()
}
handleCancelEditCell(cellID) {
this.props.dashboardActions.cancelEditCell(
this.getActiveDashboard().id,
cellID
)
}
getActiveDashboard() {
const {params: {dashboardID}, dashboards} = this.props
return dashboards.find(d => d.id === +dashboardID)
@ -363,13 +355,13 @@ class DashboardPage extends Component {
showTemplateControlBar={showTemplateControlBar}
>
{dashboards
? dashboards.map((d, i) =>
? dashboards.map((d, i) => (
<li className="dropdown-item" key={i}>
<Link to={`/sources/${sourceID}/dashboards/${d.id}`}>
{d.name}
</Link>
</li>
)
))
: null}
</DashboardHeader>}
{dashboard
@ -384,13 +376,13 @@ class DashboardPage extends Component {
onEditCell={this.handleEditDashboardCell}
onPositionChange={this.handleUpdatePosition}
onDeleteCell={this.handleDeleteDashboardCell}
onRenameCell={this.handleRenameDashboardCell}
onUpdateCell={this.handleUpdateDashboardCell}
onOpenTemplateManager={this.handleOpenTemplateManager}
templatesIncludingDashTime={templatesIncludingDashTime}
onSummonOverlayTechnologies={this.handleSummonOverlayTechnologies}
onSelectTemplate={this.handleSelectTemplate}
showTemplateControlBar={showTemplateControlBar}
onCancelEditCell={::this.handleCancelEditCell}
/>
: null}
</div>
@ -420,7 +412,7 @@ DashboardPage.propTypes = {
setTimeRange: func.isRequired,
addDashboardCellAsync: func.isRequired,
editDashboardCell: func.isRequired,
renameDashboardCell: func.isRequired,
cancelEditCell: func.isRequired,
}).isRequired,
dashboards: arrayOf(
shape({

View File

@ -132,6 +132,24 @@ export default function ui(state = initialState, action) {
return {...state, ...newState}
}
case 'CANCEL_EDIT_CELL': {
const {dashboardID, cellID} = action.payload
const dashboards = state.dashboards.map(
d =>
(d.id === dashboardID
? {
...d,
cells: d.cells.map(
c => (c.i === cellID ? {...c, isEditing: false} : c)
),
}
: d)
)
return {...state, dashboards}
}
case 'SYNC_DASHBOARD_CELL': {
const {cell, dashboard} = action.payload

View File

@ -44,9 +44,7 @@ class CustomTimeRangeDropdown extends Component {
onClick={this.handleToggleDropdown}
>
<span className="icon clock" />
<span className="dropdown-selected">{`${moment(lower).format(
'MMM Do HH:mm'
)} ${moment(upper).format('MMM Do HH:mm')}`}</span>
<span className="dropdown-selected">{`${moment(lower).format('MMM Do HH:mm')}${moment(upper).format('MMM Do HH:mm')}`}</span>
<span className="caret" />
</button>
<CustomTimeRange
@ -65,7 +63,7 @@ CustomTimeRangeDropdown.propTypes = {
onApplyTimeRange: func.isRequired,
timeRange: shape({
lower: string.isRequired,
upper: string.isRequired,
upper: string,
}).isRequired,
}

View File

@ -138,11 +138,11 @@ class LayoutRenderer extends Component {
source,
cells,
onEditCell,
onCancelEditCell,
onRenameCell,
onUpdateCell,
onDeleteCell,
onSummonOverlayTechnologies,
shouldNotBeEditable,
timeRange,
autoRefresh,
templates,
@ -156,13 +156,13 @@ class LayoutRenderer extends Component {
return (
<div key={cell.i}>
<NameableGraph
onCancelEditCell={onCancelEditCell}
isEditable={isEditable}
onEditCell={onEditCell}
onRenameCell={onRenameCell}
onUpdateCell={onUpdateCell}
onDeleteCell={onDeleteCell}
onSummonOverlayTechnologies={onSummonOverlayTechnologies}
shouldNotBeEditable={shouldNotBeEditable}
cell={cell}
>
{cell.isWidget
@ -215,7 +215,7 @@ class LayoutRenderer extends Component {
PAGE_HEADER_HEIGHT -
PAGE_CONTAINER_MARGIN -
PAGE_CONTAINER_MARGIN) /
STATUS_PAGE_ROW_COUNT
STATUS_PAGE_ROW_COUNT
: DASHBOARD_LAYOUT_ROW_HEIGHT
}
@ -298,10 +298,10 @@ LayoutRenderer.propTypes = {
onUpdateCell: func,
onDeleteCell: func,
onSummonOverlayTechnologies: func,
shouldNotBeEditable: bool,
synchronizer: func,
isStatusPage: bool,
isEditable: bool,
onCancelEditCell: func,
}
export default LayoutRenderer

View File

@ -8,10 +8,8 @@ class NameableGraph extends Component {
super(props)
this.state = {
isMenuOpen: false,
cellName: props.cell.name,
}
this.toggleMenu = ::this.toggleMenu
this.closeMenu = ::this.closeMenu
}
toggleMenu() {
@ -20,6 +18,17 @@ class NameableGraph extends Component {
})
}
handleRenameCell(e) {
const cellName = e.target.value
this.setState({cellName})
}
handleCancelEdit(cellID) {
const {cell, onCancelEditCell} = this.props
this.setState({cellName: cell.name})
onCancelEditCell(cellID)
}
closeMenu() {
this.setState({
isMenuOpen: false,
@ -30,7 +39,6 @@ class NameableGraph extends Component {
const {
cell,
onEditCell,
onRenameCell,
onUpdateCell,
onDeleteCell,
onSummonOverlayTechnologies,
@ -38,23 +46,26 @@ class NameableGraph extends Component {
children,
} = this.props
const {cellName, isMenuOpen} = this.state
return (
<div className="dash-graph">
<NameableGraphHeader
cell={cell}
cellName={cellName}
isEditable={isEditable}
onEditCell={onEditCell}
onRenameCell={onRenameCell}
onUpdateCell={onUpdateCell}
onRenameCell={::this.handleRenameCell}
onCancelEditCell={::this.handleCancelEdit}
/>
<ContextMenu
cell={cell}
onDelete={onDeleteCell}
onRename={!cell.isEditing && isEditable ? onEditCell : () => {}}
toggleMenu={this.toggleMenu}
isOpen={this.state.isMenuOpen}
toggleMenu={::this.toggleMenu}
isOpen={isMenuOpen}
isEditable={isEditable}
handleClickOutside={this.closeMenu}
handleClickOutside={::this.closeMenu}
onEdit={onSummonOverlayTechnologies}
/>
<div className="dash-graph--container">
@ -81,8 +92,8 @@ NameableGraph.propTypes = {
onUpdateCell: func,
onDeleteCell: func,
onSummonOverlayTechnologies: func,
shouldNotBeEditable: bool,
isEditable: bool,
onCancelEditCell: func,
}
export default NameableGraph

View File

@ -4,12 +4,13 @@ import classnames from 'classnames'
import CustomTimeIndicator from 'shared/components/CustomTimeIndicator'
const NameableGraphHeader = ({
onCancelEditCell,
isEditable,
onEditCell,
onRenameCell,
onUpdateCell,
cell,
cell: {x, y, name, queries},
cellName,
cell: {i, name, queries},
}) => {
const isInputVisible = isEditable && cell.isEditing
const className = classnames('dash-graph--heading', {
@ -17,10 +18,11 @@ const NameableGraphHeader = ({
})
const onKeyUp = evt => {
if (evt.key === 'Enter') {
onUpdateCell(cell)()
onUpdateCell({...cell, name: cellName})()
}
if (evt.key === 'Escape') {
onEditCell(x, y, true)()
onCancelEditCell(i)
}
}
@ -28,9 +30,9 @@ const NameableGraphHeader = ({
<div className={className}>
{isInputVisible
? <GraphNameInput
value={name}
onChange={onRenameCell(x, y)}
onBlur={onUpdateCell(cell)}
value={cellName}
onChange={onRenameCell}
onBlur={onUpdateCell({...cell, name: cellName})}
onKeyUp={onKeyUp}
/>
: <GraphName name={name} queries={queries} />}
@ -42,26 +44,28 @@ const {arrayOf, bool, func, string, shape} = PropTypes
NameableGraphHeader.propTypes = {
cell: shape(),
onEditCell: func,
cellName: string,
onRenameCell: func,
onUpdateCell: func,
isEditable: bool,
onCancelEditCell: func,
}
const GraphName = ({name, queries}) =>
const GraphName = ({name, queries}) => (
<span className="dash-graph--name">
{name}
{queries && queries.length
? <CustomTimeIndicator queries={queries} />
: null}
</span>
)
GraphName.propTypes = {
name: string,
queries: arrayOf(shape()),
}
const GraphNameInput = ({value, onKeyUp, onChange, onBlur}) =>
const GraphNameInput = ({value, onKeyUp, onChange, onBlur}) => (
<input
className="form-control input-sm dash-graph--name-edit"
type="text"
@ -71,6 +75,7 @@ const GraphNameInput = ({value, onKeyUp, onChange, onBlur}) =>
onBlur={onBlur}
onKeyUp={onKeyUp}
/>
)
GraphNameInput.propTypes = {
value: string,