commit
44339a5b25
|
@ -1,11 +1,12 @@
|
||||||
## v1.4.1.0 [unreleased]
|
## v1.4.1.0 [unreleased]
|
||||||
### Features
|
### Features
|
||||||
1. [#2409](https://github.com/influxdata/chronograf/pull/2409): Allow adding multiple event handlers to a rule
|
1. [#2409](https://github.com/influxdata/chronograf/pull/2409): Allow adding multiple event handlers to a rule
|
||||||
1. [#2709](https://github.com/influxdata/chronograf/pull/2709): Add "send test alert" button to test kapacitor alert configurations"
|
1. [#2709](https://github.com/influxdata/chronograf/pull/2709): Add "send test alert" button to test kapacitor alert configurations
|
||||||
1. [#2708](https://github.com/influxdata/chronograf/pull/2708): Link to specified kapacitor config panel from rule builder alert handlers
|
1. [#2708](https://github.com/influxdata/chronograf/pull/2708): Link to specified kapacitor config panel from rule builder alert handlers
|
||||||
1. [#2722](https://github.com/influxdata/chronograf/pull/2722): Add auto refresh widget to hosts list page
|
1. [#2722](https://github.com/influxdata/chronograf/pull/2722): Add auto refresh widget to hosts list page
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
1. [#2698](https://github.com/influxdata/chronograf/pull/2698): Improve clarity of terminology surrounding InfluxDB & Kapacitor connections
|
1. [#2698](https://github.com/influxdata/chronograf/pull/2698): Improve clarity of terminology surrounding InfluxDB & Kapacitor connections
|
||||||
|
1. [#2746](https://github.com/influxdata/chronograf/pull/2746): Separate saving TICKscript from exiting editor page
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
1. [#2684](https://github.com/influxdata/chronograf/pull/2684): Fix TICKscript Sensu alerts when no group by tags selected
|
1. [#2684](https://github.com/influxdata/chronograf/pull/2684): Fix TICKscript Sensu alerts when no group by tags selected
|
||||||
1. [#2735](https://github.com/influxdata/chronograf/pull/2735): Remove cli options from systemd service file
|
1. [#2735](https://github.com/influxdata/chronograf/pull/2735): Remove cli options from systemd service file
|
||||||
|
|
|
@ -195,16 +195,10 @@ export const updateRuleStatus = (rule, status) => dispatch => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createTask = (
|
export const createTask = (kapacitor, task) => async dispatch => {
|
||||||
kapacitor,
|
|
||||||
task,
|
|
||||||
router,
|
|
||||||
sourceID
|
|
||||||
) => async dispatch => {
|
|
||||||
try {
|
try {
|
||||||
const {data} = await createTaskAJAX(kapacitor, task)
|
const {data} = await createTaskAJAX(kapacitor, task)
|
||||||
router.push(`/sources/${sourceID}/alert-rules`)
|
dispatch(publishNotification('success', 'TICKscript successfully created'))
|
||||||
dispatch(publishNotification('success', 'You made a TICKscript!'))
|
|
||||||
return data
|
return data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
@ -220,20 +214,17 @@ export const updateTask = (
|
||||||
kapacitor,
|
kapacitor,
|
||||||
task,
|
task,
|
||||||
ruleID,
|
ruleID,
|
||||||
router,
|
|
||||||
sourceID
|
sourceID
|
||||||
) => async dispatch => {
|
) => async dispatch => {
|
||||||
try {
|
try {
|
||||||
const {data} = await updateTaskAJAX(kapacitor, task, ruleID, sourceID)
|
const {data} = await updateTaskAJAX(kapacitor, task, ruleID, sourceID)
|
||||||
router.push(`/sources/${sourceID}/alert-rules`)
|
dispatch(publishNotification('success', 'TICKscript saved'))
|
||||||
dispatch(publishNotification('success', 'TICKscript updated successully'))
|
|
||||||
return data
|
return data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
dispatch(errorThrown('Could not communicate with server'))
|
dispatch(errorThrown('Could not communicate with server'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return error.data
|
return error.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React, {PropTypes} from 'react'
|
import React, {PropTypes} from 'react'
|
||||||
|
|
||||||
const LogsToggle = ({areLogsVisible, onToggleLogsVisbility}) =>
|
const LogsToggle = ({areLogsVisible, onToggleLogsVisibility}) =>
|
||||||
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite logs-toggle">
|
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite logs-toggle">
|
||||||
<li
|
<li
|
||||||
className={areLogsVisible ? null : 'active'}
|
className={areLogsVisible ? null : 'active'}
|
||||||
onClick={onToggleLogsVisbility}
|
onClick={onToggleLogsVisibility}
|
||||||
>
|
>
|
||||||
Editor
|
Editor
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className={areLogsVisible ? 'active' : null}
|
className={areLogsVisible ? 'active' : null}
|
||||||
onClick={onToggleLogsVisbility}
|
onClick={onToggleLogsVisibility}
|
||||||
>
|
>
|
||||||
Editor + Logs
|
Editor + Logs
|
||||||
</li>
|
</li>
|
||||||
|
@ -20,7 +20,7 @@ const {bool, func} = PropTypes
|
||||||
|
|
||||||
LogsToggle.propTypes = {
|
LogsToggle.propTypes = {
|
||||||
areLogsVisible: bool,
|
areLogsVisible: bool,
|
||||||
onToggleLogsVisbility: func.isRequired,
|
onToggleLogsVisibility: func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LogsToggle
|
export default LogsToggle
|
||||||
|
|
|
@ -8,25 +8,29 @@ import LogsTable from 'src/kapacitor/components/LogsTable'
|
||||||
|
|
||||||
const Tickscript = ({
|
const Tickscript = ({
|
||||||
onSave,
|
onSave,
|
||||||
|
onExit,
|
||||||
task,
|
task,
|
||||||
logs,
|
logs,
|
||||||
validation,
|
consoleMessage,
|
||||||
onSelectDbrps,
|
onSelectDbrps,
|
||||||
onChangeScript,
|
onChangeScript,
|
||||||
onChangeType,
|
onChangeType,
|
||||||
onChangeID,
|
onChangeID,
|
||||||
|
unsavedChanges,
|
||||||
isNewTickscript,
|
isNewTickscript,
|
||||||
areLogsVisible,
|
areLogsVisible,
|
||||||
areLogsEnabled,
|
areLogsEnabled,
|
||||||
onToggleLogsVisbility,
|
onToggleLogsVisibility,
|
||||||
}) =>
|
}) =>
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<TickscriptHeader
|
<TickscriptHeader
|
||||||
task={task}
|
task={task}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
|
onExit={onExit}
|
||||||
|
unsavedChanges={unsavedChanges}
|
||||||
areLogsVisible={areLogsVisible}
|
areLogsVisible={areLogsVisible}
|
||||||
areLogsEnabled={areLogsEnabled}
|
areLogsEnabled={areLogsEnabled}
|
||||||
onToggleLogsVisbility={onToggleLogsVisbility}
|
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||||
isNewTickscript={isNewTickscript}
|
isNewTickscript={isNewTickscript}
|
||||||
/>
|
/>
|
||||||
<div className="page-contents--split">
|
<div className="page-contents--split">
|
||||||
|
@ -38,11 +42,14 @@ const Tickscript = ({
|
||||||
onChangeID={onChangeID}
|
onChangeID={onChangeID}
|
||||||
task={task}
|
task={task}
|
||||||
/>
|
/>
|
||||||
<TickscriptEditorConsole validation={validation} />
|
|
||||||
<TickscriptEditor
|
<TickscriptEditor
|
||||||
script={task.tickscript}
|
script={task.tickscript}
|
||||||
onChangeScript={onChangeScript}
|
onChangeScript={onChangeScript}
|
||||||
/>
|
/>
|
||||||
|
<TickscriptEditorConsole
|
||||||
|
consoleMessage={consoleMessage}
|
||||||
|
unsavedChanges={unsavedChanges}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{areLogsVisible ? <LogsTable logs={logs} /> : null}
|
{areLogsVisible ? <LogsTable logs={logs} /> : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,12 +60,13 @@ const {arrayOf, bool, func, shape, string} = PropTypes
|
||||||
Tickscript.propTypes = {
|
Tickscript.propTypes = {
|
||||||
logs: arrayOf(shape()).isRequired,
|
logs: arrayOf(shape()).isRequired,
|
||||||
onSave: func.isRequired,
|
onSave: func.isRequired,
|
||||||
|
onExit: func.isRequired,
|
||||||
source: shape({
|
source: shape({
|
||||||
id: string,
|
id: string,
|
||||||
}),
|
}),
|
||||||
areLogsVisible: bool,
|
areLogsVisible: bool,
|
||||||
areLogsEnabled: bool,
|
areLogsEnabled: bool,
|
||||||
onToggleLogsVisbility: func.isRequired,
|
onToggleLogsVisibility: func.isRequired,
|
||||||
task: shape({
|
task: shape({
|
||||||
id: string,
|
id: string,
|
||||||
script: string,
|
script: string,
|
||||||
|
@ -66,10 +74,11 @@ Tickscript.propTypes = {
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
onChangeScript: func.isRequired,
|
onChangeScript: func.isRequired,
|
||||||
onSelectDbrps: func.isRequired,
|
onSelectDbrps: func.isRequired,
|
||||||
validation: string,
|
consoleMessage: string,
|
||||||
onChangeType: func.isRequired,
|
onChangeType: func.isRequired,
|
||||||
onChangeID: func.isRequired,
|
onChangeID: func.isRequired,
|
||||||
isNewTickscript: bool.isRequired,
|
isNewTickscript: bool.isRequired,
|
||||||
|
unsavedChanges: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Tickscript
|
export default Tickscript
|
||||||
|
|
|
@ -1,22 +1,31 @@
|
||||||
import React, {PropTypes} from 'react'
|
import React, {PropTypes} from 'react'
|
||||||
|
|
||||||
const TickscriptEditorConsole = ({validation}) =>
|
const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
||||||
<div className="tickscript-console">
|
let consoleOutput = 'TICKscript is valid'
|
||||||
<div className="tickscript-console--output">
|
let consoleClass = 'tickscript-console--valid'
|
||||||
{validation
|
|
||||||
? <p>
|
|
||||||
{validation}
|
|
||||||
</p>
|
|
||||||
: <p className="tickscript-console--default">
|
|
||||||
Save your TICKscript to validate it
|
|
||||||
</p>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
const {string} = PropTypes
|
if (consoleMessage) {
|
||||||
|
consoleOutput = consoleMessage
|
||||||
|
consoleClass = 'tickscript-console--error'
|
||||||
|
} else if (unsavedChanges) {
|
||||||
|
consoleOutput = 'You have unsaved changes, save to validate TICKscript'
|
||||||
|
consoleClass = 'tickscript-console--default'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tickscript-console">
|
||||||
|
<p className={consoleClass}>
|
||||||
|
{consoleOutput}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {bool, string} = PropTypes
|
||||||
|
|
||||||
TickscriptEditorConsole.propTypes = {
|
TickscriptEditorConsole.propTypes = {
|
||||||
validation: string,
|
consoleMessage: string,
|
||||||
|
unsavedChanges: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TickscriptEditorConsole
|
export default TickscriptEditorConsole
|
||||||
|
|
|
@ -2,14 +2,17 @@ import React, {PropTypes} from 'react'
|
||||||
|
|
||||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||||
import LogsToggle from 'src/kapacitor/components/LogsToggle'
|
import LogsToggle from 'src/kapacitor/components/LogsToggle'
|
||||||
|
import ConfirmButton from 'src/shared/components/ConfirmButton'
|
||||||
|
|
||||||
const TickscriptHeader = ({
|
const TickscriptHeader = ({
|
||||||
task: {id},
|
task: {id},
|
||||||
onSave,
|
onSave,
|
||||||
|
onExit,
|
||||||
|
unsavedChanges,
|
||||||
areLogsVisible,
|
areLogsVisible,
|
||||||
areLogsEnabled,
|
areLogsEnabled,
|
||||||
isNewTickscript,
|
isNewTickscript,
|
||||||
onToggleLogsVisbility,
|
onToggleLogsVisibility,
|
||||||
}) =>
|
}) =>
|
||||||
<div className="page-header full-width">
|
<div className="page-header full-width">
|
||||||
<div className="page-header__container">
|
<div className="page-header__container">
|
||||||
|
@ -20,18 +23,40 @@ const TickscriptHeader = ({
|
||||||
<LogsToggle
|
<LogsToggle
|
||||||
areLogsVisible={areLogsVisible}
|
areLogsVisible={areLogsVisible}
|
||||||
areLogsEnabled={areLogsEnabled}
|
areLogsEnabled={areLogsEnabled}
|
||||||
onToggleLogsVisbility={onToggleLogsVisbility}
|
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||||
/>}
|
/>}
|
||||||
<div className="page-header__right">
|
<div className="page-header__right">
|
||||||
<SourceIndicator />
|
<SourceIndicator />
|
||||||
<button
|
{isNewTickscript
|
||||||
className="btn btn-success btn-sm"
|
? <button
|
||||||
title={id ? '' : 'ID your TICKscript to save'}
|
className="btn btn-success btn-sm"
|
||||||
onClick={onSave}
|
title="Name your TICKscript to save"
|
||||||
disabled={!id}
|
onClick={onSave}
|
||||||
>
|
disabled={!id}
|
||||||
{isNewTickscript ? 'Save New TICKscript' : 'Save TICKscript'}
|
>
|
||||||
</button>
|
Save New TICKscript
|
||||||
|
</button>
|
||||||
|
: <button
|
||||||
|
className="btn btn-success btn-sm"
|
||||||
|
title="You have unsaved changes"
|
||||||
|
onClick={onSave}
|
||||||
|
disabled={!unsavedChanges}
|
||||||
|
>
|
||||||
|
Save Changes
|
||||||
|
</button>}
|
||||||
|
{unsavedChanges
|
||||||
|
? <ConfirmButton
|
||||||
|
text="Exit"
|
||||||
|
confirmText="Discard unsaved changes?"
|
||||||
|
confirmAction={onExit}
|
||||||
|
/>
|
||||||
|
: <button
|
||||||
|
className="btn btn-default btn-sm"
|
||||||
|
title="Return to Alert Rules"
|
||||||
|
onClick={onExit}
|
||||||
|
>
|
||||||
|
Exit
|
||||||
|
</button>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,9 +66,10 @@ const {arrayOf, bool, func, shape, string} = PropTypes
|
||||||
TickscriptHeader.propTypes = {
|
TickscriptHeader.propTypes = {
|
||||||
isNewTickscript: bool,
|
isNewTickscript: bool,
|
||||||
onSave: func,
|
onSave: func,
|
||||||
|
onExit: func.isRequired,
|
||||||
areLogsVisible: bool,
|
areLogsVisible: bool,
|
||||||
areLogsEnabled: bool,
|
areLogsEnabled: bool,
|
||||||
onToggleLogsVisbility: func.isRequired,
|
onToggleLogsVisibility: func.isRequired,
|
||||||
task: shape({
|
task: shape({
|
||||||
dbrps: arrayOf(
|
dbrps: arrayOf(
|
||||||
shape({
|
shape({
|
||||||
|
@ -52,6 +78,7 @@ TickscriptHeader.propTypes = {
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
unsavedChanges: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TickscriptHeader
|
export default TickscriptHeader
|
||||||
|
|
|
@ -24,11 +24,12 @@ class TickscriptPage extends Component {
|
||||||
dbrps: [],
|
dbrps: [],
|
||||||
type: 'stream',
|
type: 'stream',
|
||||||
},
|
},
|
||||||
validation: '',
|
consoleMessage: '',
|
||||||
isEditingID: true,
|
isEditingID: true,
|
||||||
logs: [],
|
logs: [],
|
||||||
areLogsEnabled: false,
|
areLogsEnabled: false,
|
||||||
failStr: '',
|
failStr: '',
|
||||||
|
unsavedChanges: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,9 +173,10 @@ class TickscriptPage extends Component {
|
||||||
} else {
|
} else {
|
||||||
response = await createTask(kapacitor, task, router, sourceID)
|
response = await createTask(kapacitor, task, router, sourceID)
|
||||||
}
|
}
|
||||||
|
if (response.code) {
|
||||||
if (response && response.code === 500) {
|
this.setState({unsavedChanges: true, consoleMessage: response.message})
|
||||||
return this.setState({validation: response.message})
|
} else {
|
||||||
|
this.setState({unsavedChanges: false, consoleMessage: ''})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
@ -182,37 +184,57 @@ class TickscriptPage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleExit = () => {
|
||||||
|
const {source: {id: sourceID}, router} = this.props
|
||||||
|
|
||||||
|
return router.push(`/sources/${sourceID}/alert-rules`)
|
||||||
|
}
|
||||||
|
|
||||||
handleChangeScript = tickscript => {
|
handleChangeScript = tickscript => {
|
||||||
this.setState({task: {...this.state.task, tickscript}})
|
this.setState({
|
||||||
|
task: {...this.state.task, tickscript},
|
||||||
|
unsavedChanges: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelectDbrps = dbrps => {
|
handleSelectDbrps = dbrps => {
|
||||||
this.setState({task: {...this.state.task, dbrps}})
|
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeType = type => () => {
|
handleChangeType = type => () => {
|
||||||
this.setState({task: {...this.state.task, type}})
|
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeID = e => {
|
handleChangeID = e => {
|
||||||
this.setState({task: {...this.state.task, id: e.target.value}})
|
this.setState({
|
||||||
|
task: {...this.state.task, id: e.target.value},
|
||||||
|
unsavedChanges: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleLogsVisbility = () => {
|
handleToggleLogsVisibility = () => {
|
||||||
this.setState({areLogsVisible: !this.state.areLogsVisible})
|
this.setState({areLogsVisible: !this.state.areLogsVisible})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {source} = this.props
|
const {source} = this.props
|
||||||
const {task, validation, logs, areLogsVisible, areLogsEnabled} = this.state
|
const {
|
||||||
|
task,
|
||||||
|
logs,
|
||||||
|
areLogsVisible,
|
||||||
|
areLogsEnabled,
|
||||||
|
unsavedChanges,
|
||||||
|
consoleMessage,
|
||||||
|
} = this.state
|
||||||
return (
|
return (
|
||||||
<Tickscript
|
<Tickscript
|
||||||
task={task}
|
task={task}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
source={source}
|
source={source}
|
||||||
validation={validation}
|
consoleMessage={consoleMessage}
|
||||||
onSave={this.handleSave}
|
onSave={this.handleSave}
|
||||||
|
unsavedChanges={unsavedChanges}
|
||||||
|
onExit={this.handleExit}
|
||||||
isNewTickscript={!this._isEditing()}
|
isNewTickscript={!this._isEditing()}
|
||||||
onSelectDbrps={this.handleSelectDbrps}
|
onSelectDbrps={this.handleSelectDbrps}
|
||||||
onChangeScript={this.handleChangeScript}
|
onChangeScript={this.handleChangeScript}
|
||||||
|
@ -220,7 +242,7 @@ class TickscriptPage extends Component {
|
||||||
onChangeID={this.handleChangeID}
|
onChangeID={this.handleChangeID}
|
||||||
areLogsVisible={areLogsVisible}
|
areLogsVisible={areLogsVisible}
|
||||||
areLogsEnabled={areLogsEnabled}
|
areLogsEnabled={areLogsEnabled}
|
||||||
onToggleLogsVisbility={this.handleToggleLogsVisbility}
|
onToggleLogsVisibility={this.handleToggleLogsVisibility}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
import React, {Component, PropTypes} from 'react'
|
||||||
|
|
||||||
|
import OnClickOutside from 'shared/components/OnClickOutside'
|
||||||
|
|
||||||
|
class ConfirmButton extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
expanded: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleButtonClick = () => {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.setState({expanded: !this.state.expanded})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleConfirmClick = () => {
|
||||||
|
this.setState({expanded: false})
|
||||||
|
this.props.confirmAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickOutside = () => {
|
||||||
|
this.setState({expanded: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
calculatePosition = () => {
|
||||||
|
if (!this.buttonDiv || !this.tooltipDiv) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const windowWidth = window.innerWidth
|
||||||
|
const buttonRect = this.buttonDiv.getBoundingClientRect()
|
||||||
|
const tooltipRect = this.tooltipDiv.getBoundingClientRect()
|
||||||
|
|
||||||
|
const rightGap = windowWidth - buttonRect.right
|
||||||
|
|
||||||
|
if (tooltipRect.width / 2 > rightGap) {
|
||||||
|
return 'left'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'bottom'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
text,
|
||||||
|
confirmText,
|
||||||
|
type,
|
||||||
|
size,
|
||||||
|
square,
|
||||||
|
icon,
|
||||||
|
disabled,
|
||||||
|
customClass,
|
||||||
|
} = this.props
|
||||||
|
const {expanded} = this.state
|
||||||
|
|
||||||
|
const customClassString = customClass ? ` ${customClass}` : ''
|
||||||
|
const squareString = square ? ' btn-square' : ''
|
||||||
|
const expandedString = expanded ? ' active' : ''
|
||||||
|
const disabledString = disabled ? ' disabled' : ''
|
||||||
|
|
||||||
|
const classname = `confirm-button btn ${type} ${size}${customClassString}${squareString}${expandedString}${disabledString}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classname}
|
||||||
|
onClick={this.handleButtonClick}
|
||||||
|
ref={r => (this.buttonDiv = r)}
|
||||||
|
>
|
||||||
|
{icon && <span className={`icon ${icon}`} />}
|
||||||
|
{text && text}
|
||||||
|
<div className={`confirm-button--tooltip ${this.calculatePosition()}`}>
|
||||||
|
<div
|
||||||
|
className="confirm-button--confirmation"
|
||||||
|
onClick={this.handleConfirmClick}
|
||||||
|
ref={r => (this.tooltipDiv = r)}
|
||||||
|
>
|
||||||
|
{confirmText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {bool, func, string} = PropTypes
|
||||||
|
|
||||||
|
ConfirmButton.defaultProps = {
|
||||||
|
confirmText: 'Confirm',
|
||||||
|
type: 'btn-default',
|
||||||
|
size: 'btn-sm',
|
||||||
|
square: false,
|
||||||
|
}
|
||||||
|
ConfirmButton.propTypes = {
|
||||||
|
text: string,
|
||||||
|
confirmText: string,
|
||||||
|
confirmAction: func.isRequired,
|
||||||
|
type: string,
|
||||||
|
size: string,
|
||||||
|
square: bool,
|
||||||
|
icon: string,
|
||||||
|
disabled: bool,
|
||||||
|
customClass: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OnClickOutside(ConfirmButton)
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
@import 'components/ceo-display-options';
|
@import 'components/ceo-display-options';
|
||||||
|
@import 'components/confirm-button';
|
||||||
@import 'components/confirm-buttons';
|
@import 'components/confirm-buttons';
|
||||||
@import 'components/code-mirror-theme';
|
@import 'components/code-mirror-theme';
|
||||||
@import 'components/color-dropdown';
|
@import 'components/color-dropdown';
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
Confirm Button
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
This button requires a second click to confirm the action
|
||||||
|
*/
|
||||||
|
|
||||||
|
.confirm-button {
|
||||||
|
.confirm-button--tooltip {
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&.bottom {
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
top: 50%;
|
||||||
|
right: calc(100% + 4px);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.confirm-button--confirmation {
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: $c-curacao;
|
||||||
|
opacity: 0;
|
||||||
|
padding: 0 7px;
|
||||||
|
color: $g20-white;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
transition: opacity 0.25s ease, background-color 0.25s ease;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
border: 8px solid transparent;
|
||||||
|
position: absolute;
|
||||||
|
transition: border-color 0.25s ease;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $c-dreamsicle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-button--tooltip.bottom .confirm-button--confirmation:after {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
border-bottom-color: $c-curacao;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
.confirm-button--tooltip.bottom .confirm-button--confirmation:hover:after {
|
||||||
|
border-bottom-color: $c-dreamsicle;
|
||||||
|
}
|
||||||
|
.confirm-button--tooltip.left .confirm-button--confirmation:after {
|
||||||
|
left: 100%;
|
||||||
|
top: 50%;
|
||||||
|
border-left-color: $c-curacao;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
.confirm-button--tooltip.left .confirm-button--confirmation:hover:after {
|
||||||
|
border-left-color: $c-dreamsicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-button.active {
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
.confirm-button--tooltip {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.confirm-button--confirmation {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,28 +3,26 @@
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$tickscript-console-height: 60px;
|
$tickscript-controls-height: 60px;
|
||||||
|
|
||||||
.tickscript {
|
.tickscript {
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.tickscript-controls,
|
.tickscript-controls,
|
||||||
.tickscript-console,
|
.tickscript-console,
|
||||||
.tickscript-editor {
|
.tickscript-editor {
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
.tickscript-controls,
|
.tickscript-console,
|
||||||
.tickscript-console {
|
.tickscript-controls {
|
||||||
height: $tickscript-console-height;
|
padding: 0 60px;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
.tickscript-controls {
|
.tickscript-controls {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: $tickscript-controls-height;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 60px;
|
|
||||||
background-color: $g3-castle;
|
background-color: $g3-castle;
|
||||||
}
|
}
|
||||||
.tickscript-controls--name {
|
.tickscript-controls--name {
|
||||||
|
@ -42,29 +40,42 @@ $tickscript-console-height: 60px;
|
||||||
|
|
||||||
> * {margin-left: 8px;}
|
> * {margin-left: 8px;}
|
||||||
}
|
}
|
||||||
.tickscript-console--output {
|
.tickscript-console {
|
||||||
padding: 0 60px;
|
align-items: flex-start;
|
||||||
font-family: $code-font;
|
height: $tickscript-controls-height * 2.25;
|
||||||
font-weight: 600;
|
border-top: 2px solid $g3-castle;
|
||||||
display: flex;
|
background-color: $g0-obsidian;
|
||||||
align-items: center;
|
overflow-y: scroll;
|
||||||
background-color: $g2-kevlar;
|
@include custom-scrollbar($g0-obsidian,$g4-onyx);
|
||||||
border-bottom: 2px solid $g3-castle;
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: $radius $radius 0 0;
|
|
||||||
|
|
||||||
> p {
|
> p {
|
||||||
margin: 0;
|
position: relative;
|
||||||
|
padding-left: 16px;
|
||||||
|
font-family: $code-font;
|
||||||
|
margin: 11px 0;
|
||||||
|
font-weight: 700;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '>';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tickscript-console--default {
|
.tickscript-console--default {
|
||||||
color: $g10-wolf;
|
color: $g13-mist;
|
||||||
font-style: italic;
|
}
|
||||||
|
.tickscript-console--valid {
|
||||||
|
color: $c-rainforest;
|
||||||
|
}
|
||||||
|
.tickscript-console--error {
|
||||||
|
color: $c-dreamsicle;
|
||||||
}
|
}
|
||||||
.tickscript-editor {
|
.tickscript-editor {
|
||||||
height: calc(100% - #{$tickscript-console-height * 2});
|
height: calc(100% - #{$tickscript-controls-height * 3.25});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue