Merge pull request #1735 from influxdata/bugfix/cell-name
Bugfix Cell name edit cancelpull/1751/head^2
commit
8faab66415
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue