commit
880b69a3e1
|
@ -1,5 +1,8 @@
|
|||
## v1.1.0 [unreleased]
|
||||
|
||||
### Features
|
||||
1. [#610](https://github.com/influxdata/chronograf/issues/610): Add Ability to edit raw text queries in the Data Explorer
|
||||
|
||||
## v1.1.0-beta2 [2016-12-09]
|
||||
|
||||
### Features
|
||||
|
|
|
@ -34,12 +34,13 @@ export function deletePanel(panelId) {
|
|||
};
|
||||
}
|
||||
|
||||
export function addQuery(panelId) {
|
||||
export function addQuery(panelId, options) {
|
||||
return {
|
||||
type: 'ADD_QUERY',
|
||||
payload: {
|
||||
panelId,
|
||||
queryId: uuid.v4(),
|
||||
options,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -118,6 +119,16 @@ export function chooseMeasurement(queryId, measurement) {
|
|||
};
|
||||
}
|
||||
|
||||
export function editRawText(queryId, rawText) {
|
||||
return {
|
||||
type: 'EDIT_RAW_TEXT',
|
||||
payload: {
|
||||
queryId,
|
||||
rawText,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function setTimeRange(range) {
|
||||
window.localStorage.setItem('timeRange', JSON.stringify(range));
|
||||
|
||||
|
|
|
@ -3,9 +3,10 @@ import classNames from 'classnames';
|
|||
import QueryEditor from './QueryEditor';
|
||||
import QueryTabItem from './QueryTabItem';
|
||||
import RenamePanelModal from './RenamePanelModal';
|
||||
import SimpleDropdown from 'src/shared/components/SimpleDropdown';
|
||||
|
||||
const {shape, func, bool, arrayOf} = PropTypes;
|
||||
const Explorer = React.createClass({
|
||||
const Panel = React.createClass({
|
||||
propTypes: {
|
||||
panel: shape({}).isRequired,
|
||||
queries: arrayOf(shape({})).isRequired,
|
||||
|
@ -14,7 +15,7 @@ const Explorer = React.createClass({
|
|||
lower: PropTypes.string,
|
||||
}).isRequired,
|
||||
isExpanded: bool.isRequired,
|
||||
onToggleExplorer: func.isRequired,
|
||||
onTogglePanel: func.isRequired,
|
||||
actions: shape({
|
||||
chooseNamespace: func.isRequired,
|
||||
chooseMeasurement: func.isRequired,
|
||||
|
@ -44,12 +45,16 @@ const Explorer = React.createClass({
|
|||
this.props.actions.addQuery();
|
||||
},
|
||||
|
||||
handleAddRawQuery() {
|
||||
this.props.actions.addQuery({rawText: `SELECT "fields" from "db"."rp"."measurement"`});
|
||||
},
|
||||
|
||||
handleDeleteQuery(query) {
|
||||
this.props.actions.deleteQuery(query.id);
|
||||
},
|
||||
|
||||
handleSelectExplorer() {
|
||||
this.props.onToggleExplorer(this.props.panel);
|
||||
handleSelectPanel() {
|
||||
this.props.onTogglePanel(this.props.panel);
|
||||
},
|
||||
|
||||
handleDeletePanel(e) {
|
||||
|
@ -79,16 +84,16 @@ const Explorer = React.createClass({
|
|||
const {panel, isExpanded} = this.props;
|
||||
|
||||
return (
|
||||
<div className={classNames('explorer', {active: isExpanded})}>
|
||||
<div className="explorer--header" onClick={this.handleSelectExplorer}>
|
||||
<div className="explorer--name">
|
||||
<div className={classNames('panel', {active: isExpanded})}>
|
||||
<div className="panel--header" onClick={this.handleSelectPanel}>
|
||||
<div className="panel--name">
|
||||
<span className="icon caret-right"></span>
|
||||
{panel.name || "Graph"}
|
||||
</div>
|
||||
<div className="explorer--actions">
|
||||
<div title="Export Queries to Dashboard" className="explorer--action"><span className="icon export"></span></div>
|
||||
<div title="Rename Graph" className="explorer--action" onClick={this.openRenamePanelModal}><span className="icon pencil"></span></div>
|
||||
<div title="Delete Graph" className="explorer--action" onClick={this.handleDeletePanel}><span className="icon trash"></span></div>
|
||||
<div className="panel--actions">
|
||||
{/* <div title="Export Queries to Dashboard" className="panel--action"><span className="icon export"></span></div> */}
|
||||
<div title="Rename Graph" className="panel--action" onClick={this.openRenamePanelModal}><span className="icon pencil"></span></div>
|
||||
<div title="Delete Graph" className="panel--action" onClick={this.handleDeletePanel}><span className="icon trash"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
{this.renderQueryTabList()}
|
||||
|
@ -127,12 +132,13 @@ const Explorer = React.createClass({
|
|||
},
|
||||
|
||||
renderQueryTabList() {
|
||||
if (!this.props.isExpanded) {
|
||||
const {isExpanded, queries} = this.props;
|
||||
if (!isExpanded) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="explorer--tabs">
|
||||
{this.props.queries.map((q) => {
|
||||
<div className="panel--tabs">
|
||||
{queries.map((q) => {
|
||||
const queryTabText = (q.measurement && q.fields.length !== 0) ? `${q.measurement}.${q.fields[0].field}` : 'Query';
|
||||
return (
|
||||
<QueryTabItem
|
||||
|
@ -145,12 +151,30 @@ const Explorer = React.createClass({
|
|||
/>
|
||||
);
|
||||
})}
|
||||
<div className="explorer--tab" onClick={this.handleAddQuery}>
|
||||
<span className="icon plus"></span>
|
||||
</div>
|
||||
|
||||
{this.renderAddQuery()}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
onChoose(item) {
|
||||
switch (item.text) {
|
||||
case 'Query Builder':
|
||||
this.handleAddQuery();
|
||||
break;
|
||||
case 'Raw Text':
|
||||
this.handleAddRawQuery();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
renderAddQuery() {
|
||||
return (
|
||||
<SimpleDropdown onChoose={this.onChoose} items={[{text: 'Query Builder'}, {text: 'Raw Text'}]} className="panel--tab-new">
|
||||
<span className="icon plus"></span>
|
||||
</SimpleDropdown>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default Explorer;
|
||||
export default Panel;
|
|
@ -1,7 +1,7 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import ExplorerList from './ExplorerList';
|
||||
import PanelList from './PanelList';
|
||||
import * as viewActions from '../actions/view';
|
||||
|
||||
const {string, func} = PropTypes;
|
||||
|
@ -12,6 +12,7 @@ const PanelBuilder = React.createClass({
|
|||
createPanel: func.isRequired,
|
||||
deleteQuery: func.isRequired,
|
||||
addQuery: func.isRequired,
|
||||
editRawText: func.isRequired,
|
||||
chooseNamespace: func.isRequired,
|
||||
chooseMeasurement: func.isRequired,
|
||||
toggleField: func.isRequired,
|
||||
|
@ -31,15 +32,15 @@ const PanelBuilder = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const {width, actions} = this.props;
|
||||
const {activePanelID, width, actions, setActivePanel} = this.props;
|
||||
|
||||
return (
|
||||
<div className="panel-builder" style={{width}}>
|
||||
<div className="btn btn-block btn-primary" onClick={this.handleCreateExploer}><span className="icon graphline"></span> Create Graph</div>
|
||||
<ExplorerList
|
||||
<PanelList
|
||||
actions={actions}
|
||||
setActivePanel={this.props.setActivePanel}
|
||||
activePanelID={this.props.activePanelID}
|
||||
setActivePanel={setActivePanel}
|
||||
activePanelID={activePanelID}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,10 +2,10 @@ import React, {PropTypes} from 'react';
|
|||
import {connect} from 'react-redux';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Explorer from './Explorer';
|
||||
import Panel from './Panel';
|
||||
|
||||
const {func, string, shape} = PropTypes;
|
||||
const ExplorerList = React.createClass({
|
||||
const PanelList = React.createClass({
|
||||
propTypes: {
|
||||
timeRange: shape({
|
||||
upper: string,
|
||||
|
@ -18,9 +18,9 @@ const ExplorerList = React.createClass({
|
|||
activePanelID: string,
|
||||
},
|
||||
|
||||
handleToggleExplorer(panel) {
|
||||
// If the explorer being toggled is currently active, it means we should
|
||||
// close everything by setting `activeExplorerIndex` to null.
|
||||
handleTogglePanel(panel) {
|
||||
// If the panel being toggled is currently active, it means we should
|
||||
// close everything by setting `activePanelID` to null.
|
||||
const activePanelID = panel.id === this.props.activePanelID ?
|
||||
null : panel.id;
|
||||
|
||||
|
@ -45,12 +45,12 @@ const ExplorerList = React.createClass({
|
|||
});
|
||||
|
||||
return (
|
||||
<Explorer
|
||||
<Panel
|
||||
key={panelID}
|
||||
panel={panel}
|
||||
queries={queries}
|
||||
timeRange={timeRange}
|
||||
onToggleExplorer={this.handleToggleExplorer}
|
||||
onTogglePanel={this.handleTogglePanel}
|
||||
isExpanded={panelID === activePanelID}
|
||||
actions={allActions}
|
||||
/>
|
||||
|
@ -69,4 +69,4 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ExplorerList);
|
||||
export default connect(mapStateToProps)(PanelList);
|
|
@ -7,6 +7,7 @@ import DatabaseList from './DatabaseList';
|
|||
import MeasurementList from './MeasurementList';
|
||||
import FieldList from './FieldList';
|
||||
import TagList from './TagList';
|
||||
import RawQueryEditor from './RawQueryEditor';
|
||||
|
||||
const DB_TAB = 'databases';
|
||||
const MEASUREMENTS_TAB = 'measurments';
|
||||
|
@ -86,37 +87,39 @@ const QueryEditor = React.createClass({
|
|||
this.props.actions.groupByTag(this.props.query.id, tagKey);
|
||||
},
|
||||
|
||||
handleEditRawText(text) {
|
||||
this.props.actions.editRawText(this.props.query.id, text);
|
||||
},
|
||||
|
||||
handleClickTab(tab) {
|
||||
this.setState({activeTab: tab});
|
||||
},
|
||||
|
||||
render() {
|
||||
const {query, timeRange} = this.props;
|
||||
|
||||
const statement = query.rawText || selectStatement(timeRange, query) || `SELECT "fields" FROM "db"."rp"."measurement"`;
|
||||
|
||||
return (
|
||||
<div className="explorer--tab-contents">
|
||||
<div className="qeditor--query-preview">
|
||||
<pre className={classNames("", {"rq-mode": query.rawText})}><code>{statement}</code></pre>
|
||||
</div>
|
||||
{this.renderEditor()}
|
||||
<div className="panel--tab-contents">
|
||||
{this.renderQuery()}
|
||||
{this.renderLists()}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
renderEditor() {
|
||||
if (this.props.query.rawText) {
|
||||
renderQuery() {
|
||||
const {query, timeRange} = this.props;
|
||||
const statement = query.rawText || selectStatement(timeRange, query) || `SELECT "fields" FROM "db"."rp"."measurement"`;
|
||||
|
||||
if (!query.rawText) {
|
||||
return (
|
||||
<div className="qeditor--empty">
|
||||
<p className="margin-bottom-zero">
|
||||
<span className="icon alert-triangle"></span>
|
||||
Only editable in the <strong>Raw Query</strong> tab.
|
||||
</p>
|
||||
<div className="qeditor--query-preview">
|
||||
<pre><code>{statement}</code></pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <RawQueryEditor query={query} onUpdate={this.handleEditRawText} />;
|
||||
},
|
||||
|
||||
renderLists() {
|
||||
const {activeTab} = this.state;
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -23,9 +23,9 @@ const QueryTabItem = React.createClass({
|
|||
|
||||
render() {
|
||||
return (
|
||||
<div className={classNames('explorer--tab', {active: this.props.isActive})} onClick={this.handleSelect}>
|
||||
<span className="explorer--tab-label">{this.props.query.rawText ? 'Raw Text' : this.props.queryTabText}</span>
|
||||
<span className="explorer--tab-delete" onClick={this.handleDelete}></span>
|
||||
<div className={classNames('panel--tab', {active: this.props.isActive})} onClick={this.handleSelect}>
|
||||
<span className="panel--tab-label">{this.props.query.rawText ? 'Raw Text' : this.props.queryTabText}</span>
|
||||
<span className="panel--tab-delete" onClick={this.handleDelete}></span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
|
||||
const ENTER = 13;
|
||||
const ESCAPE = 27;
|
||||
const RawQueryEditor = React.createClass({
|
||||
propTypes: {
|
||||
query: PropTypes.shape({
|
||||
rawText: PropTypes.string.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
value: this.props.query.rawText,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.query.rawText !== this.props.query.rawText) {
|
||||
this.setState({value: nextProps.query.rawText});
|
||||
}
|
||||
},
|
||||
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === ENTER) {
|
||||
this.handleUpdate();
|
||||
this.editor.blur();
|
||||
} else if (e.keyCode === ESCAPE) {
|
||||
this.setState({value: this.props.query.rawText}, () => {
|
||||
this.editor.blur();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handleChange() {
|
||||
this.setState({
|
||||
value: this.editor.value,
|
||||
});
|
||||
},
|
||||
|
||||
handleUpdate() {
|
||||
this.props.onUpdate(this.state.value);
|
||||
},
|
||||
|
||||
render() {
|
||||
const {value} = this.state;
|
||||
|
||||
return (
|
||||
<div className="raw-text">
|
||||
<textarea
|
||||
className="raw-text--field"
|
||||
onChange={this.handleChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onBlur={this.handleUpdate}
|
||||
ref={(editor) => this.editor = editor}
|
||||
value={value}
|
||||
placeholder="Blank query"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default RawQueryEditor;
|
|
@ -1,5 +1,6 @@
|
|||
import defaultQueryConfig from 'src/utils/defaultQueryConfig';
|
||||
import {
|
||||
editRawText,
|
||||
applyFuncsToField,
|
||||
chooseMeasurement,
|
||||
chooseNamespace,
|
||||
|
@ -20,10 +21,10 @@ export default function queryConfigs(state = {}, action) {
|
|||
|
||||
case 'CHOOSE_NAMESPACE': {
|
||||
const {queryId, database, retentionPolicy} = action.payload;
|
||||
const nextQueryConfig = chooseNamespace(defaultQueryConfig(queryId), {database, retentionPolicy});
|
||||
const nextQueryConfig = chooseNamespace(state[queryId], {database, retentionPolicy});
|
||||
|
||||
return Object.assign({}, state, {
|
||||
[queryId]: nextQueryConfig,
|
||||
[queryId]: Object.assign(nextQueryConfig, {rawText: state[queryId].rawText}),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -32,7 +33,7 @@ export default function queryConfigs(state = {}, action) {
|
|||
const nextQueryConfig = chooseMeasurement(state[queryId], measurement);
|
||||
|
||||
return Object.assign({}, state, {
|
||||
[queryId]: nextQueryConfig,
|
||||
[queryId]: Object.assign(nextQueryConfig, {rawText: state[queryId].rawText}),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,9 +49,9 @@ export default function queryConfigs(state = {}, action) {
|
|||
case 'CREATE_PANEL':
|
||||
case 'ADD_KAPACITOR_QUERY':
|
||||
case 'ADD_QUERY': {
|
||||
const {queryId} = action.payload;
|
||||
const {queryId, options} = action.payload;
|
||||
const nextState = Object.assign({}, state, {
|
||||
[queryId]: defaultQueryConfig(queryId),
|
||||
[queryId]: Object.assign({}, defaultQueryConfig(queryId), options),
|
||||
});
|
||||
|
||||
return nextState;
|
||||
|
@ -65,6 +66,15 @@ export default function queryConfigs(state = {}, action) {
|
|||
return nextState;
|
||||
}
|
||||
|
||||
case 'EDIT_RAW_TEXT': {
|
||||
const {queryId, rawText} = action.payload;
|
||||
const nextQueryConfig = editRawText(state[queryId], rawText);
|
||||
|
||||
return Object.assign({}, state, {
|
||||
[queryId]: nextQueryConfig,
|
||||
});
|
||||
}
|
||||
|
||||
case 'GROUP_BY_TIME': {
|
||||
const {queryId, time} = action.payload;
|
||||
const nextQueryConfig = groupByTime(state[queryId], time);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import OnClickOutside from 'shared/components/OnClickOutside';
|
||||
|
||||
const Dropdown = React.createClass({
|
||||
propTypes: {
|
||||
children: PropTypes.node.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.shape({
|
||||
text: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
onChoose: PropTypes.func.isRequired,
|
||||
className: PropTypes.string,
|
||||
},
|
||||
getInitialState() {
|
||||
return {
|
||||
isOpen: false,
|
||||
};
|
||||
},
|
||||
handleClickOutside() {
|
||||
this.setState({isOpen: false});
|
||||
},
|
||||
handleSelection(item) {
|
||||
this.toggleMenu();
|
||||
this.props.onChoose(item);
|
||||
},
|
||||
toggleMenu(e) {
|
||||
if (e) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
this.setState({isOpen: !this.state.isOpen});
|
||||
},
|
||||
render() {
|
||||
const self = this;
|
||||
const {items, className} = self.props;
|
||||
|
||||
return (
|
||||
<div onClick={this.toggleMenu} className={classNames(`dropdown ${className}`, {open: self.state.isOpen})}>
|
||||
<div className="btn btn-sm btn-info dropdown-toggle">
|
||||
{this.props.children}
|
||||
</div>
|
||||
{self.state.isOpen ?
|
||||
<ul className="dropdown-menu show">
|
||||
{items.map((item, i) => {
|
||||
return (
|
||||
<li className="dropdown-item" key={i} onClick={() => self.handleSelection(item)}>
|
||||
<a href="#">
|
||||
{item.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default OnClickOutside(Dropdown);
|
|
@ -1,18 +1,19 @@
|
|||
.explorer {
|
||||
.panel {
|
||||
display: block;
|
||||
background-color: $g3-castle;
|
||||
border-radius: $radius;
|
||||
margin-bottom: 6px;
|
||||
transition: background-color 0.25s ease;
|
||||
border: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: $g4-onyx;
|
||||
}
|
||||
|
||||
// For when an explorer item is open
|
||||
// For when an panel item is open
|
||||
&.active {
|
||||
background-color: $g4-onyx;
|
||||
.explorer__header {
|
||||
.panel__header {
|
||||
&-name {
|
||||
color: $g20-white;
|
||||
|
||||
|
@ -23,8 +24,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
// Explorer Header Bar
|
||||
.explorer--header {
|
||||
// panel Header Bar
|
||||
.panel--header {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
|
@ -35,7 +36,7 @@
|
|||
justify-content: space-between;
|
||||
border-radius: $radius;
|
||||
}
|
||||
.explorer--name {
|
||||
.panel--name {
|
||||
color: $g13-mist;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
@ -56,11 +57,11 @@
|
|||
color: $g17-whisper;
|
||||
}
|
||||
}
|
||||
.explorer--actions {
|
||||
.panel--actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.explorer--action {
|
||||
.panel--action {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 0;
|
||||
|
@ -76,12 +77,12 @@
|
|||
}
|
||||
|
||||
// Tabs
|
||||
.explorer--tabs {
|
||||
.panel--tabs {
|
||||
display: flex;
|
||||
background-color: $g4-onyx;
|
||||
padding: 0 11px;
|
||||
}
|
||||
.explorer--tab {
|
||||
.panel--tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $g11-sidewalk;
|
||||
|
@ -104,12 +105,6 @@
|
|||
color: $g15-platinum;
|
||||
}
|
||||
|
||||
> span.icon.plus {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
&-delete {
|
||||
margin: 0 -4px 0 1px;
|
||||
width: 16px;
|
||||
|
@ -147,7 +142,25 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.explorer--tab-label {
|
||||
.panel--tab-new {
|
||||
> .dropdown-toggle {
|
||||
height: 28px !important;
|
||||
border-radius: $radius $radius 0 0;
|
||||
|
||||
> .icon {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
> .dropdown-menu {
|
||||
width: 108px !important;
|
||||
min-width: 108px !important;
|
||||
max-width: 108px !important;
|
||||
}
|
||||
}
|
||||
.panel--tab-label {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
|
@ -161,7 +174,7 @@
|
|||
Tab Contents
|
||||
-------------------------------------------
|
||||
*/
|
||||
.explorer--tab-contents {
|
||||
.panel--tab-contents {
|
||||
padding: 6px;
|
||||
background-color: $g6-smoke;
|
||||
border-radius: 0 0 $radius $radius;
|
||||
|
@ -177,7 +190,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.explorer__header-actions {
|
||||
.panel__header-actions {
|
||||
display: flex;
|
||||
|
||||
* {
|
|
@ -15,11 +15,9 @@ $query-editor-height: 250px;
|
|||
|
||||
pre {
|
||||
padding: 9px;
|
||||
white-space: pre-wrap;
|
||||
border: 0;
|
||||
background-color: $query-editor-tab-inactive;
|
||||
font-weight: 600;
|
||||
color: $c-comet;
|
||||
color: $c-pool;
|
||||
border-radius: $radius-small $radius-small 0 0;
|
||||
border-bottom: 2px solid $query-editor-tab-active;
|
||||
margin-bottom: 0;
|
||||
|
@ -30,11 +28,7 @@ $query-editor-height: 250px;
|
|||
code {
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
&.rq-mode {
|
||||
color: $c-rainforest;
|
||||
@include custom-scrollbar($query-editor-tab-inactive, $c-rainforest);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
.raw-query-editor {
|
||||
width: 100%;
|
||||
height: 84px;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
color: $c-comet;
|
||||
padding: 6px 6px 6px 12px;
|
||||
border-radius: 0 3px 3px 0;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
border-left: 2px solid $g6-smoke;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
resize: none;
|
||||
margin: 0 0 4px 0;
|
||||
transition:
|
||||
color 0.25s ease,
|
||||
background-color 0.25s ease,
|
||||
border-color 0.25s ease;
|
||||
|
||||
&::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&::-moz-placeholder { /* Firefox 19+ */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:-ms-input-placeholder { /* IE 10+ */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:-moz-placeholder { /* Firefox 18- */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
background-color: $g6-smoke !important;
|
||||
color: $g18-cloud !important;
|
||||
border-color: $g8-storm !important;
|
||||
}
|
||||
}
|
||||
.raw-query-editor-wrapper {
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.raw-query-editor {
|
||||
background-color: fade-out($g5-pepper, 0.5);
|
||||
}
|
||||
.raw-query-editor-delete {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&.rq-mode {
|
||||
.raw-query-editor {
|
||||
color: $c-honeydew;
|
||||
}
|
||||
&:after {
|
||||
content: 'RQ';
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: $c-honeydew;
|
||||
color: $g6-smoke;
|
||||
z-index: 3;
|
||||
bottom: 12px;
|
||||
right: 2px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
line-height: 25px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
.raw-query-editor-delete {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: transparent;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
color 0.25s ease;
|
||||
border: 0;
|
||||
color: $g8-storm;
|
||||
opacity: 0;
|
||||
font-size: 13px;
|
||||
|
||||
> .icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $g20-white;
|
||||
}
|
||||
|
||||
}
|
||||
.raw-editor {
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&-name {
|
||||
color: $g20-white;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
&-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
> * {
|
||||
transition:
|
||||
color 0.25s ease;
|
||||
margin-left: 10px;
|
||||
color: $g8-storm;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: $g20-white;
|
||||
}
|
||||
}
|
||||
.raw-editor__header-delete:hover {
|
||||
color: $c-dreamsicle;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__panel {
|
||||
margin-top: 20px;
|
||||
padding-top: 5px;
|
||||
|
||||
&:first-child {
|
||||
border: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Dropping the metaphorical CSS nuke here,
|
||||
was experiencing some weird typographic jank
|
||||
between builder / raw tabs
|
||||
*/
|
||||
.raw-text--field,
|
||||
.qeditor--query-preview pre,
|
||||
.qeditor--query-preview pre code {
|
||||
font-style: normal !important;
|
||||
letter-spacing: 0.02em !important;
|
||||
font-size: 12px !important;
|
||||
font-family: 'RobotoMono', monospace !important;
|
||||
font-weight: 600 !important;
|
||||
word-wrap: break-word !important;
|
||||
word-break: break-all !important;
|
||||
white-space: pre-wrap !important;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
$raw-text-color: $c-comet;
|
||||
|
||||
.raw-text {
|
||||
border-bottom: 2px solid $g4-onyx;
|
||||
}
|
||||
.raw-text--field {
|
||||
@include custom-scrollbar($g2-kevlar, $raw-text-color);
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: $g2-kevlar;
|
||||
border: 2px solid $g2-kevlar;
|
||||
color: $raw-text-color;
|
||||
padding: (9px - 2px);
|
||||
border-radius: 3px 3px 0 0;
|
||||
line-height: 1.5em;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
resize: none;
|
||||
margin: 0;
|
||||
transition:
|
||||
color 0.25s ease,
|
||||
background-color 0.25s ease,
|
||||
border-color 0.25s ease;
|
||||
|
||||
&::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&::-moz-placeholder { /* Firefox 19+ */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:-ms-input-placeholder { /* IE 10+ */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:-moz-placeholder { /* Firefox 18- */
|
||||
color: $g8-storm;
|
||||
}
|
||||
&:hover {
|
||||
background-color: $g3-castle;
|
||||
border-color: $g3-castle;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
color: $raw-text-color !important;
|
||||
border-color: $c-pool;
|
||||
}
|
||||
}
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
@import 'components/QueryEditor';
|
||||
@import 'components/PanelBuilder';
|
||||
@import 'components/Explorer';
|
||||
@import 'components/Panel';
|
||||
@import 'components/MultiSelectDropdown';
|
||||
@import 'components/GroupByTimeDropdown';
|
||||
@import 'components/TagList';
|
||||
@import 'components/Resizer';
|
||||
@import 'components/Header';
|
||||
@import 'components/RawQueryEditor';
|
||||
@import 'components/RawText';
|
||||
@import 'components/Visualization';
|
||||
@import 'components/Tasks';
|
||||
@import 'components/spinner';
|
||||
|
|
|
@ -434,10 +434,10 @@ $form-static-checkbox-size: 16px;
|
|||
----------------------------------------------
|
||||
*/
|
||||
table .monotype {
|
||||
font-family: Consolas, "Lucida Console", Monaco, monospace;
|
||||
font-family: 'RobotoMono', monospace !important;
|
||||
letter-spacing: 0.69px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
font-weight: 500;
|
||||
color: $g9-mountain;
|
||||
}
|
||||
.table-dot {
|
||||
|
|
|
@ -34,3 +34,9 @@
|
|||
font-weight: 700;
|
||||
src: url('fonts/Roboto-Black.ttf');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'RobotoMono';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('fonts/RobotoMono-Medium.ttf');
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -323,7 +323,9 @@ textarea {
|
|||
Dark Code Samples
|
||||
----------------------------------------------
|
||||
*/
|
||||
|
||||
code, pre {
|
||||
font-family: 'RobotoMono', monospace !important;
|
||||
}
|
||||
code {
|
||||
display: inline-block;
|
||||
background-color: $g2-kevlar;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import defaultQueryConfig from './defaultQueryConfig';
|
||||
|
||||
export function editRawText(query, rawText) {
|
||||
return Object.assign({}, query, {rawText});
|
||||
}
|
||||
|
||||
export function chooseNamespace(query, namespace) {
|
||||
return Object.assign({}, query, namespace);
|
||||
return Object.assign({}, defaultQueryConfig(query.id), namespace);
|
||||
}
|
||||
|
||||
export function chooseMeasurement(query, measurement) {
|
||||
|
|
Loading…
Reference in New Issue