@firestitch/report 18.13.0 → 18.14.0

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.
Files changed (28) hide show
  1. package/app/reports/components/component-grid/component-grid.component.d.ts +4 -0
  2. package/app/reports/data/report-grid-source.d.ts +1 -0
  3. package/app/reports/interfaces/{report-chat-viewer-detail.interface.d.ts → report-chat-viewer-show-rows.interface.d.ts} +1 -1
  4. package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +2 -2
  5. package/app/reports/interfaces/report-mark-action.type.d.ts +1 -1
  6. package/app/reports/interfaces/report-temporary-state.interface.d.ts +1 -1
  7. package/app/reports/interfaces/report-viewer-feature.type.d.ts +1 -1
  8. package/app/reports/report-grid-layout.d.ts +2 -1
  9. package/esm2022/app/reports/components/component-grid/component-grid.component.mjs +40 -5
  10. package/esm2022/app/reports/data/report-grid-source.mjs +11 -2
  11. package/esm2022/app/reports/interfaces/report-chat-viewer-show-rows.interface.mjs +2 -0
  12. package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
  13. package/esm2022/app/reports/interfaces/report-mark-action.type.mjs +1 -1
  14. package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +1 -1
  15. package/esm2022/app/reports/interfaces/report-viewer-feature.type.mjs +1 -1
  16. package/esm2022/app/reports/mark-click.mjs +2 -2
  17. package/esm2022/app/reports/option-builder.mjs +4 -4
  18. package/esm2022/app/reports/report-grid-layout.mjs +43 -2
  19. package/esm2022/app/reports/report-viewer-features.mjs +4 -2
  20. package/esm2022/app/reports/services/report-filter-state.service.mjs +2 -2
  21. package/fesm2022/{firestitch-report-echarts-EecIloKo.mjs → firestitch-report-echarts-DMflI6jp.mjs} +2 -2
  22. package/fesm2022/{firestitch-report-echarts-EecIloKo.mjs.map → firestitch-report-echarts-DMflI6jp.mjs.map} +1 -1
  23. package/fesm2022/{firestitch-report-firestitch-report-DbdLxQSE.mjs → firestitch-report-firestitch-report-C94rjx24.mjs} +104 -19
  24. package/fesm2022/firestitch-report-firestitch-report-C94rjx24.mjs.map +1 -0
  25. package/fesm2022/firestitch-report.mjs +1 -1
  26. package/package.json +1 -1
  27. package/esm2022/app/reports/interfaces/report-chat-viewer-detail.interface.mjs +0 -2
  28. package/fesm2022/firestitch-report-firestitch-report-DbdLxQSE.mjs.map +0 -1
@@ -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-DbdLxQSE.mjs';
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-C94rjx24.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-EecIloKo.mjs.map
66
+ //# sourceMappingURL=firestitch-report-echarts-DMflI6jp.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"firestitch-report-echarts-EecIloKo.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"}
1
+ {"version":3,"file":"firestitch-report-echarts-DMflI6jp.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"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, signal, computed, DestroyRef, Component, ChangeDetectionStrategy, input, model, output, untracked, NgZone, Pipe, viewChild, ElementRef, Injector, effect, afterNextRender, EventEmitter, Input, Output, ViewChild, HostBinding, ViewChildren, ApplicationRef, EnvironmentInjector, createComponent, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
+ import { inject, Injectable, signal, computed, DestroyRef, Component, ChangeDetectionStrategy, input, model, output, untracked, NgZone, Pipe, Injector, effect, viewChild, ElementRef, afterNextRender, EventEmitter, Input, Output, ViewChild, HostBinding, ViewChildren, ApplicationRef, EnvironmentInjector, createComponent, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3
3
  import * as i1$1 from '@angular/forms';
4
4
  import { FormsModule, ControlContainer, NgForm } from '@angular/forms';
5
5
  import * as i3$3 from '@angular/material/button';
@@ -29,20 +29,20 @@ import * as i3$1 from '@firestitch/zoom-pan';
29
29
  import { FsZoomPanComponent, FsZoomPanModule } from '@firestitch/zoom-pan';
30
30
  import { of, forkJoin, Subject, defer, merge, map as map$1, switchMap as switchMap$1, timer, catchError as catchError$1, filter as filter$1, mergeMap, EMPTY, concatWith, throwError, tap as tap$1, distinctUntilChanged, from, debounceTime, BehaviorSubject } from 'rxjs';
31
31
  import { FsApi, RequestMethod, StreamEventType, DisplayApiError } from '@firestitch/api';
32
- import { GridFieldType, GridGranularity, canonicalGridLayout, convertDateFilter, GridFormat, GridUnits, FsGridComponent, FsGridCellDirective, GridRowKind, readGridTable } from '@firestitch/grid';
32
+ import { GridFieldType, GridGranularity, canonicalGridLayout, convertDateFilter, GridNoteCode, GridControlState, GridFormat, GridUnits, FsGridComponent, FsGridCellDirective, GridRowKind, readGridTable } from '@firestitch/grid';
33
33
  import { parseISO, isValid, addDays, min, max, startOfDay, isLastDayOfMonth, endOfMonth, addMonths, addYears, addQuarters, addWeeks, formatISO, format, startOfYear, startOfQuarter, startOfMonth, subMonths, subDays, subWeeks, startOfWeek, endOfWeek } from 'date-fns';
34
34
  import { toZonedTime } from 'date-fns-tz';
35
35
  import { MatProgressSpinner } from '@angular/material/progress-spinner';
36
36
  import { MatCheckbox } from '@angular/material/checkbox';
37
37
  import * as i3 from '@firestitch/dialog';
38
38
  import { FsDialogModule } from '@firestitch/dialog';
39
+ import { FsPopoverDirective } from '@firestitch/popover';
39
40
  import { HttpErrorResponse, HttpContext } from '@angular/common/http';
40
41
  import { NgTemplateOutlet, DOCUMENT } from '@angular/common';
41
42
  import * as i1 from '@firestitch/list';
42
43
  import { FsListComponent, PaginationStrategy, FsListModule } from '@firestitch/list';
43
44
  import { DomSanitizer } from '@angular/platform-browser';
44
45
  import { Plugin, FsHtmlEditorComponent } from '@firestitch/html-editor';
45
- import { FsPopoverDirective } from '@firestitch/popover';
46
46
  import { MatFormField, MatHint, MatLabel, MatSuffix } from '@angular/material/form-field';
47
47
  import { MatInput } from '@angular/material/input';
48
48
  import { MatOption, MatSelect } from '@angular/material/select';
@@ -114,7 +114,8 @@ function canvasLandingPage(input) {
114
114
  // cascadingOptions narrows a select's list by the other filters of its tile
115
115
  // (ReportFilterOptionsService). drill is a time chart's click down, with
116
116
  // the tile header's breadcrumb and its menu's Drill up and Back to top as the
117
- // way back.
117
+ // way back. grid is a table tile drawn by fs-grid: a server that serves it
118
+ // sends a table only to a viewer that names it.
118
119
  const VIEWER_FEATURES = [
119
120
  'scopeFilters',
120
121
  'excludeValues',
@@ -123,6 +124,7 @@ const VIEWER_FEATURES = [
123
124
  'pageScope',
124
125
  'cascadingOptions',
125
126
  'drill',
127
+ 'grid',
126
128
  ];
127
129
  // The features a report offers on this screen: the ones its server serves
128
130
  // (Report.viewerFeatures) that this viewer also implements.
@@ -2417,16 +2419,16 @@ const COMPARED_PRIOR_PREFIX = 'vs';
2417
2419
  // The tooltip's last line on a chart whose marks act on a click
2418
2420
  // (markActionHint): one action by its full name, several by their short
2419
2421
  // names, in this order. Interface text, English in every report locale.
2420
- const MARK_ACTION_ORDER = ['drill', 'crossFilter', 'detail'];
2422
+ const MARK_ACTION_ORDER = ['drill', 'crossFilter', 'showRows'];
2421
2423
  const MARK_ACTION_HINTS = {
2422
2424
  drill: 'drill down',
2423
2425
  crossFilter: 'filter other tiles',
2424
- detail: 'show rows',
2426
+ showRows: 'show rows',
2425
2427
  };
2426
2428
  const MARK_ACTION_SHORT_HINTS = {
2427
2429
  drill: 'drill down',
2428
2430
  crossFilter: 'filter',
2429
- detail: 'show rows',
2431
+ showRows: 'show rows',
2430
2432
  };
2431
2433
  // The words a statistic line's label starts with. They are interface text,
2432
2434
  // English in every report locale; only the value after them follows it.
@@ -6105,6 +6107,47 @@ function grainedGridLayout(layout, field, granularity) {
6105
6107
  .filter((item) => !!item);
6106
6108
  return { layout: { ...layout, filters }, cleared: converted ? null : { field, granularity: grain } };
6107
6109
  }
6110
+ // The notes that leave a filter out of a read, by the filter's index (filters.N...)
6111
+ const PRUNED_FILTER_CODES = new Set([
6112
+ GridNoteCode.FieldMissing,
6113
+ GridNoteCode.CannotFilter,
6114
+ GridNoteCode.FilterRefused,
6115
+ GridNoteCode.GranularityRefused,
6116
+ ]);
6117
+ // The notes that leave a sort term out of a read, by the term's index (sort.N...)
6118
+ const PRUNED_SORT_CODES = new Set([
6119
+ GridNoteCode.FieldMissing,
6120
+ GridNoteCode.SortRefused,
6121
+ ]);
6122
+ // A viewer's layout of a table once its first read is in: the filters and sort
6123
+ // terms that read refused (a field the query no longer has, a filter or grain
6124
+ // the field no longer takes) are taken out, so the stored session layout holds
6125
+ // only what applies. When the author turned filtering off (`filter`, the
6126
+ // tile's controls.filter), the viewer's filters give way to the authored ones
6127
+ // (`authored`), which a viewer cannot change. The layout comes back as it is
6128
+ // when nothing changes.
6129
+ function prunedGridLayout(layout, notes, filter, authored = []) {
6130
+ const filters = layout.filters ?? [];
6131
+ const sort = layout.sort ?? [];
6132
+ const filterIndexes = notedIndexes(notes, 'filters', PRUNED_FILTER_CODES);
6133
+ const sortIndexes = notedIndexes(notes, 'sort', PRUNED_SORT_CODES);
6134
+ const canFilter = (filter ?? GridControlState.Enabled) === GridControlState.Enabled;
6135
+ const keptFilters = canFilter ? filters.filter((_item, index) => !filterIndexes.has(index)) : [...authored];
6136
+ const keptSort = sort.filter((_term, index) => !sortIndexes.has(index));
6137
+ const isFiltersKept = JSON.stringify(keptFilters) === JSON.stringify(filters);
6138
+ return isFiltersKept && keptSort.length === sort.length
6139
+ ? layout
6140
+ : { ...layout, filters: keptFilters, sort: keptSort };
6141
+ }
6142
+ // The indexes under `key` (key.N or key.N.part) the notes of `codes` name
6143
+ function notedIndexes(notes, key, codes) {
6144
+ const pattern = new RegExp(`^${key}\\.(\\d+)(\\.|$)`);
6145
+ return new Set(notes
6146
+ .filter((note) => codes.has(note.code))
6147
+ .map((note) => pattern.exec(note.path ?? ''))
6148
+ .filter((match) => !!match)
6149
+ .map((match) => Number(match[1])));
6150
+ }
6108
6151
 
6109
6152
  // Whether two stored filter-group defaults are the same. Compared on the fields a
6110
6153
  // default can actually carry, so key order in the payload can't read as a change.
@@ -6197,7 +6240,7 @@ function defaultSignature(group) {
6197
6240
  }
6198
6241
  // The temporary layer with nothing picked.
6199
6242
  function emptyTemporaryState() {
6200
- return { crossFilters: [], detail: null };
6243
+ return { crossFilters: [], showRows: null };
6201
6244
  }
6202
6245
  // Viewer filter state for the open report. Filter VALUES are never saved to
6203
6246
  // the report — this service holds them per filter GROUP (the propagation unit),
@@ -7792,7 +7835,7 @@ function normalizedCardSettings(settings) {
7792
7835
  const MARK_ACTION_LABELS = {
7793
7836
  drill: 'Drill down',
7794
7837
  crossFilter: 'Filter other tiles',
7795
- detail: 'Show rows',
7838
+ showRows: 'Show rows',
7796
7839
  };
7797
7840
  // Where a click was and what made it. A PointerEvent names its pointer; a
7798
7841
  // TouchEvent is a touch; anything else (a plain MouseEvent, a key press
@@ -8394,6 +8437,9 @@ class ReportGridSource {
8394
8437
  _componentId;
8395
8438
  // The report line of the latest read, null until one arrives.
8396
8439
  report = signal(null);
8440
+ // The summary of the latest read (its version and notes), null until one
8441
+ // arrives.
8442
+ summary = signal(null);
8397
8443
  _isExport;
8398
8444
  _locale;
8399
8445
  constructor(_reportData, _reportId, _componentId, options = {}) {
@@ -8413,7 +8459,13 @@ class ReportGridSource {
8413
8459
  return EMPTY;
8414
8460
  }
8415
8461
  return this._part$(event.data);
8416
- }), concatWith(defer(() => (summary ? of(summary) : throwError(() => new Error(STREAM_CUT))))), catchError$1((error) => throwError(() => readError(error))));
8462
+ }), concatWith(defer(() => {
8463
+ if (!summary) {
8464
+ return throwError(() => new Error(STREAM_CUT));
8465
+ }
8466
+ this.summary.set(summary);
8467
+ return of(summary);
8468
+ })), catchError$1((error) => throwError(() => readError(error))));
8417
8469
  });
8418
8470
  }
8419
8471
  _stream$(request, params) {
@@ -8618,7 +8670,11 @@ function decimalMark(locale) {
8618
8670
  // - fs-grid compares the layout and params by value: a cloned value never
8619
8671
  // reads again.
8620
8672
  // - An output's detail cell is drawn by fsReportGridCell, so a change tells
8621
- // a missing prior from a zero one and says why on hover, as a list does.
8673
+ // a missing prior from a zero one, as a list does; a click on it opens
8674
+ // why, as no cell carries a native tooltip.
8675
+ // - After the tile's first read, the viewer's layout loses the filters and
8676
+ // sort terms that read refused (prunedGridLayout), so stale tile state
8677
+ // (a field the AI took out of the query) does not linger.
8622
8678
  class ComponentGridComponent {
8623
8679
  reportId = input.required();
8624
8680
  component = input.required();
@@ -8642,11 +8698,15 @@ class ComponentGridComponent {
8642
8698
  _reportData = inject(ReportData);
8643
8699
  _filterState = inject(ReportFilterStateService);
8644
8700
  _destroyRef = inject(DestroyRef);
8701
+ _injector = inject(Injector);
8702
+ // Whether the first read's notes have pruned the viewer's layout.
8703
+ _isPruned = false;
8645
8704
  // The state version the params on screen were read under.
8646
8705
  _paramsVersion = 0;
8647
8706
  ngOnInit() {
8648
8707
  this.expansion.set(this._filterState.gridExpansion(this.component()));
8649
8708
  this._init();
8709
+ this._pruneAfterFirstRead();
8650
8710
  }
8651
8711
  setLayout(layout) {
8652
8712
  this._filterState.setGridLayout(this.component(), layout);
@@ -8666,6 +8726,30 @@ class ComponentGridComponent {
8666
8726
  .subscribe(() => this._applyParams());
8667
8727
  }
8668
8728
  }
8729
+ // Once the tile's first read is in, its notes prune the viewer's layout
8730
+ // (prunedGridLayout). A tile showing its authored layout has nothing to
8731
+ // prune.
8732
+ _pruneAfterFirstRead() {
8733
+ effect(() => {
8734
+ const summary = this.source().summary();
8735
+ if (!summary || this._isPruned) {
8736
+ return;
8737
+ }
8738
+ this._isPruned = true;
8739
+ untracked(() => this._prune(summary.notes ?? []));
8740
+ }, { injector: this._injector, allowSignalWrites: true });
8741
+ }
8742
+ _prune(notes) {
8743
+ const component = this.component();
8744
+ const session = this._filterState.gridSessionLayout(component);
8745
+ if (!session) {
8746
+ return;
8747
+ }
8748
+ const pruned = prunedGridLayout(session, notes, this.controls().filter, authoredGridLayout(component).filters);
8749
+ if (pruned !== session) {
8750
+ this._filterState.setGridLayout(component, pruned);
8751
+ }
8752
+ }
8669
8753
  // A change, once it has settled: at once when the state version moved,
8670
8754
  // else after the debounce; dropped when the version moves while it waits,
8671
8755
  // since that move brings its own change.
@@ -8691,16 +8775,17 @@ class ComponentGridComponent {
8691
8775
  };
8692
8776
  }
8693
8777
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8694
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentGridComponent, isStandalone: true, selector: "app-report-component-grid", inputs: { reportId: { classPropertyName: "reportId", publicName: "reportId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!-- The comparison and window note strip above the table, from the report\n line of the latest read; the windows' descriptions and notes go in each\n column's \"About this column\" instead. -->\n<div class=\"fs-column grid-pane\">\n <app-report-component-note\n [data]=\"noteData()\"\n [windowNotes]=\"false\">\n </app-report-component-note>\n <!-- The params are seeded before the first render, so the grid's first read\n carries the tile's report filters. -->\n @if (params(); as params) {\n <fs-grid\n class=\"fs-flex\"\n [source]=\"source()\"\n [layout]=\"layout()\"\n [expansion]=\"expansion()\"\n [clearedFilter]=\"clearedFilter()\"\n (expansionChange)=\"setExpansion($event)\"\n [params]=\"params\"\n [controls]=\"controls()\"\n [formatter]=\"formatter()\"\n (layoutChange)=\"setLayout($event)\">\n <ng-template fsGridCell let-value let-field=\"field\" let-record=\"record\" let-text=\"text\">\n @if (value | fsReportGridCell: field : record : text : noteData() : formatContext(); as shown) {\n <span [attr.title]=\"shown.title\">{{ shown.text }}</span>\n }\n </ng-template>\n </fs-grid>\n }\n</div>\n", styles: [":host{display:block;height:100%}.grid-pane{height:100%;min-height:0}fs-grid{min-height:0}\n"], dependencies: [{ kind: "component", type: FsGridComponent, selector: "fs-grid", inputs: ["source", "layout", "controls", "params", "expansion", "panel", "editorOpen", "formatter", "clearedFilter"], outputs: ["layoutChange", "expansionChange", "panelChange", "editorOpenChange"] }, { kind: "directive", type: FsGridCellDirective, selector: "[fsGridCell]" }, { kind: "component", type: ComponentNoteComponent, selector: "app-report-component-note", inputs: ["data", "windows", "windowDescriptions", "windowNotes"] }, { kind: "pipe", type: ReportGridCellPipe, name: "fsReportGridCell" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8778
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentGridComponent, isStandalone: true, selector: "app-report-component-grid", inputs: { reportId: { classPropertyName: "reportId", publicName: "reportId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!-- The comparison and window note strip above the table, from the report\n line of the latest read; the windows' descriptions and notes go in each\n column's \"About this column\" instead. -->\n<div class=\"fs-column grid-pane\">\n <app-report-component-note\n [data]=\"noteData()\"\n [windowNotes]=\"false\">\n </app-report-component-note>\n <!-- The params are seeded before the first render, so the grid's first read\n carries the tile's report filters. -->\n @if (params(); as params) {\n <fs-grid\n class=\"fs-flex\"\n [source]=\"source()\"\n [layout]=\"layout()\"\n [expansion]=\"expansion()\"\n [clearedFilter]=\"clearedFilter()\"\n (expansionChange)=\"setExpansion($event)\"\n [params]=\"params\"\n [controls]=\"controls()\"\n [formatter]=\"formatter()\"\n (layoutChange)=\"setLayout($event)\">\n <ng-template fsGridCell let-value let-field=\"field\" let-record=\"record\" let-text=\"text\">\n @if (value | fsReportGridCell: field : record : text : noteData() : formatContext(); as shown) {\n <!-- A cell that says why (a missing or zero prior) opens it on a\n click; no cell carries a native tooltip. -->\n @if (shown.title) {\n <span\n class=\"explained\"\n fsPopover\n trigger=\"click\"\n [template]=\"explanation\"\n [indication]=\"false\"\n [maxWidth]=\"320\">\n {{ shown.text }}\n </span>\n <ng-template #explanation>{{ shown.title }}</ng-template>\n } @else {\n <span>{{ shown.text }}</span>\n }\n }\n </ng-template>\n </fs-grid>\n }\n</div>\n", styles: [":host{display:block;height:100%}.grid-pane{height:100%;min-height:0}fs-grid{min-height:0}.explained{cursor:pointer;text-decoration:underline dotted;text-underline-offset:2px}\n"], dependencies: [{ kind: "component", type: FsGridComponent, selector: "fs-grid", inputs: ["source", "layout", "controls", "params", "expansion", "panel", "editorOpen", "formatter", "clearedFilter"], outputs: ["layoutChange", "expansionChange", "panelChange", "editorOpenChange"] }, { kind: "directive", type: FsGridCellDirective, selector: "[fsGridCell]" }, { kind: "directive", type: FsPopoverDirective, selector: "[fsPopover]", inputs: ["text", "template", "data", "leaveDelay", "showDelay", "maxWidth", "maxHeight", "wrapperClass", "autoShow", "autoClose", "loadingDiameter", "loading", "indication", "position", "theme", "size", "trigger", "enabled", "panel"], outputs: ["closed"], exportAs: ["fsPopover"] }, { kind: "component", type: ComponentNoteComponent, selector: "app-report-component-note", inputs: ["data", "windows", "windowDescriptions", "windowNotes"] }, { kind: "pipe", type: ReportGridCellPipe, name: "fsReportGridCell" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8695
8779
  }
8696
8780
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentGridComponent, decorators: [{
8697
8781
  type: Component,
8698
8782
  args: [{ selector: 'app-report-component-grid', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
8699
8783
  FsGridComponent,
8700
8784
  FsGridCellDirective,
8785
+ FsPopoverDirective,
8701
8786
  ComponentNoteComponent,
8702
8787
  ReportGridCellPipe,
8703
- ], template: "<!-- The comparison and window note strip above the table, from the report\n line of the latest read; the windows' descriptions and notes go in each\n column's \"About this column\" instead. -->\n<div class=\"fs-column grid-pane\">\n <app-report-component-note\n [data]=\"noteData()\"\n [windowNotes]=\"false\">\n </app-report-component-note>\n <!-- The params are seeded before the first render, so the grid's first read\n carries the tile's report filters. -->\n @if (params(); as params) {\n <fs-grid\n class=\"fs-flex\"\n [source]=\"source()\"\n [layout]=\"layout()\"\n [expansion]=\"expansion()\"\n [clearedFilter]=\"clearedFilter()\"\n (expansionChange)=\"setExpansion($event)\"\n [params]=\"params\"\n [controls]=\"controls()\"\n [formatter]=\"formatter()\"\n (layoutChange)=\"setLayout($event)\">\n <ng-template fsGridCell let-value let-field=\"field\" let-record=\"record\" let-text=\"text\">\n @if (value | fsReportGridCell: field : record : text : noteData() : formatContext(); as shown) {\n <span [attr.title]=\"shown.title\">{{ shown.text }}</span>\n }\n </ng-template>\n </fs-grid>\n }\n</div>\n", styles: [":host{display:block;height:100%}.grid-pane{height:100%;min-height:0}fs-grid{min-height:0}\n"] }]
8788
+ ], template: "<!-- The comparison and window note strip above the table, from the report\n line of the latest read; the windows' descriptions and notes go in each\n column's \"About this column\" instead. -->\n<div class=\"fs-column grid-pane\">\n <app-report-component-note\n [data]=\"noteData()\"\n [windowNotes]=\"false\">\n </app-report-component-note>\n <!-- The params are seeded before the first render, so the grid's first read\n carries the tile's report filters. -->\n @if (params(); as params) {\n <fs-grid\n class=\"fs-flex\"\n [source]=\"source()\"\n [layout]=\"layout()\"\n [expansion]=\"expansion()\"\n [clearedFilter]=\"clearedFilter()\"\n (expansionChange)=\"setExpansion($event)\"\n [params]=\"params\"\n [controls]=\"controls()\"\n [formatter]=\"formatter()\"\n (layoutChange)=\"setLayout($event)\">\n <ng-template fsGridCell let-value let-field=\"field\" let-record=\"record\" let-text=\"text\">\n @if (value | fsReportGridCell: field : record : text : noteData() : formatContext(); as shown) {\n <!-- A cell that says why (a missing or zero prior) opens it on a\n click; no cell carries a native tooltip. -->\n @if (shown.title) {\n <span\n class=\"explained\"\n fsPopover\n trigger=\"click\"\n [template]=\"explanation\"\n [indication]=\"false\"\n [maxWidth]=\"320\">\n {{ shown.text }}\n </span>\n <ng-template #explanation>{{ shown.title }}</ng-template>\n } @else {\n <span>{{ shown.text }}</span>\n }\n }\n </ng-template>\n </fs-grid>\n }\n</div>\n", styles: [":host{display:block;height:100%}.grid-pane{height:100%;min-height:0}fs-grid{min-height:0}.explained{cursor:pointer;text-decoration:underline dotted;text-underline-offset:2px}\n"] }]
8704
8789
  }] });
8705
8790
 
8706
8791
  // A KPI's trend over its last periods: a line that stretches to the card's
@@ -14053,7 +14138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
14053
14138
  // in the report's format context, as on screen.
14054
14139
  async function renderChartImage(component, data, width, height, context, pixelRatio = 3) {
14055
14140
  // The same tree-shaken echarts build + 'report' theme the live canvas uses.
14056
- const echarts = (await import('./firestitch-report-echarts-EecIloKo.mjs')).default;
14141
+ const echarts = (await import('./firestitch-report-echarts-DMflI6jp.mjs')).default;
14057
14142
  const host = document.createElement('div');
14058
14143
  host.style.width = `${width}px`;
14059
14144
  host.style.height = `${height}px`;
@@ -17258,7 +17343,7 @@ class ReportComponent {
17258
17343
  ReportExportService,
17259
17344
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily with
17260
17345
  // this route's chunk.
17261
- provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-EecIloKo.mjs').then((module) => module.default) }),
17346
+ provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-DMflI6jp.mjs').then((module) => module.default) }),
17262
17347
  // The bar's date pickers start their weeks on Monday and list the built-in
17263
17348
  // presets; a preset only sets the days.
17264
17349
  provideReportDatePicker(),
@@ -17279,7 +17364,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17279
17364
  ReportExportService,
17280
17365
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily with
17281
17366
  // this route's chunk.
17282
- provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-EecIloKo.mjs').then((module) => module.default) }),
17367
+ provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-DMflI6jp.mjs').then((module) => module.default) }),
17283
17368
  // The bar's date pickers start their weeks on Monday and list the built-in
17284
17369
  // presets; a preset only sets the days.
17285
17370
  provideReportDatePicker(),
@@ -19255,7 +19340,7 @@ class FsAiReportComponent {
19255
19340
  ReportAiChatData,
19256
19341
  { provide: FsAiChatData, useExisting: ReportAiChatData },
19257
19342
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
19258
- provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-EecIloKo.mjs').then((module) => module.default) }),
19343
+ provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-DMflI6jp.mjs').then((module) => module.default) }),
19259
19344
  // The bar's date pickers start their weeks on Monday and list the built-in
19260
19345
  // presets; a preset only sets the days.
19261
19346
  provideReportDatePicker(),
@@ -19279,7 +19364,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19279
19364
  ReportAiChatData,
19280
19365
  { provide: FsAiChatData, useExisting: ReportAiChatData },
19281
19366
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
19282
- provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-EecIloKo.mjs').then((module) => module.default) }),
19367
+ provideEchartsCore({ echarts: () => import('./firestitch-report-echarts-DMflI6jp.mjs').then((module) => module.default) }),
19283
19368
  // The bar's date pickers start their weeks on Monday and list the built-in
19284
19369
  // presets; a preset only sets the days.
19285
19370
  provideReportDatePicker(),
@@ -19319,4 +19404,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19319
19404
  */
19320
19405
 
19321
19406
  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, ReportComponent as c, FsAiReportComponent as d, ReportData as e, ReportService as f, ReportFilterStateService as g, ReportNodeType as h, ReportState as i, ReportValueFormat as j, ReportValueFormula as k, ReportListColumnFormat as l, ReportNumberUnits as m, ReportChartDataLabels as n, ReportChartColor as o, ReportChartLineStyle as p, ReportChartMarkStat as q, ReportChartDateLabel as r, ReportChangePolarity as s };
19322
- //# sourceMappingURL=firestitch-report-firestitch-report-DbdLxQSE.mjs.map
19407
+ //# sourceMappingURL=firestitch-report-firestitch-report-C94rjx24.mjs.map