diff --git a/assets/javascripts/discourse/adapters/query.js.es6 b/assets/javascripts/discourse/adapters/query.js.es6 index 7875d61..1a5eebc 100644 --- a/assets/javascripts/discourse/adapters/query.js.es6 +++ b/assets/javascripts/discourse/adapters/query.js.es6 @@ -1,3 +1,11 @@ import buildPluginAdapter from 'discourse/adapters/build-plugin'; -export default buildPluginAdapter('explorer'); +export default buildPluginAdapter('explorer').extend({ + + createRecord(store, type, args) { + const typeField = Ember.String.underscore(type); + return Discourse.ajax(this.pathFor(store, type), {method: 'POST', data: args}).then(function (json) { + return new Result(json[typeField], json); + }); + } +}); diff --git a/assets/javascripts/discourse/controllers/admin-plugins-explorer.js.es6 b/assets/javascripts/discourse/controllers/admin-plugins-explorer.js.es6 new file mode 100644 index 0000000..de0210d --- /dev/null +++ b/assets/javascripts/discourse/controllers/admin-plugins-explorer.js.es6 @@ -0,0 +1,39 @@ +import showModal from 'discourse/lib/show-modal'; + +export default Ember.Controller.extend({ + selectedItem: null, + + actions: { + selectItem(item) { + this.set('selectedItem', item); + }, + + dummy() {}, + + create() { + var newQuery = this.store.createRecord('query', {name: this.get('newQueryName')}); + newQuery.save(); + }, + + importQuery() { + showModal('import-query'); + }, + + run() { + const self = this; + this.set('loading', true); + Discourse.ajax("/admin/plugins/explorer/query/" + this.get('selectedItem.id') + "/run", { + type: "POST", + data: { + params: JSON.stringify({foo: 34}), + explain: true + } + }).then(function(result) { + console.log(result); + self.set('results', result); + }).finally(function() { + self.set('loading', false); + }); + } + } +}); diff --git a/assets/javascripts/discourse/controllers/admin/plugins/explorer.js b/assets/javascripts/discourse/controllers/admin/plugins/explorer.js deleted file mode 100644 index bbce391..0000000 --- a/assets/javascripts/discourse/controllers/admin/plugins/explorer.js +++ /dev/null @@ -1,5 +0,0 @@ - - -export default Ember.ArrayController.extend({ - -}); diff --git a/assets/javascripts/discourse/controllers/import-query.js.es6 b/assets/javascripts/discourse/controllers/import-query.js.es6 index 1159197..f409bed 100644 --- a/assets/javascripts/discourse/controllers/import-query.js.es6 +++ b/assets/javascripts/discourse/controllers/import-query.js.es6 @@ -22,7 +22,7 @@ export default Ember.Controller.extend(ModalFunctionality, { const object = JSON.parse(this.get('queryFile')).query; // Slight fixup before creating object - delete object.id; + object.id = 0; // 0 means no Id yet this.set('loading', true); this.store.createRecord('query', object).save().then(function(query) { diff --git a/assets/javascripts/discourse/models/query.js.es6 b/assets/javascripts/discourse/models/query.js.es6 new file mode 100644 index 0000000..399967a --- /dev/null +++ b/assets/javascripts/discourse/models/query.js.es6 @@ -0,0 +1,15 @@ +import RestModel from 'discourse/models/rest'; + +const Query = RestModel.extend({ + createProperties() { + return this.getProperties("name", "description"); + }, + + run() { + console.log("Called query#run"); + } +}); + +console.log('query model loaded'); + +export default Query; diff --git a/assets/javascripts/discourse/routes/admin-plugins-explorer.js.es6 b/assets/javascripts/discourse/routes/admin-plugins-explorer.js.es6 index a057375..ed58205 100644 --- a/assets/javascripts/discourse/routes/admin-plugins-explorer.js.es6 +++ b/assets/javascripts/discourse/routes/admin-plugins-explorer.js.es6 @@ -1,22 +1,9 @@ -import showModal from 'discourse/lib/show-modal'; + export default Discourse.Route.extend({ controllerName: 'admin-plugins-explorer', model() { return this.store.findAll('query'); - }, - - setupController(controller, model) { - - }, - - actions: { - create() { - - }, - importQuery() { - showModal('import-query'); - } } }); diff --git a/assets/javascripts/discourse/templates/admin/plugins-explorer-show.hbs b/assets/javascripts/discourse/templates/admin/plugins-explorer-show.hbs new file mode 100644 index 0000000..a8180ba --- /dev/null +++ b/assets/javascripts/discourse/templates/admin/plugins-explorer-show.hbs @@ -0,0 +1,6 @@ +{{#if model}} +

{{model.name}}

+
{{model.description}}
+ {{textarea value=model.sql}} + {{d-button action="run" label="explorer.run"}} +{{/if}} diff --git a/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs b/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs index fa28eea..e17604a 100644 --- a/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs +++ b/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs @@ -1,8 +1,23 @@ +{{text-field value=newQueryName placeholderKey="explorer.create_placeholder"}} {{d-button action="create" label="explorer.create" icon="plus"}} -{{d-button action="importQuery" label="explorer.import.label" icon="upload"}} +{{d-button action="importQuery" label="explorer.import.label" icon="upload" class="import-button"}} -{{#each query in model}} -
- {{query.name}} -
-{{/each}} +

Queries

+ + + + + + + {{#each query in content}} + + + + + {{/each}} + +
NameDescription
{{query.name}}{{query.description}}
+ +{{render "admin/plugins-explorer-show" selectedItem}} + +{{! results }} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a1eca32..6cbdba0 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -23,8 +23,9 @@ en: explorer: title: "Data Explorer" create: "Create New" + create_placeholder: "Query name..." import: label: "Import" modal: "Import A Query" export: "Export" - + run: "Run Query" diff --git a/plugin.rb b/plugin.rb index 5fa0c72..48332a8 100644 --- a/plugin.rb +++ b/plugin.rb @@ -75,9 +75,7 @@ after_initialize do query_args = query.defaults.merge(params) - time_start, time_end = nil - explain = nil - err = nil + time_start, time_end, explain, err, result = nil begin ActiveRecord::Base.connection.transaction do # Setting transaction to read only prevents shoot-in-foot actions like SELECT FOR UPDATE @@ -87,7 +85,7 @@ after_initialize do /* DataExplorer Query Query: /admin/plugins/explorer/#{query.id} -Started by: #{current_user} +Started by: #{opts[:current_user]} */ WITH query AS ( @@ -143,7 +141,7 @@ SQL def self.alloc_id DistributedMutex.synchronize('data-explorer_query-id') do max_id = DataExplorer.pstore_get("q:_id") - max_id = 0 unless max_id + max_id = 1 unless max_id DataExplorer.pstore_set("q:_id", max_id + 1) max_id end @@ -185,7 +183,7 @@ SQL end def save - unless @id + unless @id && @id > 0 @id = self.class.alloc_id end DataExplorer.pstore_set "q:#{id}", to_hash @@ -195,9 +193,15 @@ SQL DataExplorer.pstore_delete "q:#{id}" end + def read_attribute_for_serialization(attr) + self.send(attr) + end + def self.all - PluginStoreRow.where(plugin_name: DataExplorer.plugin_name).where("key LIKE 'q:%'").map do |psr| - next if psr.key == "q:_id" + PluginStoreRow.where(plugin_name: DataExplorer.plugin_name) + .where("key LIKE 'q:%'") + .where("key != 'q:_id'") + .map do |psr| DataExplorer::Query.from_hash PluginStore.cast_value(psr.type_name, psr.value) end end @@ -265,7 +269,7 @@ SQL def run query = DataExplorer::Query.find(params[:id].to_i) query_params = MultiJson.load(params[:params]) - opts = {} + opts = {current_user: current_user.username} opts[:explain] = true if params[:explain] result = DataExplorer.run_query(query, query_params, opts) @@ -293,7 +297,7 @@ SQL success: true, errors: [], params: query_params, - duration: result[:duration_nanos].to_f * 1_000_000, + duration: (result[:duration_nanos].to_f / 1_000_000).round(1), columns: cols, } json[:explain] = result[:explain] if opts[:explain]