@firestitch/report 18.17.1 → 18.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/reports/data/report.data.d.ts +0 -2
- package/app/reports/export/report-export-collector.service.d.ts +6 -0
- package/app/reports/export/report-export.service.d.ts +1 -0
- package/app/reports/export/report-pdf.service.d.ts +5 -0
- package/esm2022/app/reports/data/report.data.mjs +3 -3
- package/esm2022/app/reports/export/report-export-collector.service.mjs +1 -1
- package/esm2022/app/reports/export/report-export.service.mjs +31 -5
- package/esm2022/app/reports/export/report-pdf.service.mjs +212 -80
- package/esm2022/app/reports/export/report-pptx.service.mjs +4 -1
- package/fesm2022/{firestitch-report-echarts-rzMA7zhn.mjs → firestitch-report-echarts-CBoGhanh.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-rzMA7zhn.mjs.map → firestitch-report-echarts-CBoGhanh.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-DRkNBMic.mjs → firestitch-report-firestitch-report-MBuBuGiA.mjs} +250 -89
- package/fesm2022/firestitch-report-firestitch-report-MBuBuGiA.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +1 -1
- package/fesm2022/firestitch-report-firestitch-report-DRkNBMic.mjs.map +0 -1
package/fesm2022/{firestitch-report-echarts-rzMA7zhn.mjs → firestitch-report-echarts-CBoGhanh.mjs}
RENAMED
|
@@ -4,7 +4,7 @@ import * as echarts from 'echarts/core';
|
|
|
4
4
|
export { echarts as default };
|
|
5
5
|
import { LabelLayout } from 'echarts/features';
|
|
6
6
|
import { CanvasRenderer } from 'echarts/renderers';
|
|
7
|
-
import { R as REPORT_CHART_COLORS_CSS, a as REPORT_CHART_FONT_FAMILY, b as REPORT_AXIS_LABEL_FONT_SIZE } from './firestitch-report-firestitch-report-
|
|
7
|
+
import { R as REPORT_CHART_COLORS_CSS, a as REPORT_CHART_FONT_FAMILY, b as REPORT_AXIS_LABEL_FONT_SIZE } from './firestitch-report-firestitch-report-MBuBuGiA.mjs';
|
|
8
8
|
|
|
9
9
|
// Tree-shaken ECharts build for the reports renderer: only the chart types and
|
|
10
10
|
// components the option-builder emits are registered, keeping the lazy chunk
|
|
@@ -63,4 +63,4 @@ echarts.registerTheme('report', {
|
|
|
63
63
|
axisLabel: { color: '#52606d', fontSize: REPORT_AXIS_LABEL_FONT_SIZE },
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
|
-
//# sourceMappingURL=firestitch-report-echarts-
|
|
66
|
+
//# sourceMappingURL=firestitch-report-echarts-CBoGhanh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firestitch-report-echarts-
|
|
1
|
+
{"version":3,"file":"firestitch-report-echarts-CBoGhanh.mjs","sources":["../../src/app/reports/theme/echarts.ts"],"sourcesContent":["// Tree-shaken ECharts build for the reports renderer: only the chart types and\n// components the option-builder emits are registered, keeping the lazy chunk\n// lean. Loaded on demand by ngx-echarts via provideEchartsCore — see\n// REPORT_ECHARTS_PROVIDERS in reports-echarts.provider.ts.\n//\n// The canvas renderer (not SVG) is deliberate: chart.getDataURL() needs it for\n// the high-res images the PPT/PDF exports will use.\n\nimport { BarChart, LineChart, PieChart } from 'echarts/charts';\nimport {\n DatasetComponent,\n GridComponent,\n LegendComponent,\n MarkAreaComponent,\n MarkLineComponent,\n TooltipComponent,\n} from 'echarts/components';\nimport * as echarts from 'echarts/core';\nimport { LabelLayout } from 'echarts/features';\nimport { CanvasRenderer } from 'echarts/renderers';\n\nimport { REPORT_CHART_COLORS_CSS } from './palette';\nimport { REPORT_AXIS_LABEL_FONT_SIZE, REPORT_CHART_FONT_FAMILY } from './typography';\n\necharts.use([\n BarChart,\n LineChart,\n PieChart,\n GridComponent,\n TooltipComponent,\n LegendComponent,\n DatasetComponent,\n // Reference lines and statistic lines (markLine), reference bands\n // (markArea), and the overlap hiding of 'auto' data labels (LabelLayout).\n MarkLineComponent,\n MarkAreaComponent,\n LabelLayout,\n CanvasRenderer,\n]);\n\n// The house theme — the single place report chart \"standards\" live (palette,\n// typography, tooltip styling). Polished defaults now; refined in the polish\n// phase.\necharts.registerTheme('report', {\n color: REPORT_CHART_COLORS_CSS,\n textStyle: {\n fontFamily: REPORT_CHART_FONT_FAMILY,\n },\n title: {\n textStyle: { color: '#1f2933', fontSize: 14, fontWeight: 600 },\n },\n legend: {\n textStyle: { color: '#52606d', fontSize: 11 },\n },\n tooltip: {\n backgroundColor: 'rgba(31, 41, 51, 0.92)',\n borderWidth: 0,\n textStyle: { color: '#fff', fontSize: 12 },\n },\n categoryAxis: {\n axisLine: { lineStyle: { color: '#cbd2d9' } },\n axisTick: { show: false },\n axisLabel: { color: '#52606d', fontSize: REPORT_AXIS_LABEL_FONT_SIZE },\n splitLine: { show: false },\n },\n valueAxis: {\n axisLine: { show: false },\n axisLabel: { color: '#52606d', fontSize: REPORT_AXIS_LABEL_FONT_SIZE },\n splitLine: { lineStyle: { color: '#e4e7eb' } },\n },\n timeAxis: {\n axisLine: { lineStyle: { color: '#cbd2d9' } },\n axisLabel: { color: '#52606d', fontSize: REPORT_AXIS_LABEL_FONT_SIZE },\n },\n});\n\nexport default echarts;\n"],"names":[],"mappings":";;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA,OAAO,CAAC,GAAG,CAAC;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,aAAa;IACb,gBAAgB;IAChB,eAAe;IACf,gBAAgB;;;IAGhB,iBAAiB;IACjB,iBAAiB;IACjB,WAAW;IACX,cAAc;AACf,CAAA,CAAC,CAAC;AAEH;AACA;AACA;AACA,OAAO,CAAC,aAAa,CAAC,QAAQ,EAAE;AAC9B,IAAA,KAAK,EAAE,uBAAuB;AAC9B,IAAA,SAAS,EAAE;AACT,QAAA,UAAU,EAAE,wBAAwB;AACrC,KAAA;AACD,IAAA,KAAK,EAAE;AACL,QAAA,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE;AAC/D,KAAA;AACD,IAAA,MAAM,EAAE;QACN,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE;AAC9C,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,eAAe,EAAE,wBAAwB;AACzC,QAAA,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;AAC3C,KAAA;AACD,IAAA,YAAY,EAAE;QACZ,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;AAC7C,QAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;QACzB,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,2BAA2B,EAAE;AACtE,QAAA,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;AAC3B,KAAA;AACD,IAAA,SAAS,EAAE;AACT,QAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;QACzB,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,2BAA2B,EAAE;QACtE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;AAC/C,KAAA;AACD,IAAA,QAAQ,EAAE;QACR,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;QAC7C,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,2BAA2B,EAAE;AACvE,KAAA;AACF,CAAA,CAAC"}
|
|
@@ -429,14 +429,14 @@ class ReportData {
|
|
|
429
429
|
}
|
|
430
430
|
// Make one column filterable. `level` (component | report) places a new
|
|
431
431
|
// group; `groupId` instead links into an existing group. A select filter's
|
|
432
|
-
// options are derived from the component
|
|
432
|
+
// options are derived from the component's own query.
|
|
433
433
|
addFilter(reportId, componentId, filter, config = {}) {
|
|
434
434
|
return this._api.post(this._path(`${reportId}/components/${componentId}/filters`), filter, {
|
|
435
435
|
key: 'filter',
|
|
436
436
|
...config,
|
|
437
437
|
});
|
|
438
438
|
}
|
|
439
|
-
// Update a filter — any subset of { label,
|
|
439
|
+
// Update a filter — any subset of { label, enabled }.
|
|
440
440
|
updateFilter(reportId, filterId, changes, config = {}) {
|
|
441
441
|
return this._api.put(this._path(`${reportId}/filters/${filterId}`), changes, {
|
|
442
442
|
key: 'filter',
|
|
@@ -15411,7 +15411,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
15411
15411
|
// in the report's format context, as on screen.
|
|
15412
15412
|
async function renderChartImage(component, data, width, height, context, pixelRatio = 3) {
|
|
15413
15413
|
// The same tree-shaken echarts build + 'report' theme the live canvas uses.
|
|
15414
|
-
const echarts = (await import('./firestitch-report-echarts-
|
|
15414
|
+
const echarts = (await import('./firestitch-report-echarts-CBoGhanh.mjs')).default;
|
|
15415
15415
|
const host = document.createElement('div');
|
|
15416
15416
|
host.style.width = `${width}px`;
|
|
15417
15417
|
host.style.height = `${height}px`;
|
|
@@ -15722,6 +15722,18 @@ const NO_BAND_MARGIN = 0.5 * PT;
|
|
|
15722
15722
|
const NO_BANDS = { headerHeight: 0, footerHeight: 0 };
|
|
15723
15723
|
// The last row of a list box whose rows carry on past it.
|
|
15724
15724
|
const CONTINUED_NOTICE = 'Continued on the following pages';
|
|
15725
|
+
// The last row of a list box whose rows have nowhere to go: its heading and
|
|
15726
|
+
// totals row, wrapped tall in narrow columns, leave a continuation page no
|
|
15727
|
+
// room for a row.
|
|
15728
|
+
const NO_ROOM_NOTICE = 'Not enough room for this table — enlarge the tile';
|
|
15729
|
+
// A list's or a table tile's table: its font size and cell padding, points.
|
|
15730
|
+
const TABLE_FONT_SIZE = 8;
|
|
15731
|
+
const TABLE_CELL_PADDING = 3;
|
|
15732
|
+
// What a component's box says when it could not be drawn.
|
|
15733
|
+
const UNDRAWN_NOTE = 'Could not be drawn';
|
|
15734
|
+
// Thrown from autoTable's page hook to stop an on-page table at the first page
|
|
15735
|
+
// it would add (_drawTable).
|
|
15736
|
+
const STRAY_PAGE = new Error('The table ran past its page');
|
|
15725
15737
|
// A text line's height as a multiple of its largest font size — the canvas
|
|
15726
15738
|
// stylesheet's line-height, so a block wraps and stacks the same way.
|
|
15727
15739
|
const TEXT_LINE_HEIGHT = 1.25;
|
|
@@ -15744,7 +15756,14 @@ const GRID_INDENT$1 = 8;
|
|
|
15744
15756
|
// row-height estimate, so it cannot spill past the box. The rows that do not
|
|
15745
15757
|
// fit continue on pages of their own after the report page, under the same
|
|
15746
15758
|
// header/footer and with the same column widths, up to PDF_LIST_ROWS; a
|
|
15747
|
-
// longer result ends in a row pointing to the component's CSV export.
|
|
15759
|
+
// longer result ends in a row pointing to the component's CSV export. A
|
|
15760
|
+
// table whose heading and totals row leave a continuation page no room for a
|
|
15761
|
+
// row stops at its box with a notice instead: autoTable would add pages
|
|
15762
|
+
// without end trying to place it.
|
|
15763
|
+
//
|
|
15764
|
+
// A component that fails to draw is marked in its box and the file goes on
|
|
15765
|
+
// (_guarded); build() hands back the ones that did, as it does the text it
|
|
15766
|
+
// cut.
|
|
15748
15767
|
//
|
|
15749
15768
|
// A text block's tables are drawn by autoTable too, from the line its words
|
|
15750
15769
|
// reach, in the column widths the canvas gives them (ReportTextLayoutService).
|
|
@@ -15766,12 +15785,16 @@ class ReportPdfService {
|
|
|
15766
15785
|
// Each continuation appends its pages at the end of the document, so
|
|
15767
15786
|
// two lists that overflowed on one page follow it back to back.
|
|
15768
15787
|
for (const overflow of overflows) {
|
|
15769
|
-
|
|
15788
|
+
const tokens = this._tokens(context, collectedPage.page, index, pageNumber + 1);
|
|
15789
|
+
await this._guarded(context, overflow.component, tokens.pageName, tokens, false, async () => {
|
|
15790
|
+
pageNumber = await this._renderContinuation(context, collectedPage.page, index, pageNumber, overflow);
|
|
15791
|
+
});
|
|
15770
15792
|
}
|
|
15771
15793
|
}
|
|
15772
15794
|
return {
|
|
15773
15795
|
overflows: [...context.textOverflows.values()],
|
|
15774
15796
|
overflowNote: PDF_OVERFLOW_NOTE,
|
|
15797
|
+
undrawn: [...context.undrawn.values()],
|
|
15775
15798
|
save: () => {
|
|
15776
15799
|
context.doc.save(`${this._slug(collected.report.name)}.pdf`);
|
|
15777
15800
|
},
|
|
@@ -15780,13 +15803,14 @@ class ReportPdfService {
|
|
|
15780
15803
|
async _context(collected) {
|
|
15781
15804
|
const report = collected.report;
|
|
15782
15805
|
const { jsPDF } = await import('jspdf');
|
|
15783
|
-
const autoTable =
|
|
15806
|
+
const { default: autoTable, __createTable: createTable } = await import('jspdf-autotable');
|
|
15784
15807
|
const pageW = report.pageWidth * PT;
|
|
15785
15808
|
const pageH = report.pageHeight * PT;
|
|
15786
15809
|
const orientation = pageW >= pageH ? 'landscape' : 'portrait';
|
|
15787
15810
|
return {
|
|
15788
15811
|
doc: new jsPDF({ orientation, unit: 'pt', format: [pageW, pageH] }),
|
|
15789
15812
|
autoTable,
|
|
15813
|
+
createTable,
|
|
15790
15814
|
jsPDF,
|
|
15791
15815
|
report,
|
|
15792
15816
|
timezone: resolveReportTimezone(report),
|
|
@@ -15798,6 +15822,7 @@ class ReportPdfService {
|
|
|
15798
15822
|
filterFields: collected.filterFields,
|
|
15799
15823
|
masterFilters: layerFilterFields(collected.filterFields, report.filterGroups ?? [], null),
|
|
15800
15824
|
textOverflows: new Map(),
|
|
15825
|
+
undrawn: new Map(),
|
|
15801
15826
|
};
|
|
15802
15827
|
}
|
|
15803
15828
|
// One report page: the header and footer first, under the page's own
|
|
@@ -15810,14 +15835,59 @@ class ReportPdfService {
|
|
|
15810
15835
|
doc.addPage([context.pageW, context.pageH], context.orientation);
|
|
15811
15836
|
await this._renderMaster(context, collectedPage.page, tokens);
|
|
15812
15837
|
for (const item of collectedPage.components) {
|
|
15813
|
-
|
|
15814
|
-
|
|
15838
|
+
await this._guarded(context, item.component, tokens.pageName, pageTokens, true, async () => {
|
|
15839
|
+
if (item.component.type !== 'text') {
|
|
15840
|
+
await this._renderComponent(context, collectedPage.page, item, tokens, overflows);
|
|
15841
|
+
}
|
|
15842
|
+
else if (await this._renderText(context, item.component, pageTokens)) {
|
|
15843
|
+
this._recordOverflow(context, item.component, tokens.pageName, pageTokens);
|
|
15844
|
+
}
|
|
15845
|
+
});
|
|
15846
|
+
}
|
|
15847
|
+
}
|
|
15848
|
+
// Draws one component, or one list's continuation pages, so that whatever
|
|
15849
|
+
// goes wrong stays with it: a draw that throws loses the pages it added, its
|
|
15850
|
+
// box on the page (boxed) is blanked under UNDRAWN_NOTE, and the export's
|
|
15851
|
+
// gate names it under page. One component can then never stop the file.
|
|
15852
|
+
async _guarded(context, component, page, tokens, boxed, draw) {
|
|
15853
|
+
const { doc } = context;
|
|
15854
|
+
const current = doc.getCurrentPageInfo().pageNumber;
|
|
15855
|
+
const pages = doc.getNumberOfPages();
|
|
15856
|
+
try {
|
|
15857
|
+
await draw();
|
|
15858
|
+
}
|
|
15859
|
+
catch (error) {
|
|
15860
|
+
// The file only says the box could not be drawn; the console keeps why.
|
|
15861
|
+
console.error(error);
|
|
15862
|
+
while (doc.getNumberOfPages() > pages) {
|
|
15863
|
+
doc.deletePage(doc.getNumberOfPages());
|
|
15815
15864
|
}
|
|
15816
|
-
|
|
15817
|
-
|
|
15865
|
+
doc.setPage(current);
|
|
15866
|
+
if (boxed) {
|
|
15867
|
+
this._undrawnBox(doc, component);
|
|
15868
|
+
}
|
|
15869
|
+
if (!context.undrawn.has(component.id)) {
|
|
15870
|
+
context.undrawn.set(component.id, {
|
|
15871
|
+
componentId: component.id,
|
|
15872
|
+
page,
|
|
15873
|
+
name: component.type === 'text'
|
|
15874
|
+
? textOverflow(component, page, tokens).snippet
|
|
15875
|
+
: exportTitle(component, tokens),
|
|
15876
|
+
});
|
|
15818
15877
|
}
|
|
15819
15878
|
}
|
|
15820
15879
|
}
|
|
15880
|
+
// A component's box blanked under UNDRAWN_NOTE, over whatever of it was
|
|
15881
|
+
// drawn before it failed.
|
|
15882
|
+
_undrawnBox(doc, component) {
|
|
15883
|
+
const x = component.x * PT;
|
|
15884
|
+
const y = component.y * PT;
|
|
15885
|
+
const w = component.w * PT;
|
|
15886
|
+
const h = component.h * PT;
|
|
15887
|
+
doc.setFillColor('#ffffff');
|
|
15888
|
+
doc.rect(x, y, w, h, 'F');
|
|
15889
|
+
this._boxNote(doc, UNDRAWN_NOTE, x, y, w, h);
|
|
15890
|
+
}
|
|
15821
15891
|
// The header and footer, their value tokens filled with the master's values
|
|
15822
15892
|
// whichever page they sit on: a report page or a continuation page. They
|
|
15823
15893
|
// read no page filter: its token prints the em dash there.
|
|
@@ -15827,9 +15897,11 @@ class ReportPdfService {
|
|
|
15827
15897
|
}
|
|
15828
15898
|
const masterTokens = { ...tokens, values: context.masterValues, filters: context.masterFilters };
|
|
15829
15899
|
for (const component of (context.report.master?.components ?? []).filter(isDrawn)) {
|
|
15830
|
-
|
|
15831
|
-
this.
|
|
15832
|
-
|
|
15900
|
+
await this._guarded(context, component, HEADER_FOOTER_NAME, masterTokens, true, async () => {
|
|
15901
|
+
if (await this._renderText(context, component, masterTokens)) {
|
|
15902
|
+
this._recordOverflow(context, component, HEADER_FOOTER_NAME, masterTokens);
|
|
15903
|
+
}
|
|
15904
|
+
});
|
|
15833
15905
|
}
|
|
15834
15906
|
}
|
|
15835
15907
|
// Lists a text block that was cut, under the page the export's overflow gate
|
|
@@ -15955,7 +16027,8 @@ class ReportPdfService {
|
|
|
15955
16027
|
// wraps them, and the words are drawn into each cell once autoTable has
|
|
15956
16028
|
// drawn its grid lines and fill (_drawTextCell), so they keep their runs'
|
|
15957
16029
|
// fonts and colors. Only the rows the box holds are drawn, and a table that
|
|
15958
|
-
// loses any is cut. The cursor it leaves is
|
|
16030
|
+
// loses any, or runs past its page anyway, is cut. The cursor it leaves is
|
|
16031
|
+
// TEXT_TABLE_MARGIN under it.
|
|
15959
16032
|
_drawTextTable(context, table, layout, box, top) {
|
|
15960
16033
|
if (top >= box.bottom) {
|
|
15961
16034
|
return { cursorY: top, cut: true };
|
|
@@ -15967,13 +16040,11 @@ class ReportPdfService {
|
|
|
15967
16040
|
: Array.from({ length: table.columns }, () => width / table.columns);
|
|
15968
16041
|
const body = table.rows.map((row) => row.cells.map((cell) => this._textCellInput(context.doc, cell, columnWidths)));
|
|
15969
16042
|
const options = this._textTableOptions(context, columnWidths, left, top, width, box.bottom);
|
|
15970
|
-
const fit = this._textTableFit(context, { ...options, body });
|
|
15971
|
-
|
|
15972
|
-
this._drawTable(context, { ...options, body: this._keptRows(body, fit) });
|
|
15973
|
-
}
|
|
16043
|
+
const fit = this._textTableFit(context, { ...options, body }, top, box.bottom);
|
|
16044
|
+
const whole = !fit || this._drawTable(context, { ...options, body: this._keptRows(body, fit) });
|
|
15974
16045
|
return {
|
|
15975
|
-
cursorY: fit ? context.doc.lastAutoTable.finalY + TEXT_TABLE_MARGIN : top,
|
|
15976
|
-
cut: fit < table.rows.length,
|
|
16046
|
+
cursorY: fit && whole ? context.doc.lastAutoTable.finalY + TEXT_TABLE_MARGIN : top,
|
|
16047
|
+
cut: !whole || fit < table.rows.length,
|
|
15977
16048
|
};
|
|
15978
16049
|
}
|
|
15979
16050
|
// A text table's cell as autoTable takes it: its spans and fill and, when it
|
|
@@ -16027,22 +16098,10 @@ class ReportPdfService {
|
|
|
16027
16098
|
didDrawCell: (hook) => this._drawTextCell(hook),
|
|
16028
16099
|
};
|
|
16029
16100
|
}
|
|
16030
|
-
// How many of a text table's rows its box
|
|
16031
|
-
//
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
_textTableFit(context, options) {
|
|
16035
|
-
const scratch = this._scratchDocument(context);
|
|
16036
|
-
let fit = 0;
|
|
16037
|
-
context.autoTable(scratch, {
|
|
16038
|
-
...options,
|
|
16039
|
-
didDrawCell: (hook) => {
|
|
16040
|
-
if (scratch.getCurrentPageInfo().pageNumber === 1 && !hook.row.spansMultiplePages) {
|
|
16041
|
-
fit = Math.max(fit, hook.row.index + 1);
|
|
16042
|
-
}
|
|
16043
|
-
},
|
|
16044
|
-
});
|
|
16045
|
-
return fit;
|
|
16101
|
+
// How many of a text table's rows its box, from top to bottom, holds whole:
|
|
16102
|
+
// the table laid out as _measure lays out a list's.
|
|
16103
|
+
_textTableFit(context, options, top, bottom) {
|
|
16104
|
+
return this._fittingRows(context.createTable(this._scratchDocument(context), options), top, bottom, 0);
|
|
16046
16105
|
}
|
|
16047
16106
|
// The first `fit` rows, a cell that spans down past the last of them cut
|
|
16048
16107
|
// there.
|
|
@@ -16166,7 +16225,7 @@ class ReportPdfService {
|
|
|
16166
16225
|
};
|
|
16167
16226
|
}
|
|
16168
16227
|
// A tile on its report page, its title's tokens filled with that page's.
|
|
16169
|
-
async _renderComponent(context, item, tokens, overflows) {
|
|
16228
|
+
async _renderComponent(context, page, item, tokens, overflows) {
|
|
16170
16229
|
const { doc } = context;
|
|
16171
16230
|
const component = item.component;
|
|
16172
16231
|
// Geometry is stored in inches; the PDF draws in points.
|
|
@@ -16207,7 +16266,7 @@ class ReportPdfService {
|
|
|
16207
16266
|
}
|
|
16208
16267
|
case 'list':
|
|
16209
16268
|
case 'grid':
|
|
16210
|
-
this._renderTable(context, item, x, bodyY, w, bodyH, overflows);
|
|
16269
|
+
this._renderTable(context, page, item, x, bodyY, w, bodyH, overflows);
|
|
16211
16270
|
break;
|
|
16212
16271
|
case 'kpi':
|
|
16213
16272
|
this._renderKpi(context, item, x, bodyY, w, bodyH);
|
|
@@ -16245,42 +16304,51 @@ class ReportPdfService {
|
|
|
16245
16304
|
doc.text(this._pdfText(title), x, y + 10, { maxWidth: w });
|
|
16246
16305
|
}
|
|
16247
16306
|
// An italic grey line centered in a component's body, for a body that holds
|
|
16248
|
-
// something other than its content.
|
|
16307
|
+
// something other than its content. A line wider than the body wraps.
|
|
16249
16308
|
_boxNote(doc, text, x, y, w, h) {
|
|
16250
16309
|
doc.setFont('helvetica', 'italic');
|
|
16251
16310
|
doc.setFontSize(9);
|
|
16252
16311
|
doc.setTextColor(MUTED_COLOR$1);
|
|
16253
|
-
doc.text(text, x + w / 2, y + h / 2, { align: 'center' });
|
|
16312
|
+
doc.text(text, x + w / 2, y + h / 2, { align: 'center', maxWidth: w });
|
|
16254
16313
|
}
|
|
16255
16314
|
// A list's on-page table. All of its fetched rows are laid out once to learn
|
|
16256
16315
|
// how many the box holds; when they do not all fit, the box's last row says
|
|
16257
16316
|
// the table continues and the rest go to overflows for continuation pages.
|
|
16258
16317
|
// A box too short for even the head carries the notice as a line instead.
|
|
16259
|
-
// A
|
|
16260
|
-
//
|
|
16261
|
-
|
|
16318
|
+
// A table whose heading and totals row leave a continuation page no room for
|
|
16319
|
+
// a row stops at its box, its notice saying so. A totals row closes the
|
|
16320
|
+
// table once: in the box when every row fits it, else after the last
|
|
16321
|
+
// continuation row. Points throughout.
|
|
16322
|
+
_renderTable(context, page, item, x, y, w, h, overflows) {
|
|
16262
16323
|
const { component, search, filtered } = item;
|
|
16263
16324
|
const { head, cells, numeric, foot, omitted } = item.table ? this._gridCells(item) : this._listCells(context, item);
|
|
16264
16325
|
const bottom = context.pageH - (y + h);
|
|
16265
|
-
const { fit, columnStyles } = this._measure(context, head, cells, numeric, foot, x, y, w, bottom);
|
|
16326
|
+
const { fit, columnStyles, minHeight } = this._measure(context, head, cells, numeric, foot, x, y, w, bottom);
|
|
16266
16327
|
if (fit === cells.length && omitted === 0) {
|
|
16267
16328
|
this._drawTable(context, this._tableOptions(context, head, numeric, cells, x, y, w, bottom, columnStyles, foot));
|
|
16268
16329
|
return;
|
|
16269
16330
|
}
|
|
16331
|
+
// autoTable needs room for a row under the heading on every page it adds,
|
|
16332
|
+
// or it adds pages until the browser's stack runs out.
|
|
16333
|
+
const continues = minHeight < this._continuationRoom(context, page);
|
|
16334
|
+
const notice = continues ? CONTINUED_NOTICE : NO_ROOM_NOTICE;
|
|
16270
16335
|
// The notice takes the place of the last row that fit, so that row moves
|
|
16271
16336
|
// to the continuation. omitted > 0 means a full PDF_LIST_ROWS fetch, which
|
|
16272
16337
|
// never fits one box, so the CSV notice always lands on a continuation
|
|
16273
16338
|
// page.
|
|
16274
16339
|
const kept = Math.max(0, fit - 1);
|
|
16275
|
-
overflows.push({
|
|
16276
|
-
component, search, crumbs: item.crumbs, filtered, head, numeric, rows: cells.slice(kept), omitted, foot, x, w, columnStyles,
|
|
16277
|
-
});
|
|
16278
16340
|
if (fit >= 1) {
|
|
16279
|
-
const body = [...cells.slice(0, kept), this._noticeRow(
|
|
16341
|
+
const body = [...cells.slice(0, kept), this._noticeRow(notice, numeric.length, true)];
|
|
16280
16342
|
this._drawTable(context, this._tableOptions(context, head, numeric, body, x, y, w, bottom, columnStyles));
|
|
16281
16343
|
}
|
|
16282
16344
|
else {
|
|
16283
|
-
this._boxNote(context.doc,
|
|
16345
|
+
this._boxNote(context.doc, notice, x, y, w, h);
|
|
16346
|
+
}
|
|
16347
|
+
if (continues) {
|
|
16348
|
+
overflows.push({
|
|
16349
|
+
component, search, crumbs: item.crumbs, filtered, head, numeric, rows: cells.slice(kept), omitted, foot, x, w,
|
|
16350
|
+
columnStyles,
|
|
16351
|
+
});
|
|
16284
16352
|
}
|
|
16285
16353
|
}
|
|
16286
16354
|
// A list's heading, rows, totals row and the rows past its fetch.
|
|
@@ -16302,7 +16370,16 @@ class ReportPdfService {
|
|
|
16302
16370
|
rowSpan: exported.rowSpan,
|
|
16303
16371
|
styles: {
|
|
16304
16372
|
...(exported.bold ? { fontStyle: 'bold' } : {}),
|
|
16305
|
-
...(exported.indent
|
|
16373
|
+
...(exported.indent
|
|
16374
|
+
? {
|
|
16375
|
+
cellPadding: {
|
|
16376
|
+
top: TABLE_CELL_PADDING,
|
|
16377
|
+
right: TABLE_CELL_PADDING,
|
|
16378
|
+
bottom: TABLE_CELL_PADDING,
|
|
16379
|
+
left: TABLE_CELL_PADDING + exported.indent * GRID_INDENT$1,
|
|
16380
|
+
},
|
|
16381
|
+
}
|
|
16382
|
+
: {}),
|
|
16306
16383
|
},
|
|
16307
16384
|
});
|
|
16308
16385
|
return {
|
|
@@ -16345,7 +16422,13 @@ class ReportPdfService {
|
|
|
16345
16422
|
margin: { left: x, right: context.pageW - x - w, bottom },
|
|
16346
16423
|
tableWidth: w,
|
|
16347
16424
|
rowPageBreak: 'avoid',
|
|
16348
|
-
styles: {
|
|
16425
|
+
styles: {
|
|
16426
|
+
font: 'helvetica',
|
|
16427
|
+
fontStyle: 'normal',
|
|
16428
|
+
fontSize: TABLE_FONT_SIZE,
|
|
16429
|
+
cellPadding: TABLE_CELL_PADDING,
|
|
16430
|
+
textColor: '#1f2933',
|
|
16431
|
+
},
|
|
16349
16432
|
headStyles: { fillColor: '#4e79a7', textColor: '#ffffff', fontStyle: 'bold' },
|
|
16350
16433
|
alternateRowStyles: { fillColor: '#f5f7fa' },
|
|
16351
16434
|
...(columnStyles ? { columnStyles } : {}),
|
|
@@ -16383,37 +16466,51 @@ class ReportPdfService {
|
|
|
16383
16466
|
}
|
|
16384
16467
|
// Lays every fetched row out once on a scratch document of the same page
|
|
16385
16468
|
// size, with the options the real draw uses, and reads back how many body
|
|
16386
|
-
// rows the box
|
|
16387
|
-
//
|
|
16388
|
-
//
|
|
16389
|
-
//
|
|
16390
|
-
//
|
|
16391
|
-
//
|
|
16392
|
-
//
|
|
16469
|
+
// rows the box holds (fit), the column widths autoTable chose, with each
|
|
16470
|
+
// numeric column's right alignment merged in, so the on-page table and its
|
|
16471
|
+
// continuation pages carry both, and the least room a page must give the
|
|
16472
|
+
// table (minHeight). The totals row is laid out too, so the widths hold it,
|
|
16473
|
+
// and a table whose rows fit the box but whose totals row does not moves
|
|
16474
|
+
// its last row on. fit 0 means not even one body row fits under the head.
|
|
16475
|
+
// The table is laid out, never drawn: drawn, autoTable pages it, and a table
|
|
16476
|
+
// with no room for a row on a page pages without end.
|
|
16393
16477
|
_measure(context, head, cells, numeric, foot, x, y, w, bottom) {
|
|
16394
16478
|
const scratch = this._scratchDocument(context);
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
...this._tableOptions(context, head, numeric, cells, x, y, w, bottom, undefined, foot),
|
|
16398
|
-
didDrawCell: (hook) => {
|
|
16399
|
-
if (hook.section === 'body' && scratch.getCurrentPageInfo().pageNumber === 1) {
|
|
16400
|
-
fit = Math.max(fit, hook.row.index + 1);
|
|
16401
|
-
}
|
|
16402
|
-
},
|
|
16403
|
-
});
|
|
16404
|
-
const columns = scratch.lastAutoTable.columns;
|
|
16479
|
+
const table = context.createTable(scratch, this._tableOptions(context, head, numeric, cells, x, y, w, bottom, undefined, foot));
|
|
16480
|
+
const columns = table.columns;
|
|
16405
16481
|
const columnStyles = {};
|
|
16406
16482
|
columns.forEach((column, index) => {
|
|
16407
16483
|
columnStyles[index] = numeric[index]
|
|
16408
16484
|
? { cellWidth: column.width, halign: 'right' }
|
|
16409
16485
|
: { cellWidth: column.width };
|
|
16410
16486
|
});
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16414
|
-
fit
|
|
16487
|
+
const headHeight = table.getHeadHeight(table.columns);
|
|
16488
|
+
const footHeight = table.getFootHeight(table.columns);
|
|
16489
|
+
return {
|
|
16490
|
+
fit: this._fittingRows(table, y + headHeight, context.pageH - bottom, footHeight),
|
|
16491
|
+
columnStyles,
|
|
16492
|
+
// One line of a row: the line autoTable must place on a page before it
|
|
16493
|
+
// moves on, at the table's font size and padding.
|
|
16494
|
+
minHeight: headHeight + footHeight + TABLE_FONT_SIZE * scratch.getLineHeightFactor() + 2 * TABLE_CELL_PADDING,
|
|
16495
|
+
};
|
|
16496
|
+
}
|
|
16497
|
+
// How many of a laid-out table's body rows fit whole between top and
|
|
16498
|
+
// bottom, as autoTable decides it: a row fits when its tallest cell (one that
|
|
16499
|
+
// spans rows counts all of them) ends by bottom, the last row's by the top
|
|
16500
|
+
// of the totals row (footHeight) under it, and the next row starts where it
|
|
16501
|
+
// ends.
|
|
16502
|
+
_fittingRows(table, top, bottom, footHeight) {
|
|
16503
|
+
let cursor = top;
|
|
16504
|
+
let fit = 0;
|
|
16505
|
+
for (const [index, row] of table.body.entries()) {
|
|
16506
|
+
const limit = index === table.body.length - 1 ? bottom - footHeight : bottom;
|
|
16507
|
+
if (cursor + row.getMaxCellHeight(table.columns) > limit) {
|
|
16508
|
+
break;
|
|
16509
|
+
}
|
|
16510
|
+
cursor += row.height;
|
|
16511
|
+
fit += 1;
|
|
16415
16512
|
}
|
|
16416
|
-
return
|
|
16513
|
+
return fit;
|
|
16417
16514
|
}
|
|
16418
16515
|
// A blank document of the export's page size, for laying a table out to see
|
|
16419
16516
|
// what fits before the real one is drawn on.
|
|
@@ -16424,20 +16521,42 @@ class ReportPdfService {
|
|
|
16424
16521
|
orientation: context.orientation,
|
|
16425
16522
|
});
|
|
16426
16523
|
}
|
|
16427
|
-
// Draws an on-page table (a list's, or a text block's)
|
|
16428
|
-
//
|
|
16429
|
-
//
|
|
16430
|
-
//
|
|
16431
|
-
// remaining components
|
|
16524
|
+
// Draws an on-page table (a list's, or a text block's) on its page alone.
|
|
16525
|
+
// That is all it should need: the measured fit, the identical column widths
|
|
16526
|
+
// and a single-line notice keep the table inside its box. Should autoTable
|
|
16527
|
+
// start another page anyway, the table stops there and the page goes, so a
|
|
16528
|
+
// stray page can never catch the report page's remaining components, nor a
|
|
16529
|
+
// table with no room for a row add pages without end. Returns whether the
|
|
16530
|
+
// table was drawn whole.
|
|
16432
16531
|
_drawTable(context, options) {
|
|
16433
16532
|
const { doc } = context;
|
|
16434
16533
|
const page = doc.getCurrentPageInfo().pageNumber;
|
|
16435
16534
|
const pages = doc.getNumberOfPages();
|
|
16436
|
-
|
|
16535
|
+
let whole = true;
|
|
16536
|
+
try {
|
|
16537
|
+
context.autoTable(doc, {
|
|
16538
|
+
...options,
|
|
16539
|
+
// Fires as the table starts its own page, and again on each page it
|
|
16540
|
+
// moves to (an existing page, such as a continuation page under a
|
|
16541
|
+
// header, as well as a new one).
|
|
16542
|
+
willDrawPage: () => {
|
|
16543
|
+
if (doc.getCurrentPageInfo().pageNumber !== page) {
|
|
16544
|
+
throw STRAY_PAGE;
|
|
16545
|
+
}
|
|
16546
|
+
},
|
|
16547
|
+
});
|
|
16548
|
+
}
|
|
16549
|
+
catch (error) {
|
|
16550
|
+
if (error !== STRAY_PAGE) {
|
|
16551
|
+
throw error;
|
|
16552
|
+
}
|
|
16553
|
+
whole = false;
|
|
16554
|
+
}
|
|
16437
16555
|
while (doc.getNumberOfPages() > pages) {
|
|
16438
16556
|
doc.deletePage(doc.getNumberOfPages());
|
|
16439
16557
|
}
|
|
16440
16558
|
doc.setPage(page);
|
|
16559
|
+
return whole;
|
|
16441
16560
|
}
|
|
16442
16561
|
// The rows of one list that did not fit its box, on pages appended after
|
|
16443
16562
|
// the report page, each with the page's header and footer, the table's
|
|
@@ -16446,9 +16565,7 @@ class ReportPdfService {
|
|
|
16446
16565
|
// Returns the physical page counter after these pages.
|
|
16447
16566
|
async _renderContinuation(context, page, index, pageNumber, overflow) {
|
|
16448
16567
|
const { doc } = context;
|
|
16449
|
-
const
|
|
16450
|
-
const top = this._continuationMargin(bands.headerHeight);
|
|
16451
|
-
const bottom = this._continuationMargin(bands.footerHeight);
|
|
16568
|
+
const { top, bottom } = this._continuationMargins(context, page);
|
|
16452
16569
|
const { x, w } = overflow;
|
|
16453
16570
|
const body = overflow.omitted > 0
|
|
16454
16571
|
? [...overflow.rows, this._noticeRow(moreRowsNotice(overflow.omitted), overflow.numeric.length, false)]
|
|
@@ -16482,6 +16599,21 @@ class ReportPdfService {
|
|
|
16482
16599
|
}
|
|
16483
16600
|
doc.setPage(doc.getNumberOfPages());
|
|
16484
16601
|
}
|
|
16602
|
+
// The margins a continuation table keeps from the top and bottom of its
|
|
16603
|
+
// pages, under its title's strip at the top.
|
|
16604
|
+
_continuationMargins(context, page) {
|
|
16605
|
+
const bands = page.masterHidden ? NO_BANDS : context.report.config?.headerFooter ?? NO_BANDS;
|
|
16606
|
+
return {
|
|
16607
|
+
top: this._continuationMargin(bands.headerHeight),
|
|
16608
|
+
bottom: this._continuationMargin(bands.footerHeight),
|
|
16609
|
+
};
|
|
16610
|
+
}
|
|
16611
|
+
// The height a continuation page gives its table: between its margins, under
|
|
16612
|
+
// the title.
|
|
16613
|
+
_continuationRoom(context, page) {
|
|
16614
|
+
const { top, bottom } = this._continuationMargins(context, page);
|
|
16615
|
+
return context.pageH - top - TITLE_H$1 - bottom;
|
|
16616
|
+
}
|
|
16485
16617
|
// The margin a continuation table keeps from one edge: inside the band when
|
|
16486
16618
|
// the page has one.
|
|
16487
16619
|
_continuationMargin(band) {
|
|
@@ -16847,6 +16979,9 @@ class ReportPptxService {
|
|
|
16847
16979
|
return {
|
|
16848
16980
|
overflows: [...overflows.values()],
|
|
16849
16981
|
overflowNote: PPTX_OVERFLOW_NOTE,
|
|
16982
|
+
// A slide's shapes are laid out by PowerPoint, so a component cannot
|
|
16983
|
+
// fail to draw here as a PDF table can.
|
|
16984
|
+
undrawn: [],
|
|
16850
16985
|
save: async () => {
|
|
16851
16986
|
await pptx.writeFile({ fileName: `${this._slug(report.name)}.pptx` });
|
|
16852
16987
|
},
|
|
@@ -18025,7 +18160,8 @@ const RETRY = 'retry';
|
|
|
18025
18160
|
const DOWNLOAD = 'download';
|
|
18026
18161
|
// Runs a report export end to end: collect every tile and value, refuse to
|
|
18027
18162
|
// write a file that is missing any of them without saying so, build it, refuse
|
|
18028
|
-
// to save one whose text does not fit its
|
|
18163
|
+
// to save one that could not draw a component, or whose text does not fit its
|
|
18164
|
+
// boxes, without saying so, then save.
|
|
18029
18165
|
//
|
|
18030
18166
|
// The gates are the reason this sits between the collector and the renderers
|
|
18031
18167
|
// rather than in either of them. A deck with five blank pages is worse than no
|
|
@@ -18064,11 +18200,12 @@ class ReportExportService {
|
|
|
18064
18200
|
? this._run(report, listRows, build)
|
|
18065
18201
|
: this._buildAndSave(collected, build)))));
|
|
18066
18202
|
}
|
|
18067
|
-
// Builds the file, then saves it once the overflow
|
|
18203
|
+
// Builds the file, then saves it once the undrawn and overflow gates let it
|
|
18204
|
+
// through.
|
|
18068
18205
|
_buildAndSave(collected, build) {
|
|
18069
18206
|
return from(build(collected))
|
|
18070
|
-
.pipe(switchMap((built) => this.
|
|
18071
|
-
.pipe(switchMap(() => from(Promise.resolve(built.save()))))));
|
|
18207
|
+
.pipe(switchMap((built) => this._undrawnGate(built)
|
|
18208
|
+
.pipe(switchMap(() => this._overflowGate(built)), switchMap(() => from(Promise.resolve(built.save()))))));
|
|
18072
18209
|
}
|
|
18073
18210
|
// Resolves to DOWNLOAD when the export is whole (or the user accepted an
|
|
18074
18211
|
// incomplete one) and to RETRY when they want another attempt. Cancelling
|
|
@@ -18094,6 +18231,30 @@ class ReportExportService {
|
|
|
18094
18231
|
})
|
|
18095
18232
|
.pipe(catchError(() => EMPTY));
|
|
18096
18233
|
}
|
|
18234
|
+
// Resolves to DOWNLOAD when the build drew every component, or the user
|
|
18235
|
+
// accepted a file that marks the ones it could not in their place. There is
|
|
18236
|
+
// no Retry: a second build draws the same data the same way. Each component
|
|
18237
|
+
// is named by its page and its title (a text block by the start of its
|
|
18238
|
+
// words). Cancelling ends the export quietly, as at the failure gate, and
|
|
18239
|
+
// the built file is dropped unsaved.
|
|
18240
|
+
_undrawnGate(built) {
|
|
18241
|
+
if (!built.undrawn.length) {
|
|
18242
|
+
return of(DOWNLOAD);
|
|
18243
|
+
}
|
|
18244
|
+
const components = built.undrawn
|
|
18245
|
+
.map((undrawn) => `<strong>${escapeHtml(undrawn.page)}</strong>`
|
|
18246
|
+
+ (undrawn.name ? ` (“${escapeHtml(undrawn.name)}”)` : ''));
|
|
18247
|
+
return this._prompt.confirm({
|
|
18248
|
+
title: 'Some tiles could not be drawn',
|
|
18249
|
+
template: `Some tiles could not be drawn: ${components.join(', ')}. `
|
|
18250
|
+
+ 'The file says "Could not be drawn" in their place.',
|
|
18251
|
+
buttons: [
|
|
18252
|
+
{ label: 'Download Anyway', value: DOWNLOAD, color: 'primary' },
|
|
18253
|
+
{ label: 'Cancel', cancel: true, color: '' },
|
|
18254
|
+
],
|
|
18255
|
+
})
|
|
18256
|
+
.pipe(catchError(() => EMPTY));
|
|
18257
|
+
}
|
|
18097
18258
|
// Resolves to DOWNLOAD when every text block fits its box in the built file,
|
|
18098
18259
|
// or the user accepted one that does not. There is no Retry: the words are
|
|
18099
18260
|
// the report's own, so a second attempt would build the same file. Each block
|
|
@@ -18898,7 +19059,7 @@ class FsAiReportComponent {
|
|
|
18898
19059
|
ReportAiChatData,
|
|
18899
19060
|
{ provide: FsAiChatData, useExisting: ReportAiChatData },
|
|
18900
19061
|
// Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
|
|
18901
|
-
provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-
|
|
19062
|
+
provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-CBoGhanh.mjs').then((module) => module.default) }),
|
|
18902
19063
|
// The bar's date pickers start their weeks on Monday and list the built-in
|
|
18903
19064
|
// presets; a preset only sets the days.
|
|
18904
19065
|
provideReportDatePicker(),
|
|
@@ -18922,7 +19083,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
18922
19083
|
ReportAiChatData,
|
|
18923
19084
|
{ provide: FsAiChatData, useExisting: ReportAiChatData },
|
|
18924
19085
|
// Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
|
|
18925
|
-
provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-
|
|
19086
|
+
provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-CBoGhanh.mjs').then((module) => module.default) }),
|
|
18926
19087
|
// The bar's date pickers start their weeks on Monday and list the built-in
|
|
18927
19088
|
// presets; a preset only sets the days.
|
|
18928
19089
|
provideReportDatePicker(),
|
|
@@ -19015,4 +19176,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
19015
19176
|
*/
|
|
19016
19177
|
|
|
19017
19178
|
export { FsAiReportsComponent as F, GRANULARITY_OPTIONS as G, REPORT_CHART_COLORS_CSS as R, REPORT_CHART_FONT_FAMILY as a, REPORT_AXIS_LABEL_FONT_SIZE as b, FsAiReportComponent as c, ReportData as d, ReportService as e, ReportFilterStateService as f, ReportNodeType as g, ReportState as h, ReportValueFormat as i, ReportValueFormula as j, ReportListColumnFormat as k, ReportNumberUnits as l, ReportChartDataLabels as m, ReportChartColor as n, ReportChartLineStyle as o, ReportChartMarkStat as p, ReportChartDateLabel as q, ReportChangePolarity as r };
|
|
19018
|
-
//# sourceMappingURL=firestitch-report-firestitch-report-
|
|
19179
|
+
//# sourceMappingURL=firestitch-report-firestitch-report-MBuBuGiA.mjs.map
|