123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <% if @query.errors.any? %>
- <div class="alert alert-danger"><%= @query.errors.full_messages.first %></div>
- <% end %>
- <div id="app" v-cloak>
- <%= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {autocomplete: "off"} do |f| %>
- <div class="row">
- <div id="statement-box" class="col-xs-8">
- <div class= "form-group">
- <%= f.hidden_field :statement %>
- <div id="editor-container">
- <div id="editor" :style="{ height: editorHeight }"><%= @query.statement %></div>
- </div>
- </div>
- <div class="form-group text-right">
- <div class="pull-left" style="margin-top: 9px;">
- <%= link_to "Back", :back %>
- </div>
- <a :href="dataSourcePath" target="_blank" style="margin-right: 10px;">Schema</a>
- <%= f.select :data_source, Blazer.data_sources.values.select { |ds| q = @query.dup; q.data_source = ds.id; q.editable?(blazer_user) }.map { |ds| [ds.name, ds.id] }, {}, class: ("hide" if Blazer.data_sources.size <= 1), style: "width: 140px;" %>
- <div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;">
- <select id="table_names" style="width: 240px;" placeholder="Preview table"></select>
- </div>
- <a v-on:click="run" v-if="!running" class="btn btn-info" style="vertical-align: top; width: 70px;">Run</a>
- <a v-on:click="cancel" v-if="running" class="btn btn-danger" style="vertical-align: top; width: 70px;">Cancel</a>
- </div>
- </div>
- <div class="col-xs-4">
- <div class="form-group">
- <%= f.label :name %>
- <%= f.text_field :name, class: "form-control" %>
- </div>
- <div class="form-group">
- <%= f.label :description %>
- <%= f.text_area :description, placeholder: "Optional", style: "height: 80px;", class: "form-control" %>
- </div>
- <div class="text-right">
- <%= f.submit "For Enter Press", class: "hide" %>
- <% if @query.persisted? %>
- <%= link_to "Delete", query_path(@query), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
- <%= f.submit "Fork", class: "btn btn-info" %>
- <% end %>
- <%= f.submit @query.persisted? ? "Update" : "Create", class: "btn btn-success" %>
- </div>
- <% if @query.persisted? %>
- <% dashboards_count = @query.dashboards.count %>
- <% checks_count = @query.checks.count %>
- <% words = [] %>
- <% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
- <% words << pluralize(checks_count, "check") if checks_count > 0 %>
- <% if words.any? %>
- <div class="alert alert-info" style="margin-top: 10px; padding: 8px 12px;">
- Part of <%= words.to_sentence %>. Be careful when editing.
- </div>
- <% end %>
- <% end %>
- </div>
- </div>
- <% end %>
- <div id="results">
- <p class="text-muted" v-if="running">Loading...</p>
- <div id="results-html" v-if="!running" :class="{ 'query-error': error }"></div>
- </div>
- </div>
- <script>
- <%= blazer_js_var "params", variable_params %>
- <%= blazer_js_var "previewStatement", Hash[Blazer.data_sources.map { |k, v| [k, (v.preview_statement rescue "")] }] %>
- var app = new Vue({
- el: "#app",
- data: {
- running: false,
- results: "",
- error: false,
- dataSource: "",
- selectize: null,
- editorHeight: "180px"
- },
- computed: {
- dataSourcePath: function() {
- return Routes.schema_queries_path({data_source: this.dataSource})
- }
- },
- methods: {
- run: function(e) {
- this.running = true
- this.results = ""
- this.error = false
- cancelAllQueries()
- var data = $.extend({}, params, {statement: this.getSQL(), data_source: $("#query_data_source").val()})
- var _this = this
- runQuery(data, function (data) {
- _this.running = false
- _this.showResults(data)
- errorLine = _this.getErrorLine()
- if (errorLine) {
- editor.getSession().addGutterDecoration(errorLine - 1, "error")
- editor.scrollToLine(errorLine, true, true, function () {})
- editor.gotoLine(errorLine, 0, true)
- editor.focus()
- }
- }, function (data) {
- _this.running = false
- _this.error = true
- _this.showResults(data)
- })
- },
- cancel: function(e) {
- this.running = false
- cancelAllQueries()
- },
- updateDataSource: function(dataSource) {
- this.dataSource = dataSource
- var selectize = this.selectize
- selectize.clearOptions()
- if (this.tablesXhr) {
- this.tablesXhr.abort()
- }
- this.tablesXhr = $.getJSON(Routes.tables_queries_path({data_source: this.dataSource}), function(data) {
- var newOptions = []
- for (var i = 0; i < data.length; i++) {
- newOptions.push({text: data[i], value: data[i]})
- }
- selectize.clearOptions()
- selectize.addOption(newOptions)
- selectize.refreshOptions(false)
- })
- },
- showEditor: function() {
- var _this = this
- editor = ace.edit("editor")
- editor.setTheme("ace/theme/twilight")
- editor.getSession().setMode("ace/mode/sql")
- editor.setOptions({
- enableBasicAutocompletion: false,
- enableSnippets: false,
- enableLiveAutocompletion: false,
- highlightActiveLine: false,
- fontSize: 12,
- minLines: 10
- })
- editor.renderer.setShowGutter(true)
- editor.renderer.setPrintMarginColumn(false)
- editor.renderer.setPadding(10)
- editor.getSession().setUseWrapMode(true)
- editor.commands.addCommand({
- name: "run",
- bindKey: {win: "Ctrl-Enter", mac: "Command-Enter"},
- exec: function(editor) {
- _this.run()
- },
- readOnly: false // false if this command should not apply in readOnly mode
- })
- // fix command+L
- editor.commands.removeCommands(["gotoline", "find"])
- this.editor = editor
- editor.getSession().on("change", function () {
- $("#query_statement").val(editor.getValue())
- _this.adjustHeight()
- })
- this.adjustHeight()
- editor.focus()
- },
- adjustHeight: function() {
- // http://stackoverflow.com/questions/11584061/
- var editor = this.editor
- var lines = editor.getSession().getScreenLength()
- if (lines < 9) {
- lines = 9
- }
- this.editorHeight = ((lines + 1) * 16).toString() + "px"
- Vue.nextTick(function () {
- editor.resize()
- })
- },
- getSQL: function() {
- var selectedText = editor.getSelectedText()
- var text = selectedText.length < 10 ? editor.getValue() : selectedText
- return text.replace(/\n/g, "\r\n")
- },
- getErrorLine: function() {
- var editor = this.editor
- var errorLine = this.results.substring(0, 100).includes("alert-danger") && /LINE (\d+)/g.exec(this.results)
- if (errorLine) {
- errorLine = parseInt(errorLine[1], 10)
- if (editor.getSelectedText().length >= 10) {
- errorLine += editor.getSelectionRange().start.row
- }
- return errorLine
- }
- },
- showResults(data) {
- // can't do it the Vue way due to script tags in results
- // this.results = data
- Vue.nextTick(function () {
- $("#results-html").html(data)
- })
- }
- },
- mounted: function() {
- var _this = this
- var $select = $("#table_names").selectize({})
- var selectize = $select[0].selectize
- selectize.on("change", function(val) {
- editor.setValue(previewStatement[_this.dataSource].replace("{table}", val), 1)
- _this.run()
- selectize.clear(true)
- selectize.blur()
- })
- this.selectize = selectize
- this.updateDataSource($("#query_data_source").val())
- var $dsSelect = $("#query_data_source").selectize({})
- var dsSelectize = $dsSelect[0].selectize
- dsSelectize.on("change", function(val) {
- _this.updateDataSource(val)
- dsSelectize.blur()
- })
- this.showEditor()
- }
- })
- </script>
|