More work on interface, fixes for backend

This commit is contained in:
Kane York 2015-06-25 14:53:03 -07:00
parent 01b38207d9
commit 2c71bc11aa
10 changed files with 108 additions and 38 deletions

View File

@ -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);
});
}
});

View File

@ -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);
});
}
}
});

View File

@ -1,5 +0,0 @@
export default Ember.ArrayController.extend({
});

View File

@ -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) {

View File

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

View File

@ -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');
}
}
});

View File

@ -0,0 +1,6 @@
{{#if model}}
<h2>{{model.name}}</h2>
<div>{{model.description}}</div>
{{textarea value=model.sql}}
{{d-button action="run" label="explorer.run"}}
{{/if}}

View File

@ -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}}
<div class="row">
{{query.name}}
</div>
{{/each}}
<h3>Queries</h3>
<table class="query-list">
<thead>
<th class="q-name">Name</th>
<th class="q-desc">Description</th>
</thead>
<tbody>
{{#each query in content}}
<tr {{action "selectItem" query}}>
<td class="q-name">{{query.name}}</td>
<td class="q-desc">{{query.description}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{render "admin/plugins-explorer-show" selectedItem}}
{{! results }}

View File

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

View File

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