diff --git a/ui/src/chronograf/components/QueryTabItem.js b/ui/src/chronograf/components/QueryTabItem.js
index ab16e8692..60eda42e0 100644
--- a/ui/src/chronograf/components/QueryTabItem.js
+++ b/ui/src/chronograf/components/QueryTabItem.js
@@ -23,9 +23,9 @@ const QueryTabItem = React.createClass({
render() {
return (
-
-
{this.props.query.rawText ? 'Raw Text' : this.props.queryTabText}
-
+
+ {this.props.query.rawText ? 'Raw Text' : this.props.queryTabText}
+
);
},
diff --git a/ui/src/chronograf/components/RawQueryEditor.js b/ui/src/chronograf/components/RawQueryEditor.js
new file mode 100644
index 000000000..03c347e4c
--- /dev/null
+++ b/ui/src/chronograf/components/RawQueryEditor.js
@@ -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 (
+
+
+ );
+ },
+});
+
+export default RawQueryEditor;
diff --git a/ui/src/chronograf/reducers/queryConfigs.js b/ui/src/chronograf/reducers/queryConfigs.js
index 82fe56c7c..7b0bcc865 100644
--- a/ui/src/chronograf/reducers/queryConfigs.js
+++ b/ui/src/chronograf/reducers/queryConfigs.js
@@ -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);
diff --git a/ui/src/shared/components/SimpleDropdown.js b/ui/src/shared/components/SimpleDropdown.js
new file mode 100644
index 000000000..8871be49d
--- /dev/null
+++ b/ui/src/shared/components/SimpleDropdown.js
@@ -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 (
+
+
+ {this.props.children}
+
+ {self.state.isOpen ?
+
+ {items.map((item, i) => {
+ return (
+ - self.handleSelection(item)}>
+
+ {item.text}
+
+
+ );
+ })}
+
+ : null}
+
+ );
+ },
+});
+
+export default OnClickOutside(Dropdown);
diff --git a/ui/src/style/chronograf/components/_Explorer.scss b/ui/src/style/chronograf/components/_Panel.scss
similarity index 83%
rename from ui/src/style/chronograf/components/_Explorer.scss
rename to ui/src/style/chronograf/components/_Panel.scss
index e62af7547..a7fcdb832 100644
--- a/ui/src/style/chronograf/components/_Explorer.scss
+++ b/ui/src/style/chronograf/components/_Panel.scss
@@ -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;
* {
diff --git a/ui/src/style/chronograf/components/_QueryEditor.scss b/ui/src/style/chronograf/components/_QueryEditor.scss
index 695c5a1ee..80172b717 100644
--- a/ui/src/style/chronograf/components/_QueryEditor.scss
+++ b/ui/src/style/chronograf/components/_QueryEditor.scss
@@ -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;
}
}
}
diff --git a/ui/src/style/chronograf/components/_RawQueryEditor.scss b/ui/src/style/chronograf/components/_RawQueryEditor.scss
deleted file mode 100644
index 3dc766096..000000000
--- a/ui/src/style/chronograf/components/_RawQueryEditor.scss
+++ /dev/null
@@ -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;
- }
- }
-
-}
diff --git a/ui/src/style/chronograf/components/_RawText.scss b/ui/src/style/chronograf/components/_RawText.scss
new file mode 100644
index 000000000..b9e0e1a15
--- /dev/null
+++ b/ui/src/style/chronograf/components/_RawText.scss
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/ui/src/style/chronograf/main.scss b/ui/src/style/chronograf/main.scss
index 026b83991..f20658b90 100644
--- a/ui/src/style/chronograf/main.scss
+++ b/ui/src/style/chronograf/main.scss
@@ -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';
diff --git a/ui/src/style/enterprise_style/_enterprise-custom.scss b/ui/src/style/enterprise_style/_enterprise-custom.scss
index 13850c75d..35346297d 100644
--- a/ui/src/style/enterprise_style/_enterprise-custom.scss
+++ b/ui/src/style/enterprise_style/_enterprise-custom.scss
@@ -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 {
diff --git a/ui/src/style/enterprise_style/fonts.css b/ui/src/style/enterprise_style/fonts.css
index b1bef5d85..f0bc55849 100644
--- a/ui/src/style/enterprise_style/fonts.css
+++ b/ui/src/style/enterprise_style/fonts.css
@@ -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');
+}
diff --git a/ui/src/style/enterprise_style/fonts/RobotoMono-Medium.ttf b/ui/src/style/enterprise_style/fonts/RobotoMono-Medium.ttf
new file mode 100755
index 000000000..88ff0c15a
Binary files /dev/null and b/ui/src/style/enterprise_style/fonts/RobotoMono-Medium.ttf differ
diff --git a/ui/src/style/enterprise_style/theme-dark.scss b/ui/src/style/enterprise_style/theme-dark.scss
index ac6dafb99..4c9bec6d7 100644
--- a/ui/src/style/enterprise_style/theme-dark.scss
+++ b/ui/src/style/enterprise_style/theme-dark.scss
@@ -323,7 +323,9 @@ textarea {
Dark Code Samples
----------------------------------------------
*/
-
+code, pre {
+ font-family: 'RobotoMono', monospace !important;
+}
code {
display: inline-block;
background-color: $g2-kevlar;
diff --git a/ui/src/utils/queryTransitions.js b/ui/src/utils/queryTransitions.js
index cf7af5649..f5c4c52de 100644
--- a/ui/src/utils/queryTransitions.js
+++ b/ui/src/utils/queryTransitions.js
@@ -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) {