devexpress-reporting
Version:
DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.
346 lines (345 loc) • 16.8 kB
JavaScript
/**
* DevExpress HTML/JS Reporting (designer\internal\errorPanel\_errorPanelViewModel.js)
* Version: 24.2.6
* Build date: Mar 18, 2025
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* License: https://www.devexpress.com/Support/EULAs/universal.xml
*/
import { convertFromCssPixelUnits, formatUnicorn, getParentContainer } from '@devexpress/analytics-core/analytics-internal';
import { Disposable, getLocalization, _LatestChangeSet } from '@devexpress/analytics-core/analytics-utils';
import DataSource from 'devextreme/data/data_source';
import ButtonGroup from 'devextreme/ui/button_group';
import DataGrid from 'devextreme/ui/data_grid';
import * as ko from 'knockout';
import { BandSurface } from '../../bands/xrBand';
import { XRCrossBandSurface } from '../../controls/xrCrossband';
import { ErrorSource, ErrorType } from './_types';
export class ErrorPanelViewModel extends Disposable {
static get allErrorSources() {
return Object.keys(ErrorSource).filter(key => isNaN(parseFloat(key)));
}
static get allErrorTypes() {
return Object.keys(ErrorType).filter(key => isNaN(parseFloat(key)));
}
_createMessage(count, localizationFormat) {
const formats = localizationFormat.split('|');
if (count === 1)
return formatUnicorn(formats[0], count);
if (count === 0 && formats[2]) {
return formatUnicorn(formats[2], count);
}
return formatUnicorn(formats[1], count);
}
_createAvailableSourcesArray() {
const dataSource = [];
if (this._initOptions?.showReportCreationErrorSource)
dataSource.push({ value: ErrorSource.ReportCreation, displayValue: getLocalization('Report Creation', 'DevExpress.XtraReports.Diagnostics.ErrorSource.Creation') });
if (this._initOptions?.showReportLayoutErrorSource)
dataSource.push({ value: ErrorSource.ReportLayout, displayValue: getLocalization('Report Layout', 'DevExpress.XtraReports.Diagnostics.ErrorSource.Layout') });
if (this._initOptions?.showReportScriptsErrorSource)
dataSource.push({ value: ErrorSource.ReportScripts, displayValue: getLocalization('Report Scripts', 'DevExpress.XtraReports.Diagnostics.ErrorSource.Scripts') });
if (this._initOptions?.showReportExportErrorSource)
dataSource.push({ value: ErrorSource.ReportExport, displayValue: getLocalization('Report Export', 'DevExpress.XtraReports.Diagnostics.ErrorSource.Export') });
return dataSource;
}
_expandParentBands(root) {
while (root) {
const surface = root.surface;
if (surface instanceof BandSurface) {
surface.collapsed(false);
}
else if (surface instanceof XRCrossBandSurface) {
const rect = surface['_unitAbsoluteRect'];
const expandedBands = [];
surface.parent.getChildrenCollection()().forEach(band => {
if (surface.isThereIntersection(rect, band.absoluteRect())) {
band.collapsed(false);
expandedBands.push(band);
}
});
const expandChildBands = (bands) => {
bands && bands.forEach(band => {
band.collapsed(false);
expandChildBands(band.bandsHolder.bands());
});
};
expandChildBands(expandedBands);
return;
}
root = root.parentModel();
}
}
clear() {
this._providers = [];
this._subscriptions.forEach(x => x.dispose());
this._subscriptions = [];
this._errorList([]);
}
navigateToItem(name) {
this._onClick && this._onClick();
const control = this._controlsHelper.getControlByName(name);
if (!control)
return;
if (control['surface']) {
this._expandParentBands(control);
this._selection.focused(control['surface']);
this._controlScrollingTool.scrollToControl(control['surface']);
}
else {
this._editableObject(control);
}
}
getNotificationTemplate() {
return this._filteredErrorList().length > 0 ? 'dxrd-svg-errorPanel-notification' : 'dxrd-svg-errorPanel-notification_empty';
}
getTitleMessage() {
return [this._errorMessage(), this._warningMessage(), this._informationMessage()].join('\n');
}
assignErrors() {
const errors = this._errorList();
errors.splice(0);
for (let i = 0; i < this._providers.length; i++) {
this._providers[i].errors().forEach(x => {
x.link = 'https://docs.devexpress.com/XtraReports/403060#' + x.code.toLowerCase();
x.showLink = this._initOptions?.enableErrorCodeLinks;
});
errors.push(...this._providers[i].errors());
}
this._errorList.valueHasMutated();
}
subscribeProvider(provider) {
this._providers.push(provider);
this._subscriptions.push(provider.errors.subscribe((errors) => {
this.assignErrors();
}));
this.assignErrors();
}
collectErrors() {
const undo = this._getUndoEngine();
const latestChanges = undo && undo.getCurrentChangeSet();
if (!undo || !latestChanges.equal(this._latestChangeSet())) {
this._latestChangeSet(latestChanges);
for (let i = 0; i < this._providers.length; i++) {
this._providers[i].collectErrors();
}
}
}
toggleCollapsed() {
if (this.collapsed())
this.collectErrors();
this.collapsed(!this.collapsed());
}
createDataGridOptions(undoEngine) {
const ds = ko.observable(new DataSource(this._errorList()));
this._disposables.push(this._errorList.subscribe((newVal) => {
ds().dispose();
ds(new DataSource(this._errorList()));
}));
this._suppressedErrorCodes(this._initOptions.suppressedErrorCodes || []);
this._dataGridOptions = {
dataSource: ds,
showColumnLines: false,
showRowLines: true,
showBorders: false,
headerFilter: {
visible: true
},
filterValue: this._filterValue,
noDataText: getLocalization('No errors', 'ASPxReportsStringId.ReportDesigner_ErrorPanel_NoErrors'),
columns: [{
caption: ' ',
width: '30px',
dataField: 'errorType',
alignment: 'left',
allowHeaderFiltering: false,
cellTemplate: 'dxrd-errorType-column',
dataType: 'number'
}, {
dataField: 'code',
caption: getLocalization('Code', 'PreviewStringId.ReportDesignAnalyzer_GridColumn_Code'),
cellTemplate: 'dxrd-code-column',
filterType: 'exclude',
filterValues: this._suppressedErrorCodes(),
dataType: 'string'
}, {
dataField: 'errorSource',
visible: false,
dataType: 'number'
}, {
dataField: 'description',
visible: false,
dataType: 'string'
},
{
dataField: 'message',
allowFiltering: false,
caption: getLocalization('Description', 'PreviewStringId.ReportDesignAnalyzer_GridColumn_Description'),
dataType: 'string'
},
{
dataField: 'controlName',
allowFiltering: false,
caption: getLocalization('Source', 'PreviewStringId.ReportDesignAnalyzer_GridColumn_Source'),
cellTemplate: 'dxrd-source-column',
dataType: 'string'
}],
searchPanel: {
visible: true
},
masterDetail: {
enabled: true,
template: 'detail'
},
onOptionChanged: (e) => {
if (/columns\[[0-9]+\].filterValues/i.test(e.fullName)) {
this._suppressedErrorCodes(e.value || []);
}
},
toolbar: {
items: [
{
template: 'dxrd-error-source-filter',
data: {
value: this._errorSource,
dataSource: this._createAvailableSourcesArray(),
getContainer: getParentContainer
},
location: 'before'
}, {
template: 'dxrd-error-type-filter',
data: {
selectedItemKeys: this._choosenTypes,
items: [
{ template: 'dxrd-error-type-filter-item', text: () => this._errorMessage(), icon: ErrorType.Error },
{ template: 'dxrd-error-type-filter-item', text: () => this._warningMessage(), icon: ErrorType.Warning },
{ template: 'dxrd-error-type-filter-item', text: () => this._informationMessage(), icon: ErrorType.Information }
], keyExpr: 'icon', selectionMode: 'multiple', stylingMode: 'outlined'
},
location: 'before'
}, {
widget: 'dxButtonWithTemplate',
cssClass: 'dxrd-collect-errors-button',
options: {
icon: 'dxrd-svg-errorPanel-collectErrors',
text: getLocalization('Collect Errors', 'ASPxReportsStringId.ReportDesigner_Analyzer_CollectErrors'),
onClick: () => this.collectErrors(),
disabled: this._collectErrorButtonDisabled
},
location: 'before'
}, 'searchPanel'
]
}
};
}
_initDefaultFilter() {
if (this._initOptions?.enableReportCreationErrorSource && this._initOptions?.showReportCreationErrorSource)
this._errorSource.push(ErrorSource.ReportCreation);
if (this._initOptions?.enableReportLayoutErrorSource && this._initOptions?.showReportLayoutErrorSource)
this._errorSource.push(ErrorSource.ReportLayout);
if (this._initOptions?.enableReportScriptsErrorSource && this._initOptions?.showReportScriptsErrorSource)
this._errorSource.push(ErrorSource.ReportScripts);
if (this._initOptions?.enableReportExportErrorSource && this._initOptions?.showReportExportErrorSource)
this._errorSource.push(ErrorSource.ReportExport);
if (this._initOptions?.showErrors)
this._choosenTypes.push(ErrorType.Error);
if (this._initOptions?.showWarnings)
this._choosenTypes.push(ErrorType.Warning);
if (this._initOptions?.showInformation)
this._choosenTypes.push(ErrorType.Information);
}
_assignFilter() {
const filter = [];
const uncheckedTypes = ErrorPanelViewModel.allErrorTypes.map(x => ErrorType[x]).filter(x => this._choosenTypes().indexOf(x) === -1);
const uncheckedSources = ErrorPanelViewModel.allErrorSources.map(x => ErrorSource[x]).filter(x => this._errorSource().indexOf(x) === -1);
if (uncheckedTypes.length) {
filter.push(['errorType', 'noneof', uncheckedTypes]);
}
if (uncheckedSources.length) {
filter.push(['errorSource', 'noneof', uncheckedSources]);
}
this._filterValue(filter.reduce((res, val) => {
if (!res.length)
res.push(val);
else
res.push('and', val);
return res;
}, []));
}
getIconTemplateName(errorType) {
return 'dxrd-svg-errorPanel-' + ErrorType[errorType].toLowerCase();
}
constructor(options) {
super();
this._offset = 20;
this._height = ko.observable(210);
this._errorSource = ko.observableArray([]);
this._choosenTypes = ko.observableArray([]);
this._filterValue = ko.observable();
this._getUndoEngine = null;
this._onClick = () => void 0;
this._latestChangeSet = ko.observable(_LatestChangeSet.Empty());
this._openErrorPanelIconHeight = 42;
this.collapsed = ko.observable(true);
this.position = ko.observable(null);
this._suppressedErrorCodes = ko.observableArray();
this._errorList = ko.observableArray([]);
this._providers = [];
this._subscriptions = [];
this.panelTitle = getLocalization('Report Design Analyzer', 'ReportStringId.UD_Title_ErrorList');
this._initOptions = options || {};
this._editableObject = options.editableObject;
this._resizableOptions = {
starting: () => void (0),
handles: 'n',
start: (e, element) => {
},
stop: () => { },
resize: (e, element) => {
const originalHeight = convertFromCssPixelUnits(element.dataset.originalHeight);
const sizeDiff = e.pageY - convertFromCssPixelUnits(element.dataset.originalTopMousePosition);
this._height(originalHeight - sizeDiff);
},
disabled: this.collapsed,
zoom: 1,
minimumHeight: ko.computed(() => this.collapsed() ? this._openErrorPanelIconHeight : 210),
maxHeight: 420
};
this._getUndoEngine = () => options.undoEngine && options.undoEngine();
this._onClick = options.onClick;
this._disposables.push(this._resizableOptions.minimumHeight);
this._disposables.push({
dispose: () => {
this._getUndoEngine = null;
this._latestChangeSet(_LatestChangeSet.Empty());
}
});
DataGrid.length;
ButtonGroup.length;
if (options.position) {
this._disposables.push(this._position = ko.computed(() => {
const left = this.collapsed() ? 'auto' : (options.position.left() + this._offset);
const right = options.position.right() + this._offset;
return {
left: options.rtl ? right : left,
right: options.rtl ? left : right,
height: (!this.collapsed() ? this._height() : 42),
};
}));
}
this._disposables.push(this._collectErrorButtonDisabled = ko.computed(() => {
return options.undoEngine && options.undoEngine() && options.undoEngine().getCurrentChangeSet().equal(this._latestChangeSet());
}));
this._selection = options.selection;
this._controlsHelper = options.controlsHelper;
this._controlScrollingTool = options.controlScrollingTool;
this.createDataGridOptions(options.undoEngine);
this._initDefaultFilter();
this._assignFilter();
this._disposables.push(this._errorMessage, this._warningMessage, this._informationMessage);
this._disposables.push(...([this._errorSource, this._choosenTypes].map(x => x.subscribe(() => this._assignFilter(), undefined, undefined))));
this._disposables.push(this._filteredErrorList = ko.computed(() => this._errorList().filter(x => {
return this._errorSource().indexOf(x.errorSource) !== -1 &&
(this._suppressedErrorCodes() || []).indexOf(x.code) === -1;
})), this._errorMessage = ko.computed(() => this._createMessage(this._filteredErrorList().filter(x => x.errorType == ErrorType.Error).length, getLocalization('{0} Error|{0} Errors', 'PreviewStringId.ReportDesignAnalyzer_Error'))), this._warningMessage = ko.computed(() => this._createMessage(this._filteredErrorList().filter(x => x.errorType == ErrorType.Warning).length, getLocalization('{0} Warning|{0} Warnings', 'PreviewStringId.ReportDesignAnalyzer_Warning'))), this._informationMessage = ko.computed(() => this._createMessage(this._filteredErrorList().filter(x => x.errorType == ErrorType.Information).length, getLocalization('{0} Message|{0} Messages', 'PreviewStringId.ReportDesignAnalyzer_Message'))));
}
}