This is a follow-up to d726c4889e.
The previous change missed changing the name of the query object when passing it to QueryResultsWrapper, which resulted in the download links not working properly after a query was run.
This change fixes that bug, and includes an acceptance test to ensure it stays fixed during future work on this plugin.
188 lines
4.6 KiB
JavaScript
188 lines
4.6 KiB
JavaScript
import { tracked } from "@glimmer/tracking";
|
|
import Controller from "@ember/controller";
|
|
import { action } from "@ember/object";
|
|
import { service } from "@ember/service";
|
|
import { Promise } from "rsvp";
|
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
import { bind } from "discourse/lib/decorators";
|
|
import { i18n } from "discourse-i18n";
|
|
|
|
export default class PluginsExplorerController extends Controller {
|
|
@service dialog;
|
|
@service appEvents;
|
|
@service router;
|
|
|
|
@tracked sortByProperty = "last_run_at";
|
|
@tracked sortDescending = true;
|
|
@tracked params;
|
|
@tracked search;
|
|
@tracked newQueryName;
|
|
@tracked showCreate;
|
|
@tracked loading = false;
|
|
|
|
queryParams = ["id"];
|
|
explain = false;
|
|
acceptedImportFileTypes = ["application/json"];
|
|
order = null;
|
|
form = null;
|
|
|
|
get sortedQueries() {
|
|
const sortedQueries = this.model.sortBy(this.sortByProperty);
|
|
return this.sortDescending ? sortedQueries.reverse() : sortedQueries;
|
|
}
|
|
|
|
get parsedParams() {
|
|
return this.params ? JSON.parse(this.params) : null;
|
|
}
|
|
|
|
get filteredContent() {
|
|
const regexp = new RegExp(this.search, "i");
|
|
return this.sortedQueries.filter(
|
|
(result) => regexp.test(result.name) || regexp.test(result.description)
|
|
);
|
|
}
|
|
|
|
get createDisabled() {
|
|
return (this.newQueryName || "").trim().length === 0;
|
|
}
|
|
|
|
addCreatedRecord(record) {
|
|
this.model.pushObject(record);
|
|
this.router.transitionTo(
|
|
"adminPlugins.explorer.queries.details",
|
|
record.id
|
|
);
|
|
}
|
|
|
|
async _importQuery(file) {
|
|
const json = await this._readFileAsTextAsync(file);
|
|
const query = this._parseQuery(json);
|
|
const record = this.store.createRecord("query", query);
|
|
const response = await record.save();
|
|
return response.target;
|
|
}
|
|
|
|
_parseQuery(json) {
|
|
const parsed = JSON.parse(json);
|
|
const query = parsed.query;
|
|
if (!query || !query.sql) {
|
|
throw new TypeError();
|
|
}
|
|
query.id = 0; // 0 means no Id yet
|
|
return query;
|
|
}
|
|
|
|
_readFileAsTextAsync(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
resolve(reader.result);
|
|
};
|
|
reader.onerror = reject;
|
|
|
|
reader.readAsText(file);
|
|
});
|
|
}
|
|
|
|
@bind
|
|
dragMove(e) {
|
|
if (!e.movementY && !e.movementX) {
|
|
return;
|
|
}
|
|
|
|
const editPane = document.querySelector(".query-editor");
|
|
const target = editPane.querySelector(".panels-flex");
|
|
const grippie = editPane.querySelector(".grippie");
|
|
|
|
// we need to get the initial height / width of edit pane
|
|
// before we manipulate the size
|
|
if (!this.initialPaneWidth && !this.originalPaneHeight) {
|
|
this.originalPaneWidth = target.clientWidth;
|
|
this.originalPaneHeight = target.clientHeight;
|
|
}
|
|
|
|
const newHeight = Math.max(
|
|
this.originalPaneHeight,
|
|
target.clientHeight + e.movementY
|
|
);
|
|
const newWidth = Math.max(
|
|
this.originalPaneWidth,
|
|
target.clientWidth + e.movementX
|
|
);
|
|
|
|
target.style.height = newHeight + "px";
|
|
target.style.width = newWidth + "px";
|
|
grippie.style.width = newWidth + "px";
|
|
this.appEvents.trigger("ace:resize");
|
|
}
|
|
|
|
@bind
|
|
scrollTop() {
|
|
window.scrollTo(0, 0);
|
|
}
|
|
|
|
@action
|
|
async import(files) {
|
|
try {
|
|
this.loading = true;
|
|
const file = files[0];
|
|
const record = await this._importQuery(file);
|
|
this.addCreatedRecord(record);
|
|
} catch (e) {
|
|
if (e.jqXHR) {
|
|
popupAjaxError(e);
|
|
} else if (e instanceof SyntaxError) {
|
|
this.dialog.alert(i18n("explorer.import.unparseable_json"));
|
|
} else if (e instanceof TypeError) {
|
|
this.dialog.alert(i18n("explorer.import.wrong_json"));
|
|
} else {
|
|
this.dialog.alert(i18n("errors.desc.unknown"));
|
|
// eslint-disable-next-line no-console
|
|
console.error(e);
|
|
}
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
}
|
|
|
|
@action
|
|
displayCreate() {
|
|
this.showCreate = true;
|
|
}
|
|
|
|
@action
|
|
updateSortProperty(property) {
|
|
if (this.sortByProperty === property) {
|
|
this.sortDescending = !this.sortDescending;
|
|
} else {
|
|
this.sortByProperty = property;
|
|
this.sortDescending = true;
|
|
}
|
|
}
|
|
|
|
@action
|
|
async create() {
|
|
try {
|
|
const name = this.newQueryName.trim();
|
|
this.loading = true;
|
|
this.showCreate = false;
|
|
const result = await this.store.createRecord("query", { name }).save();
|
|
this.addCreatedRecord(result.target);
|
|
} catch (error) {
|
|
popupAjaxError(error);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
}
|
|
|
|
@action
|
|
updateSearch(value) {
|
|
this.search = value;
|
|
}
|
|
|
|
@action
|
|
updateNewQueryName(value) {
|
|
this.newQueryName = value;
|
|
}
|
|
}
|