| 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>
 |