mirror of
https://github.com/discourse/discourse-data-explorer.git
synced 2025-03-09 13:24:53 +00:00
More work on interface, fixes for backend
This commit is contained in:
parent
01b38207d9
commit
2c71bc11aa
@ -1,3 +1,11 @@
|
|||||||
import buildPluginAdapter from 'discourse/adapters/build-plugin';
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
|
||||||
|
|
||||||
});
|
|
@ -22,7 +22,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||||||
const object = JSON.parse(this.get('queryFile')).query;
|
const object = JSON.parse(this.get('queryFile')).query;
|
||||||
|
|
||||||
// Slight fixup before creating object
|
// Slight fixup before creating object
|
||||||
delete object.id;
|
object.id = 0; // 0 means no Id yet
|
||||||
|
|
||||||
this.set('loading', true);
|
this.set('loading', true);
|
||||||
this.store.createRecord('query', object).save().then(function(query) {
|
this.store.createRecord('query', object).save().then(function(query) {
|
||||||
|
15
assets/javascripts/discourse/models/query.js.es6
Normal file
15
assets/javascripts/discourse/models/query.js.es6
Normal 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;
|
@ -1,22 +1,9 @@
|
|||||||
import showModal from 'discourse/lib/show-modal';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
controllerName: 'admin-plugins-explorer',
|
controllerName: 'admin-plugins-explorer',
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
return this.store.findAll('query');
|
return this.store.findAll('query');
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
create() {
|
|
||||||
|
|
||||||
},
|
|
||||||
importQuery() {
|
|
||||||
showModal('import-query');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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}}
|
@ -1,8 +1,23 @@
|
|||||||
|
{{text-field value=newQueryName placeholderKey="explorer.create_placeholder"}}
|
||||||
{{d-button action="create" label="explorer.create" icon="plus"}}
|
{{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}}
|
<h3>Queries</h3>
|
||||||
<div class="row">
|
<table class="query-list">
|
||||||
{{query.name}}
|
<thead>
|
||||||
</div>
|
<th class="q-name">Name</th>
|
||||||
{{/each}}
|
<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 }}
|
||||||
|
@ -23,8 +23,9 @@ en:
|
|||||||
explorer:
|
explorer:
|
||||||
title: "Data Explorer"
|
title: "Data Explorer"
|
||||||
create: "Create New"
|
create: "Create New"
|
||||||
|
create_placeholder: "Query name..."
|
||||||
import:
|
import:
|
||||||
label: "Import"
|
label: "Import"
|
||||||
modal: "Import A Query"
|
modal: "Import A Query"
|
||||||
export: "Export"
|
export: "Export"
|
||||||
|
run: "Run Query"
|
||||||
|
24
plugin.rb
24
plugin.rb
@ -75,9 +75,7 @@ after_initialize do
|
|||||||
|
|
||||||
query_args = query.defaults.merge(params)
|
query_args = query.defaults.merge(params)
|
||||||
|
|
||||||
time_start, time_end = nil
|
time_start, time_end, explain, err, result = nil
|
||||||
explain = nil
|
|
||||||
err = nil
|
|
||||||
begin
|
begin
|
||||||
ActiveRecord::Base.connection.transaction do
|
ActiveRecord::Base.connection.transaction do
|
||||||
# Setting transaction to read only prevents shoot-in-foot actions like SELECT FOR UPDATE
|
# Setting transaction to read only prevents shoot-in-foot actions like SELECT FOR UPDATE
|
||||||
@ -87,7 +85,7 @@ after_initialize do
|
|||||||
/*
|
/*
|
||||||
DataExplorer Query
|
DataExplorer Query
|
||||||
Query: /admin/plugins/explorer/#{query.id}
|
Query: /admin/plugins/explorer/#{query.id}
|
||||||
Started by: #{current_user}
|
Started by: #{opts[:current_user]}
|
||||||
*/
|
*/
|
||||||
WITH query AS (
|
WITH query AS (
|
||||||
|
|
||||||
@ -143,7 +141,7 @@ SQL
|
|||||||
def self.alloc_id
|
def self.alloc_id
|
||||||
DistributedMutex.synchronize('data-explorer_query-id') do
|
DistributedMutex.synchronize('data-explorer_query-id') do
|
||||||
max_id = DataExplorer.pstore_get("q:_id")
|
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)
|
DataExplorer.pstore_set("q:_id", max_id + 1)
|
||||||
max_id
|
max_id
|
||||||
end
|
end
|
||||||
@ -185,7 +183,7 @@ SQL
|
|||||||
end
|
end
|
||||||
|
|
||||||
def save
|
def save
|
||||||
unless @id
|
unless @id && @id > 0
|
||||||
@id = self.class.alloc_id
|
@id = self.class.alloc_id
|
||||||
end
|
end
|
||||||
DataExplorer.pstore_set "q:#{id}", to_hash
|
DataExplorer.pstore_set "q:#{id}", to_hash
|
||||||
@ -195,9 +193,15 @@ SQL
|
|||||||
DataExplorer.pstore_delete "q:#{id}"
|
DataExplorer.pstore_delete "q:#{id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read_attribute_for_serialization(attr)
|
||||||
|
self.send(attr)
|
||||||
|
end
|
||||||
|
|
||||||
def self.all
|
def self.all
|
||||||
PluginStoreRow.where(plugin_name: DataExplorer.plugin_name).where("key LIKE 'q:%'").map do |psr|
|
PluginStoreRow.where(plugin_name: DataExplorer.plugin_name)
|
||||||
next if psr.key == "q:_id"
|
.where("key LIKE 'q:%'")
|
||||||
|
.where("key != 'q:_id'")
|
||||||
|
.map do |psr|
|
||||||
DataExplorer::Query.from_hash PluginStore.cast_value(psr.type_name, psr.value)
|
DataExplorer::Query.from_hash PluginStore.cast_value(psr.type_name, psr.value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -265,7 +269,7 @@ SQL
|
|||||||
def run
|
def run
|
||||||
query = DataExplorer::Query.find(params[:id].to_i)
|
query = DataExplorer::Query.find(params[:id].to_i)
|
||||||
query_params = MultiJson.load(params[:params])
|
query_params = MultiJson.load(params[:params])
|
||||||
opts = {}
|
opts = {current_user: current_user.username}
|
||||||
opts[:explain] = true if params[:explain]
|
opts[:explain] = true if params[:explain]
|
||||||
result = DataExplorer.run_query(query, query_params, opts)
|
result = DataExplorer.run_query(query, query_params, opts)
|
||||||
|
|
||||||
@ -293,7 +297,7 @@ SQL
|
|||||||
success: true,
|
success: true,
|
||||||
errors: [],
|
errors: [],
|
||||||
params: query_params,
|
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,
|
columns: cols,
|
||||||
}
|
}
|
||||||
json[:explain] = result[:explain] if opts[:explain]
|
json[:explain] = result[:explain] if opts[:explain]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user