2023-12-01 16:47:54 +01:00
|
|
|
import { tracked } from "@glimmer/tracking";
|
2022-06-17 15:01:34 +02:00
|
|
|
import Controller from "@ember/controller";
|
2023-12-01 16:47:54 +01:00
|
|
|
import { action } from "@ember/object";
|
2024-11-19 10:20:51 +00:00
|
|
|
import { service } from "@ember/service";
|
2023-12-01 16:47:54 +01:00
|
|
|
import { Promise } from "rsvp";
|
2018-10-10 17:26:23 +05:30
|
|
|
import { ajax } from "discourse/lib/ajax";
|
2023-12-01 16:47:54 +01:00
|
|
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
2025-02-06 16:45:00 +00:00
|
|
|
import { bind } from "discourse/lib/decorators";
|
2023-12-07 11:49:35 -07:00
|
|
|
import QueryHelp from "discourse/plugins/discourse-data-explorer/discourse/components/modal/query-help";
|
2024-08-20 09:42:50 +08:00
|
|
|
import { ParamValidationError } from "discourse/plugins/discourse-data-explorer/discourse/components/param-input-form";
|
2023-12-01 16:47:54 +01:00
|
|
|
import Query from "discourse/plugins/discourse-data-explorer/discourse/models/query";
|
2015-06-25 14:53:03 -07:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
export default class PluginsExplorerController extends Controller {
|
2023-12-07 11:49:35 -07:00
|
|
|
@service modal;
|
2023-01-05 09:27:10 -06:00
|
|
|
@service appEvents;
|
2023-12-01 16:02:52 +00:00
|
|
|
@service router;
|
2015-06-30 10:20:22 -07:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@tracked params;
|
|
|
|
|
@tracked editingName = false;
|
|
|
|
|
@tracked editingQuery = false;
|
|
|
|
|
@tracked loading = false;
|
|
|
|
|
@tracked showResults = false;
|
|
|
|
|
@tracked hideSchema = false;
|
2025-02-10 14:54:01 +11:00
|
|
|
@tracked results = this.model.results;
|
2023-01-05 09:27:10 -06:00
|
|
|
@tracked dirty = false;
|
2015-07-14 10:34:23 -07:00
|
|
|
|
2025-02-10 14:54:01 +11:00
|
|
|
queryParams = ["params"];
|
2023-01-05 09:27:10 -06:00
|
|
|
explain = false;
|
|
|
|
|
order = null;
|
2024-08-20 09:42:50 +08:00
|
|
|
form = null;
|
2015-06-30 10:20:22 -07:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
get saveDisabled() {
|
|
|
|
|
return !this.dirty;
|
|
|
|
|
}
|
2021-08-20 14:26:48 +04:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
get runDisabled() {
|
|
|
|
|
return this.dirty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get parsedParams() {
|
|
|
|
|
return this.params ? JSON.parse(this.params) : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get editDisabled() {
|
2025-02-10 14:54:01 +11:00
|
|
|
return parseInt(this.model.id, 10) < 0 ? true : false;
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
2019-10-16 12:43:10 +02:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
get groupOptions() {
|
|
|
|
|
return this.groups
|
2020-10-07 14:08:07 +10:00
|
|
|
.filter((g) => g.id !== 0)
|
|
|
|
|
.map((g) => {
|
2020-10-19 12:03:03 -07:00
|
|
|
return { id: g.id, name: g.name };
|
2020-10-07 14:08:07 +10:00
|
|
|
});
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
2019-09-11 09:09:41 -05:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@action
|
2024-01-02 12:38:22 -07:00
|
|
|
async save() {
|
|
|
|
|
try {
|
|
|
|
|
this.loading = true;
|
2025-02-10 14:54:01 +11:00
|
|
|
await this.model.save();
|
2019-09-11 10:30:39 -05:00
|
|
|
|
2024-01-02 12:38:22 -07:00
|
|
|
this.dirty = false;
|
|
|
|
|
this.editingName = false;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
popupAjaxError(error);
|
|
|
|
|
throw error;
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
}
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
saveAndRun() {
|
|
|
|
|
this.save().then(() => this.run());
|
|
|
|
|
}
|
2015-07-08 16:46:36 -07:00
|
|
|
|
2021-08-20 14:26:48 +04:00
|
|
|
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;
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
2021-08-20 14:26:48 +04:00
|
|
|
|
|
|
|
|
_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;
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
2021-08-20 14:26:48 +04:00
|
|
|
|
|
|
|
|
_readFileAsTextAsync(file) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
reader.onload = () => {
|
|
|
|
|
resolve(reader.result);
|
|
|
|
|
};
|
|
|
|
|
reader.onerror = reject;
|
|
|
|
|
|
|
|
|
|
reader.readAsText(file);
|
|
|
|
|
});
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
didStartDrag() {}
|
|
|
|
|
|
|
|
|
|
@bind
|
|
|
|
|
didEndDrag() {}
|
2021-08-20 14:26:48 +04:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@action
|
|
|
|
|
updateGroupIds(value) {
|
|
|
|
|
this.dirty = true;
|
2025-02-10 14:54:01 +11:00
|
|
|
this.model.set("group_ids", value);
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
2015-06-25 14:53:03 -07:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@action
|
|
|
|
|
updateHideSchema(value) {
|
|
|
|
|
this.hideSchema = value;
|
|
|
|
|
}
|
2015-06-30 10:37:48 -07:00
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@action
|
|
|
|
|
editName() {
|
|
|
|
|
this.editingName = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
editQuery() {
|
|
|
|
|
this.editingQuery = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
download() {
|
2025-02-10 14:54:01 +11:00
|
|
|
window.open(this.model.downloadUrl, "_blank");
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
goHome() {
|
2025-02-10 14:54:01 +11:00
|
|
|
this.router.transitionTo("adminPlugins.explorer");
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
showHelpModal() {
|
2023-12-07 11:49:35 -07:00
|
|
|
this.modal.show(QueryHelp);
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
resetParams() {
|
2025-02-10 14:54:01 +11:00
|
|
|
this.model.resetParams();
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
2024-01-02 12:38:22 -07:00
|
|
|
async discard() {
|
|
|
|
|
try {
|
|
|
|
|
this.loading = true;
|
2025-02-10 14:54:01 +11:00
|
|
|
const result = await this.store.find("query", this.model.id);
|
|
|
|
|
this.model.setProperties(result.getProperties(Query.updatePropertyNames));
|
|
|
|
|
if (!this.model.group_ids || !Array.isArray(this.model.group_ids)) {
|
|
|
|
|
this.model.set("group_ids", []);
|
2024-01-02 12:38:22 -07:00
|
|
|
}
|
|
|
|
|
this.dirty = false;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
popupAjaxError(error);
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
}
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
2024-01-02 12:38:22 -07:00
|
|
|
async destroyQuery() {
|
|
|
|
|
try {
|
|
|
|
|
this.loading = true;
|
|
|
|
|
this.showResults = false;
|
2025-02-10 14:54:01 +11:00
|
|
|
await this.store.destroyRecord("query", this.model);
|
|
|
|
|
this.model.set("destroyed", true);
|
2024-01-02 12:38:22 -07:00
|
|
|
} catch (error) {
|
|
|
|
|
popupAjaxError(error);
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
}
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
2024-01-02 12:38:22 -07:00
|
|
|
async recover() {
|
|
|
|
|
try {
|
|
|
|
|
this.loading = true;
|
|
|
|
|
this.showResults = true;
|
2025-02-10 14:54:01 +11:00
|
|
|
await this.model.save();
|
|
|
|
|
this.model.set("destroyed", false);
|
2024-01-02 12:38:22 -07:00
|
|
|
} catch (error) {
|
|
|
|
|
popupAjaxError(error);
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
}
|
2023-01-05 09:27:10 -06:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 09:42:50 +08:00
|
|
|
@action
|
|
|
|
|
onRegisterApi(form) {
|
|
|
|
|
this.form = form;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 09:27:10 -06:00
|
|
|
@action
|
|
|
|
|
setDirty() {
|
|
|
|
|
this.dirty = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
exitEdit() {
|
|
|
|
|
this.editingName = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
2024-08-20 09:42:50 +08:00
|
|
|
async run() {
|
|
|
|
|
let params = null;
|
2025-02-10 14:54:01 +11:00
|
|
|
if (this.model.hasParams) {
|
2024-08-20 09:42:50 +08:00
|
|
|
try {
|
|
|
|
|
params = await this.form?.submit();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err instanceof ParamValidationError) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (params == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-05 09:27:10 -06:00
|
|
|
this.setProperties({
|
|
|
|
|
loading: true,
|
|
|
|
|
showResults: false,
|
2024-08-20 09:42:50 +08:00
|
|
|
params: JSON.stringify(params),
|
2023-01-05 09:27:10 -06:00
|
|
|
});
|
|
|
|
|
|
2025-02-10 14:54:01 +11:00
|
|
|
ajax("/admin/plugins/explorer/queries/" + this.model.id + "/run", {
|
2023-01-05 09:27:10 -06:00
|
|
|
type: "POST",
|
|
|
|
|
data: {
|
2024-08-20 09:42:50 +08:00
|
|
|
params: JSON.stringify(params),
|
2023-01-05 09:27:10 -06:00
|
|
|
explain: this.explain,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.then((result) => {
|
|
|
|
|
this.results = result;
|
|
|
|
|
if (!result.success) {
|
|
|
|
|
this.showResults = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.showResults = true;
|
|
|
|
|
})
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
this.showResults = false;
|
|
|
|
|
if (err.jqXHR && err.jqXHR.status === 422 && err.jqXHR.responseJSON) {
|
|
|
|
|
this.results = err.jqXHR.responseJSON;
|
|
|
|
|
} else {
|
|
|
|
|
popupAjaxError(err);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.finally(() => (this.loading = false));
|
|
|
|
|
}
|
|
|
|
|
}
|