Files
raven-client/ayanova/src/views/ay-report-edit.vue
2020-09-09 13:46:43 +00:00

997 lines
30 KiB
Vue

<template>
<div v-resize="onResize">
<!-- {{ formState }} -->
<v-row v-show="formState.ready">
<gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
<v-col cols="12" class="d-sm-none accent--text">
<h4>{{ $ay.t("ReportEditorMobileWarning") }}</h4>
</v-col>
<v-col cols="12" class="py-2">
<v-btn-toggle
v-model="activeTab"
tile
color="deep-purple accent-3"
group
@change="onViewChange"
mandatory
>
<v-btn value="properties">
{{ $ay.t("ReportEditorProperties") }}
</v-btn>
<v-btn value="template">
{{ $ay.t("ReportTemplate") }}
</v-btn>
<v-btn value="style">
CSS
</v-btn>
<v-btn value="jsPrerender">
Prepare
</v-btn>
<v-btn value="jsHelpers">
Helpers
</v-btn>
<v-btn value="rawData" v-if="reportData != null">
{{ $ay.t("ReportEditorData") }}
</v-btn>
</v-btn-toggle>
</v-col>
<v-col cols="12" v-show="view == 'edit'">
<div id="editContainer"></div>
</v-col>
<v-col cols="12" v-show="view == 'properties'">
<v-form ref="form">
<v-row>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-text-field
v-model="obj.name"
:readonly="formState.readOnly"
:disabled="formState.readOnly"
:clearable="!formState.readOnly"
@click:clear="fieldValueChanged('name')"
:counter="255"
:label="$ay.t('ReportName')"
:rules="[
form().max255(this, 'name'),
form().required(this, 'name')
]"
:error-messages="form().serverErrors(this, 'name')"
ref="name"
:data-cy="!!$ay.dev ? 'name' : false"
@input="fieldValueChanged('name')"
></v-text-field>
</v-col>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-checkbox
v-model="obj.active"
:readonly="formState.readOnly"
:disabled="formState.readOnly"
:label="$ay.t('Active')"
ref="active"
:data-cy="!!$ay.dev ? 'active' : false"
:error-messages="form().serverErrors(this, 'active')"
@change="fieldValueChanged('active')"
></v-checkbox>
</v-col>
<v-col cols="12" sm="6" lg="4" xl="3">
<gz-role-picker
:label="$ay.t('AuthorizationRoles')"
v-model="obj.roles"
:readonly="formState.readOnly"
:disabled="formState.readOnly"
ref="roles"
testId="roles"
:error-messages="form().serverErrors(this, 'roles')"
@input="fieldValueChanged('roles')"
limitSelectionTo="inside"
></gz-role-picker>
</v-col>
<v-col cols="12">
<v-textarea
v-model="obj.notes"
:readonly="formState.readOnly"
:disabled="formState.readOnly"
:label="$ay.t('ReportNotes')"
:error-messages="form().serverErrors(this, 'notes')"
ref="notes"
:data-cy="!!$ay.dev ? 'notes' : false"
@input="fieldValueChanged('notes')"
auto-grow
:clearable="!formState.readOnly"
></v-textarea>
</v-col>
</v-row>
</v-form>
</v-col>
</v-row>
</div>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
import * as monaco from "monaco-editor";
//jsreport demo
//https://playground.jsreport.net/w/admin/hBfqC7af
//jsreport text editor source
//https://github.com/jsreport/jsreport-studio/blob/master/src/components/Editor/TextEditor.js
//Monaco editor info page with links
//https://microsoft.github.io/monaco-editor/
//vue-monaco component source
//https://github.com/egoist/vue-monaco/blob/master/src/MonacoEditor.js
/*TODO:
"tab" button color doesn't follow pre-defined colors, use highlight instead
also make the data tab button grayer looking so it's clearer that it's different than the rest
An error when direct rendering brings UI down unlike during render and error when in report designer, fix it
complete docs as much as needed for now then...
Add sanitize html for Marked markdown helper as in Wiki control
Is the report list filtered by roles? It should not present reports that a user is not permitted to use by role.
When in report designer it would be useful to show the html generated by the renderer as a diagnostic assistant
Also the script that will be executed minus the hb and marked etc if possible
INITIAL SAMPLE REPORTS
Make up initial sample reports for widget that show off the basics including logo etc
make them auto generate (import from files?) with sample data in seeder
Default example working template with api methods being called generated automatically
Example with currency formatting and date/time formatting etc included automatically.
Use same libs as at client with built in helpers using client meta data
Since reports will only ever be rendered on Client demand can stick with that system for now and replicate at headless chrome that same process in hb helpers
docs
document basics
handlebars, links to hb etc
built in helpers sb documented
build release for joyce to play with and give feedback
*/
const FORM_KEY = "ay-report-edit";
let JUST_DELETED = false;
let editor = null;
export default {
async created() {
let vm = this;
try {
await initForm(vm);
vm.rights = window.$gz.role.getRights(window.$gz.type.Report);
vm.formState.readOnly = !vm.rights.change;
window.$gz.eventBus.$on("menu-click", clickHandler);
//route params MUST have source data
// if (!vm.$route.params.reportDataOptions) {
// throw "ay-report-edit::created - missing reportDataOptions route parameter";
// }
//id 0 means create a new record don't load one
if (vm.$route.params.recordid != 0) {
//is there already an obj from a prior operation?
if (vm.$route.params.obj) {
//yes, no need to fetch it
vm.obj = vm.$route.params.obj;
window.$gz.form.setFormState({
vm: vm,
loading: false
});
} else {
await vm.getDataFromApi(vm.$route.params.recordid); //let getdata handle loading
}
} else {
//New record so there *MUST* be an ayType on the route params
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
//---------------
//setup the editor and models
//Created editor models for each type of report element that can be edited
vm.editData.template.model = monaco.editor.createModel(
vm.obj.template,
"html"
);
vm.editData.style.model = monaco.editor.createModel(vm.obj.style, "css");
vm.editData.jsPrerender.model = monaco.editor.createModel(
vm.obj.jsPrerender,
"javascript"
);
if (vm.reportData != null) {
vm.editData.rawData.model = monaco.editor.createModel(
JSON.stringify(vm.reportData, null, "\t"),
"json"
);
}
vm.editData.jsHelpers.model = monaco.editor.createModel(
vm.obj.jsHelpers,
"javascript"
);
//Create the editor itself
editor = monaco.editor.create(document.getElementById("editContainer"), {
model: vm.editData.template.model
});
//save the initial state because we're going to move away from it immediately
vm.editData.template.state = editor.saveViewState();
//change subscription
editor.onDidChangeModelContent(event => {
const editorValue = editor.getValue();
// console.log("editorchange active tab=", vm.activeTab);
// console.log("editorchange, value of editor is", editorValue);
switch (vm.activeTab) {
case "template":
vm.obj.template = editorValue;
break;
case "style":
vm.obj.style = editorValue;
break;
case "jsPrerender":
vm.obj.jsPrerender = editorValue;
break;
case "jsHelpers":
vm.obj.jsHelpers = editorValue;
break;
}
vm.formState.dirty = true;
//trigger normal form processing when edit happens
//without this you can never save after a server error in the script returns
//pretend the name field changed even though it didn't
vm.fieldValueChanged("name");
});
vm.view = "properties";
//---------------
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
generateMenu(vm);
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
vm.formState.ready = true;
}
},
async beforeRouteLeave(to, from, next) {
if (!this.formState.dirty || JUST_DELETED) {
next();
return;
}
if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
next();
} else {
next(false);
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
//TODO: dispose all models and editor
editor && editor.dispose();
},
data() {
return {
reportData: null,
editAreaHeight: 300,
activeTab: "properties",
lastTab: "properties",
view: "edit", //"edit","properties","test"
editData: {
template: {
model: null,
state: null
},
style: {
model: null,
state: null
},
jsPrerender: {
model: null,
state: null
},
jsHelpers: {
model: null,
state: null
},
rawData: {
model: null,
state: null
}
},
obj: {
id: 0,
concurrency: 0,
name: "report",
active: true,
notes: "",
roles: 124927, //all except customers
objectType: 0,
template: `<html>
<body>
{{#each ayReportData}}
<h2>{{ Name }}</h2>
<div>Notes: <span class='example'>{{ Notes }}</span></div>
{{/each}}
</body>
</html>`,
style: `.example {
color: blue;
}`,
jsPrerender: `async function ayPrepareData(reportData){
//this function (if present) is called with the report data
//before the report is rendered
//modify data as required here and return it to change the data before the report renders
//see the help documentation for details
return reportData;
}`,
jsHelpers: `//Register custom Handlebars helpers here to use in your report script
//https://handlebarsjs.com/guide/#custom-helpers
Handlebars.registerHelper('loud', function (aString) {
return aString.toUpperCase()
})`,
renderType: 0
},
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: true,
errorBoxMessage: null,
appError: null,
serverError: {}
},
rights: window.$gz.role.defaultRightsObject(),
ayaType: window.$gz.type.Report
};
},
//WATCHERS
watch: {
formState: {
handler: function(val) {
//,oldval is available here too if necessary
if (this.formState.loading) {
return;
}
//enable / disable save button
if (val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
} else {
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
}
//enable / disable RENDER button if it can be rendered (has data)
if (this.reportData != null) {
if (!val.dirty && val.valid) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":render");
} else {
window.$gz.eventBus.$emit(
"menu-disable-item",
FORM_KEY + ":render"
);
}
}
//enable / disable duplicate / new button
if (!val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit(
"menu-enable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":new");
} else {
window.$gz.eventBus.$emit(
"menu-disable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":new");
}
},
deep: true
}
},
methods: {
//alternate method, one editor with tabs example
//probably should do this way
//https://github.com/Microsoft/monaco-editor/issues/604
//https://github.com/Microsoft/monaco-editor/blob/bad3c34056624dca34ac8be5028ae3454172125c/website/playground/playground.js#L108
//https://github.com/microsoft/monaco-editor-samples/tree/master/browser-esm-webpack-monaco-plugin
//
onViewChange() {
let vm = this;
let currentState = editor.saveViewState();
let currentModel = editor.getModel();
// debugger;
//save edit state before switching
switch (vm.lastTab) {
case "properties":
//no state to save here
break;
case "template":
vm.editData.template.state = currentState;
break;
case "style":
vm.editData.style.state = currentState;
break;
case "jsPrerender":
vm.editData.jsPrerender.state = currentState;
break;
case "jsHelpers":
vm.editData.jsHelpers.state = currentState;
break;
case "rawData":
vm.editData.rawData.state = currentState;
break;
}
vm.lastTab = vm.activeTab;
//set new view stuff
switch (vm.activeTab) {
case "properties":
vm.view = "properties";
return;
break;
case "template":
editor.setModel(vm.editData.template.model);
editor.restoreViewState(vm.editData.template.state);
editor.updateOptions({ readOnly: false });
vm.view = "edit";
break;
case "style":
editor.setModel(vm.editData.style.model);
editor.restoreViewState(vm.editData.style.state);
editor.updateOptions({ readOnly: false });
vm.view = "edit";
break;
case "jsPrerender":
editor.setModel(vm.editData.jsPrerender.model);
editor.restoreViewState(vm.editData.jsPrerender.state);
editor.updateOptions({ readOnly: false });
vm.view = "edit";
break;
case "jsHelpers":
editor.setModel(vm.editData.jsHelpers.model);
editor.restoreViewState(vm.editData.jsHelpers.state);
editor.updateOptions({ readOnly: false });
vm.view = "edit";
break;
case "rawData":
editor.setModel(vm.editData.rawData.model);
editor.restoreViewState(vm.editData.rawData.state);
editor.updateOptions({ readOnly: true });
vm.view = "edit";
break;
}
vm.$nextTick(() => {
editor.layout();
editor.focus();
});
// vm.lastTab = vm.activeTab;
},
onResize() {
this.$nextTick(() => {
//resize related links:
//https://github.com/Microsoft/monaco-editor/issues/28
let el = document.getElementById("editContainer");
el.style = `width:100%;height:${window.innerHeight * 0.77}px`;
if (editor != null) {
editor.layout();
}
});
},
canSave: function() {
return this.formState.valid && this.formState.dirty;
},
canDuplicate: function() {
return this.formState.valid && !this.formState.dirty;
},
ayaTypes: function() {
return window.$gz.type;
},
form() {
return window.$gz.form;
},
fieldValueChanged(ref) {
if (
this.formState.ready &&
!this.formState.loading &&
!this.formState.readOnly
) {
window.$gz.form.fieldValueChanged(this, ref);
}
},
async getDataFromApi(recordId) {
let vm = this;
window.$gz.form.setFormState({
vm: vm,
loading: true
});
if (!recordId) {
throw FORM_KEY + "::getDataFromApi -> Missing recordID!";
}
let url = "report/" + recordId;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.get(url);
if (res.error) {
//Not found?
if (res.error.code == "2010") {
//notify not found error then navigate backwards
window.$gz.eventBus.$emit("notify-error", vm.$ay.t("ErrorAPI2010"));
// navigate backwards
window.$gz._.delay(function() {
vm.$router.go(-1);
}, 2000);
}
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.obj = res.data;
//modify the menu as necessary
generateMenu(vm);
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true,
loading: false
});
}
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async submit() {
//######################
//need to set vm.obj first with model get value of text of each type being edited
//as only properties will be set already on obj, the rest is still as it was upon initial fetch
//unless I code it to always save to obj on each change of view or something but not necessary really
//USE MODEL.getValue() to get the text value of the model being edited
//Models sb already set in vm if they were set or edited previously
let vm = this;
if (vm.canSave == false) {
return;
}
try {
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = "report/"; // + vm.$route.params.recordid;
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url, vm.obj);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Logic for detecting if a post or put: if id then it was a post, if no id then it was a put
if (res.data.id) {
//POST - whole new object returned
vm.obj = res.data;
//Change URL to new record
//NOTE: will not cause a page re-render, almost nothing does unless forced with a KEY property or using router.GO()
this.$router.push({
name: "ay-report-edit",
params: {
recordid: res.data.id,
obj: res.data, // Pass data object to new form
reportDataOptions: vm.$route.params.reportDataOptions
}
});
} else {
//PUT - only concurrency token is returned (**warning, if server changes object other fields then this needs to act more like POST above but is more efficient this way**)
//Handle "put" of an existing record (UPDATE)
vm.obj.concurrency = res.data.concurrency;
}
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async remove() {
let vm = this;
try {
let dialogResult = await window.$gz.dialog.confirmDelete();
if (dialogResult != true) {
return;
}
//do the delete
window.$gz.form.setFormState({
vm: vm,
loading: true
});
//No need to delete a new record, just abandon it...
if (vm.$route.params.recordid == 0) {
//this should not get offered for delete but to be safe and clear just in case:
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
} else {
let url = "report/" + vm.$route.params.recordid;
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.remove(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//workaround to prevent warning about leaving dirty record
//For some reason I couldn't just reset isdirty in formstate
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
}
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async duplicate() {
let vm = this;
if (!vm.canDuplicate || vm.$route.params.recordid == 0) {
return;
}
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = "report/duplicate/" + vm.$route.params.recordid;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Navigate to new record
this.$router.push({
name: "ay-report-edit",
params: {
recordid: res.data.id,
obj: res.data // Pass data object to new form
}
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async render() {
let vm = this;
if (vm.$route.params.recordid == 0) {
return;
}
/*
public class RenderReportParameter
{
public long ReportId { get; set; }
public long[] SelectedRowIds { get; set; }
public string DataListKey { get; set; }
public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList
}
*/
let reportDataOptions = vm.$route.params.reportDataOptions;
if (!reportDataOptions) {
throw "Missing report data: to view report must come here from an object edit form or list so data can be provided for viewing the report";
}
reportDataOptions.ReportId = vm.obj.id;
//Meta data from client for use by report script
reportDataOptions.ClientMeta = window.$gz.api.reportClientMetaData();
// {
// UserName: vm.$store.state.userName,
// Authorization: "Bearer " + window.$gz.store.state.apiToken, //api token for using api methods as current user viewing report
// TimeZoneName: window.$gz.locale.getBrowserTimeZoneName(),
// LanguageName: window.$gz.locale.getBrowserLanguages(),
// Hour12: window.$gz.locale.getHour12(),
// CurrencyName: window.$gz.locale.getCurrencyName(),
// LanguageName: window.$gz.locale.getBrowserFirstLanguage(),
// DefaultLocale: window.$gz.locale
// .getBrowserFirstLanguage()
// .split("-", 1)[0]
// };
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = "report/render";
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url, reportDataOptions);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
let reportUrl = window.$gz.api.reportDownloadUrl(res.data);
//console.log("Report url:", reportUrl);
if (window.open(reportUrl, "Report") == null) {
vm.formState.serverError =
"Problem displaying report in new window. Browser must allow pop-ups to view reports; check your browser setting";
window.$gz.form.setErrorBoxErrors(vm);
}
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
}
}
};
//end of vue object
/////////////////////////////
//
//
async function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "save":
m.vm.submit();
break;
case "delete":
m.vm.remove();
break;
case "new":
m.vm.$router.push({
name: "ay-report-edit",
params: { recordid: 0, new: true }
});
break;
case "duplicate":
m.vm.duplicate();
break;
case "render":
m.vm.render();
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: false,
icon: "fa-drafting-compass",
title: "ReportDesignReport",
helpUrl: "form-ay-report-edit",
formData: {
ayaType: window.$gz.type.Report,
recordId: vm.$route.params.recordid
},
menuItems: []
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Save",
icon: "fa-save",
surface: true,
key: FORM_KEY + ":save",
vm: vm
});
}
if (vm.reportData != null) {
menuOptions.menuItems.push({
title: "Report",
icon: "fa-print",
key: FORM_KEY + ":render",
surface: true,
vm: vm
});
}
if (vm.rights.delete && vm.$route.params.recordid != 0) {
menuOptions.menuItems.push({
title: "Delete",
icon: "fa-trash-alt",
surface: false,
key: FORM_KEY + ":delete",
vm: vm
});
}
// //STUB REPORTS
// //Report not Print, print is a further option
// menuOptions.menuItems.push({
// title: "Report",
// icon: "fa-file-alt",
// key: FORM_KEY + ":report",
// vm: vm
// });
// //get last report selected
// let lastReport = window.$gz.form.getLastReport(FORM_KEY);
// if (lastReport != null) {
// menuOptions.menuItems.push({
// title: lastReport.name,
// icon: "fa-file-alt",
// key: FORM_KEY + ":report:" + lastReport.id,
// vm: vm
// });
// }
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "New",
icon: "fa-plus",
key: FORM_KEY + ":new",
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Duplicate",
icon: "fa-clone",
key: FORM_KEY + ":duplicate",
vm: vm
});
}
//EXPORT
if (vm.$route.params.recordid != 0) {
let href = window.$gz.api.genericDownloadUrl(
"report/export/" + vm.$route.params.recordid
);
menuOptions.menuItems.push({
title: "Export",
icon: "fa-file-download",
href: href,
target: "_blank",
key: FORM_KEY + ":export",
vm: vm
});
}
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await fetchReportData(vm);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations([
"ReportDesignReport",
"ReportName",
"ReportEditorProperties",
"ReportEditorData",
"ReportEditorMobileWarning",
"ReportNotes",
"ReportTemplate",
"AuthorizationRoles"
]);
}
////////////////////
//
async function fetchReportData(vm) {
/* public AyaType ObjectType { get; set; }
public long[] SelectedRowIds { get; set; }
public string DataListKey { get; set; }
public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList
*/
let reportDataOptions = vm.$route.params.reportDataOptions;
if (!reportDataOptions) {
vm.reportData = null;
return;
// throw "ay-report-edit:fetchReportData - route parameter reportDataOptions is missing or empty, unable to init report designer";
}
if (reportDataOptions.ObjectType == null) {
throw "ay-report-edit:fetchReportData - route parameter ObjectType is missing or empty, unable to init report designer";
}
vm.obj.objectType = reportDataOptions.ObjectType;
let res = await window.$gz.api.upsert("report/data", reportDataOptions);
//We never expect there to be no data here
if (!res.hasOwnProperty("data")) {
throw res;
} else {
vm.reportData = res.data;
}
}
</script>