@firestitch/report 18.11.1 → 18.13.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.
- package/app/reports/components/component-grid/component-grid.component.d.ts +33 -0
- package/app/reports/components/component-grid/report-grid-cell.pipe.d.ts +11 -0
- package/app/reports/components/component-grid/report-grid-formatter.d.ts +9 -0
- package/app/reports/components/report-component/report-component.component.d.ts +0 -1
- package/app/reports/data/report-grid-source.d.ts +22 -0
- package/app/reports/data/report.data.d.ts +3 -1
- package/app/reports/export/report-export-collector.service.d.ts +8 -1
- package/app/reports/export/report-filter-lines.d.ts +2 -0
- package/app/reports/export/report-grid-export.d.ts +20 -0
- package/app/reports/export/report-pdf.service.d.ts +2 -0
- package/app/reports/export/report-pptx.service.d.ts +1 -0
- package/app/reports/group-by.d.ts +3 -0
- package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +2 -0
- package/app/reports/interfaces/report-chat-viewer-tile.interface.d.ts +5 -0
- package/app/reports/interfaces/report-export-snapshot.interface.d.ts +2 -0
- package/app/reports/interfaces/report-grid-config.interface.d.ts +5 -0
- package/app/reports/interfaces/report-grid-line.interface.d.ts +6 -0
- package/app/reports/interfaces/report-grid-params.interface.d.ts +7 -0
- package/app/reports/interfaces/report-grid-report.interface.d.ts +2 -0
- package/app/reports/interfaces/report-grid-session-layout.interface.d.ts +5 -0
- package/app/reports/interfaces/report.interface.d.ts +10 -2
- package/app/reports/report-chat-viewer-state.d.ts +4 -1
- package/app/reports/report-filter-items.d.ts +1 -1
- package/app/reports/report-grid-layout.d.ts +10 -0
- package/app/reports/services/report-filter-state.service.d.ts +13 -0
- package/app/reports/tile-data-state.d.ts +2 -2
- package/esm2022/app/reports/components/component-grid/component-grid.component.mjs +120 -0
- package/esm2022/app/reports/components/component-grid/report-grid-cell.pipe.mjs +41 -0
- package/esm2022/app/reports/components/component-grid/report-grid-formatter.mjs +94 -0
- package/esm2022/app/reports/components/component-text/component-text.component.mjs +1 -1
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +28 -25
- package/esm2022/app/reports/data/report-grid-source.mjs +105 -0
- package/esm2022/app/reports/data/report.data.mjs +15 -4
- package/esm2022/app/reports/export/report-export-collector.service.mjs +72 -7
- package/esm2022/app/reports/export/report-filter-lines.mjs +68 -1
- package/esm2022/app/reports/export/report-grid-export.mjs +48 -0
- package/esm2022/app/reports/export/report-pdf.service.mjs +47 -17
- package/esm2022/app/reports/export/report-pptx.service.mjs +48 -4
- package/esm2022/app/reports/group-by.mjs +13 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-chat-viewer-tile.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-export-snapshot.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-grid-config.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-grid-line.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-grid-params.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-grid-report.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-grid-session-layout.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
- package/esm2022/app/reports/report-chat-viewer-state.mjs +21 -6
- package/esm2022/app/reports/report-filter-items.mjs +9 -7
- package/esm2022/app/reports/report-grid-layout.mjs +67 -0
- package/esm2022/app/reports/report-tile.mjs +5 -5
- package/esm2022/app/reports/services/report-filter-state.service.mjs +170 -18
- package/esm2022/app/reports/tile-data-state.mjs +12 -17
- package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +8 -4
- package/esm2022/app/reports/views/report/report.component.mjs +2 -2
- package/fesm2022/{firestitch-report-echarts-B0RWUjR8.mjs → firestitch-report-echarts-EecIloKo.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-B0RWUjR8.mjs.map → firestitch-report-echarts-EecIloKo.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-CJW0lLdW.mjs → firestitch-report-firestitch-report-DbdLxQSE.mjs} +945 -109
- package/fesm2022/firestitch-report-firestitch-report-DbdLxQSE.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +4 -2
- package/fesm2022/firestitch-report-firestitch-report-CJW0lLdW.mjs.map +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { OnInit } from '@angular/core';
|
|
2
|
+
import { GridExpansion, GridLayout } from '@firestitch/grid';
|
|
3
|
+
import { ReportGridSource } from '../../data/report-grid-source';
|
|
4
|
+
import { ReportGridParams } from '../../interfaces/report-grid-params.interface';
|
|
5
|
+
import { ReportComponent } from '../../interfaces/report.interface';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export declare class ComponentGridComponent implements OnInit {
|
|
8
|
+
readonly reportId: import("@angular/core").InputSignal<number>;
|
|
9
|
+
readonly component: import("@angular/core").InputSignal<ReportComponent>;
|
|
10
|
+
readonly params: import("@angular/core").WritableSignal<ReportGridParams>;
|
|
11
|
+
readonly controls: import("@angular/core").Signal<import("@firestitch/grid").GridControls>;
|
|
12
|
+
readonly source: import("@angular/core").Signal<ReportGridSource>;
|
|
13
|
+
readonly layout: import("@angular/core").Signal<GridLayout>;
|
|
14
|
+
readonly clearedFilter: import("@angular/core").Signal<import("@firestitch/grid").GridClearedFilter>;
|
|
15
|
+
readonly expansion: import("@angular/core").WritableSignal<GridExpansion>;
|
|
16
|
+
readonly noteData: import("@angular/core").Signal<import("../../interfaces/report-grid-report.interface").ReportGridReport>;
|
|
17
|
+
readonly formatContext: import("@angular/core").Signal<import("../../interfaces/report.interface").ReportFormatContext>;
|
|
18
|
+
readonly formatter: import("@angular/core").Signal<import("@firestitch/grid").GridFormatter>;
|
|
19
|
+
private readonly _componentId;
|
|
20
|
+
private _reportData;
|
|
21
|
+
private _filterState;
|
|
22
|
+
private _destroyRef;
|
|
23
|
+
private _paramsVersion;
|
|
24
|
+
ngOnInit(): void;
|
|
25
|
+
setLayout(layout: GridLayout): void;
|
|
26
|
+
setExpansion(expansion: GridExpansion | undefined): void;
|
|
27
|
+
private _init;
|
|
28
|
+
private _settled$;
|
|
29
|
+
private _applyParams;
|
|
30
|
+
private _readParams;
|
|
31
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ComponentGridComponent, never>;
|
|
32
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ComponentGridComponent, "app-report-component-grid", never, { "reportId": { "alias": "reportId"; "required": true; "isSignal": true; }; "component": { "alias": "component"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PipeTransform } from '@angular/core';
|
|
2
|
+
import { GridField } from '@firestitch/grid';
|
|
3
|
+
import { FormattedOutputValue } from '../../format';
|
|
4
|
+
import { ReportGridReport } from '../../interfaces/report-grid-report.interface';
|
|
5
|
+
import { ReportFormatContext } from '../../interfaces/report.interface';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export declare class ReportGridCellPipe implements PipeTransform {
|
|
8
|
+
transform(value: unknown, field: GridField | null, record: Record<string, unknown> | undefined, text: string, report: ReportGridReport | null, format: ReportFormatContext): FormattedOutputValue;
|
|
9
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ReportGridCellPipe, never>;
|
|
10
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<ReportGridCellPipe, "fsReportGridCell", true>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GridFormatter } from '@firestitch/grid';
|
|
2
|
+
import { ReportGridReport } from '../../interfaces/report-grid-report.interface';
|
|
3
|
+
import { ReportFormatContext } from '../../interfaces/report.interface';
|
|
4
|
+
export interface ReportGridFormatContext {
|
|
5
|
+
format: ReportFormatContext;
|
|
6
|
+
timezone: string;
|
|
7
|
+
report: ReportGridReport | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function reportGridFormatter(context: ReportGridFormatContext): GridFormatter;
|
|
@@ -102,7 +102,6 @@ export declare class ReportComponentComponent implements OnInit, OnChanges {
|
|
|
102
102
|
private _origin;
|
|
103
103
|
private _track;
|
|
104
104
|
private _emitGeometry;
|
|
105
|
-
private get _isTimeSeries();
|
|
106
105
|
private get _heightAuto();
|
|
107
106
|
get heightAuto(): boolean;
|
|
108
107
|
private _inches;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { GridParams, GridRequest, GridResult, GridSource } from '@firestitch/grid';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { ReportGridReport } from '../interfaces/report-grid-report.interface';
|
|
4
|
+
import { ReportLocaleTag } from '../interfaces/report.interface';
|
|
5
|
+
import { ReportData } from './report.data';
|
|
6
|
+
export interface ReportGridSourceOptions {
|
|
7
|
+
isExport?: boolean;
|
|
8
|
+
locale?: () => ReportLocaleTag;
|
|
9
|
+
}
|
|
10
|
+
export declare class ReportGridSource implements GridSource {
|
|
11
|
+
private readonly _reportData;
|
|
12
|
+
private readonly _reportId;
|
|
13
|
+
private readonly _componentId;
|
|
14
|
+
readonly report: import("@angular/core").WritableSignal<ReportGridReport>;
|
|
15
|
+
private readonly _isExport;
|
|
16
|
+
private readonly _locale;
|
|
17
|
+
constructor(_reportData: ReportData, _reportId: number, _componentId: number, options?: ReportGridSourceOptions);
|
|
18
|
+
read(request: GridRequest, params: GridParams): Observable<GridResult>;
|
|
19
|
+
private _stream$;
|
|
20
|
+
private _part$;
|
|
21
|
+
private _described;
|
|
22
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { RequestConfig } from '@firestitch/api';
|
|
1
|
+
import { RequestConfig, StreamEvent } from '@firestitch/api';
|
|
2
|
+
import { GridRequest } from '@firestitch/grid';
|
|
2
3
|
import { Observable } from 'rxjs';
|
|
3
4
|
import { ReportExportLine } from '../interfaces/report-export-line.interface';
|
|
4
5
|
import { ReportFilterGroupChanges } from '../interfaces/report-filter-group-changes.interface';
|
|
@@ -54,6 +55,7 @@ export declare class ReportData<T = any> {
|
|
|
54
55
|
h: number;
|
|
55
56
|
}>)[], config?: RequestConfig): Observable<T>;
|
|
56
57
|
componentData(reportId: number, componentId: number, filters?: ResolvedFilterValue[], state?: ComponentDataState, isExport?: boolean, config?: RequestConfig): Observable<T>;
|
|
58
|
+
componentGrid(reportId: number, componentId: number, filters: ResolvedFilterValue[], state: ComponentDataState, grid: GridRequest, isExport?: boolean, config?: RequestConfig): Observable<StreamEvent>;
|
|
57
59
|
pageValues(reportId: number, pageId: number, filters?: ResolvedFilterValue[], isExport?: boolean, config?: RequestConfig, matchAnyGroupIds?: number[]): Observable<ReportPageValue[]>;
|
|
58
60
|
exportComponent(reportId: number, componentId: number, filters?: ResolvedFilterValue[], state?: ComponentDataState, title?: string, config?: RequestConfig): Observable<ComponentExportResponse>;
|
|
59
61
|
exportReport(reportId: number, filters?: ResolvedFilterValue[], pageId?: number | null, frequency?: ChartGranularity | null, filterLines?: ReportExportLine[], states?: Record<number, ComponentDataState>, titles?: Record<number, string>, config?: RequestConfig): Observable<T>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridTable } from '@firestitch/grid';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
3
|
import { ReportExportLine } from '../interfaces/report-export-line.interface';
|
|
3
4
|
import { ReportExportSnapshot } from '../interfaces/report-export-snapshot.interface';
|
|
@@ -12,6 +13,9 @@ export interface CollectedComponent {
|
|
|
12
13
|
search?: string;
|
|
13
14
|
hiddenColumns: string[];
|
|
14
15
|
crumbs?: string[];
|
|
16
|
+
table?: GridTable;
|
|
17
|
+
tableNotes?: string[];
|
|
18
|
+
filtered?: boolean;
|
|
15
19
|
}
|
|
16
20
|
export interface CollectedPage {
|
|
17
21
|
page: ReportPage;
|
|
@@ -67,7 +71,7 @@ export interface KpiExportParts {
|
|
|
67
71
|
}
|
|
68
72
|
export declare const HEADER_FOOTER_NAME = "Header & footer";
|
|
69
73
|
export declare function emptyLabel(item: CollectedComponent): string;
|
|
70
|
-
export declare function exportTitle(component: ReportComponent, tokens: TextTokenContext, search?: string | null, crumbs?: readonly string[] | null): string;
|
|
74
|
+
export declare function exportTitle(component: ReportComponent, tokens: TextTokenContext, search?: string | null, crumbs?: readonly string[] | null, filtered?: boolean): string;
|
|
71
75
|
export declare function isFailed(item: CollectedComponent): boolean;
|
|
72
76
|
export declare function textOverflow(component: ReportComponent, page: string, tokens: TextTokenContext): TextOverflow;
|
|
73
77
|
export declare function coverLines(collected: CollectedReport): string[];
|
|
@@ -79,6 +83,7 @@ export declare function listHeadings(component: ReportComponent, data: Component
|
|
|
79
83
|
export declare function listTotalsRow(data: ComponentData, columns: readonly ExportListColumn[], timezone: string, context: ReportFormatContext): string[] | null;
|
|
80
84
|
export declare function exportWindowsLine(item: CollectedComponent, timezone: string, locale: ReportLocaleTag): string;
|
|
81
85
|
export declare function exportNoteLines(item: CollectedComponent, timezone: string, locale: ReportLocaleTag): string[];
|
|
86
|
+
export declare function isEmptyTile(item: CollectedComponent): boolean;
|
|
82
87
|
export declare function kpiCardHasExtras(view: KpiCardView, notes: readonly string[]): boolean;
|
|
83
88
|
export declare function kpiExportParts(view: KpiCardView, notes: readonly string[], available: number, heights: KpiExportHeights): KpiExportParts;
|
|
84
89
|
export declare function scaledKpiHeights(heights: KpiExportHeights, scale: number): KpiExportHeights;
|
|
@@ -99,6 +104,8 @@ export declare class ReportExportCollectorService {
|
|
|
99
104
|
private _valuesJobs;
|
|
100
105
|
private _runJob;
|
|
101
106
|
private _componentData;
|
|
107
|
+
private _tileState;
|
|
108
|
+
private _gridTable;
|
|
102
109
|
private _collected;
|
|
103
110
|
private _groupValues;
|
|
104
111
|
private _pageValues;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridField, GridFilter } from '@firestitch/grid';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
3
|
import { ReportDrillStep } from '../interfaces/report-drill-step.interface';
|
|
3
4
|
import { ReportExportLine } from '../interfaces/report-export-line.interface';
|
|
@@ -17,3 +18,4 @@ export declare function matchLineText(match: ReportFilterMatch | null | undefine
|
|
|
17
18
|
export declare function drillLineText(component: Pick<ReportComponent, 'title'>, path: readonly ReportDrillStep[], formatContext: Pick<ReportFormatContext, 'locale'>): string;
|
|
18
19
|
export declare function exportLines(input: ReportExportLinesInput): Observable<ReportExportLine[]>;
|
|
19
20
|
export declare function exportGroups(report: Report, pageId: number | null): ReportFilterGroup[];
|
|
21
|
+
export declare function gridFilterLineText(label: string, filter: GridFilter, field: GridField | undefined, locale: ReportFormatContext['locale']): string | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { GridLayout, GridTable } from '@firestitch/grid';
|
|
2
|
+
import { ReportFormatContext } from '../interfaces/report.interface';
|
|
3
|
+
export declare const GRID_EXPORT_COLUMNS = 60;
|
|
4
|
+
export interface GridExportCell {
|
|
5
|
+
text: string;
|
|
6
|
+
colSpan: number;
|
|
7
|
+
rowSpan: number;
|
|
8
|
+
bold: boolean;
|
|
9
|
+
indent: number;
|
|
10
|
+
numeric: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface GridExportTable {
|
|
13
|
+
head: GridExportCell[][];
|
|
14
|
+
body: GridExportCell[][];
|
|
15
|
+
foot: GridExportCell[] | null;
|
|
16
|
+
numeric: boolean[];
|
|
17
|
+
moreRows: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function gridExportTable(table: GridTable): GridExportTable;
|
|
20
|
+
export declare function gridExportNotes(table: GridTable, layout: GridLayout, locale: ReportFormatContext['locale']): string[];
|
|
@@ -3,6 +3,7 @@ import { ReportChatViewerDetail } from './report-chat-viewer-detail.interface';
|
|
|
3
3
|
import { ReportChatViewerDrill } from './report-chat-viewer-drill.interface';
|
|
4
4
|
import { ReportChatViewerFilter } from './report-chat-viewer-filter.interface';
|
|
5
5
|
import { ReportChatViewerSelection } from './report-chat-viewer-selection.interface';
|
|
6
|
+
import { ReportChatViewerTile } from './report-chat-viewer-tile.interface';
|
|
6
7
|
import { ReportFilterMatch } from './report-filter-match.type';
|
|
7
8
|
import { ChartGranularity } from './report.interface';
|
|
8
9
|
export interface ReportChatViewerState {
|
|
@@ -13,5 +14,6 @@ export interface ReportChatViewerState {
|
|
|
13
14
|
crossFilters?: ReportChatViewerCrossFilter[];
|
|
14
15
|
drills?: ReportChatViewerDrill[];
|
|
15
16
|
detail?: ReportChatViewerDetail | null;
|
|
17
|
+
tiles?: ReportChatViewerTile[];
|
|
16
18
|
selection?: ReportChatViewerSelection;
|
|
17
19
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridExpansion } from '@firestitch/grid';
|
|
1
2
|
import { ReportStateSnapshot } from './report-state-snapshot.interface';
|
|
2
3
|
import { ReportViewerFeature } from './report-viewer-feature.type';
|
|
3
4
|
import { ChartGranularity, ComponentDataState, FilterGroupValue, ReportFormatContext, ReportRelativeRange, ResolvedFilterValue } from './report.interface';
|
|
@@ -8,6 +9,7 @@ export interface ReportExportSnapshot {
|
|
|
8
9
|
filters: Record<number, ResolvedFilterValue[]>;
|
|
9
10
|
valueFilters: Record<number, ResolvedFilterValue[]>;
|
|
10
11
|
states: Record<number, ComponentDataState>;
|
|
12
|
+
gridExpansions?: Record<number, GridExpansion>;
|
|
11
13
|
frequency: ChartGranularity | null;
|
|
12
14
|
features: ReportViewerFeature[];
|
|
13
15
|
formatContext: ReportFormatContext;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GridParams } from '@firestitch/grid';
|
|
2
|
+
import { ChartGranularity, ResolvedFilterValue } from './report.interface';
|
|
3
|
+
export interface ReportGridParams extends GridParams {
|
|
4
|
+
filters: ResolvedFilterValue[];
|
|
5
|
+
matchAnyGroupIds?: number[];
|
|
6
|
+
frequency?: ChartGranularity;
|
|
7
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridLayout } from '@firestitch/grid';
|
|
1
2
|
import { ReportChangePolarity } from '../enums/report-change-polarity.enum';
|
|
2
3
|
import { ReportChartColor } from '../enums/report-chart-color.enum';
|
|
3
4
|
import { ReportChartDataLabels } from '../enums/report-chart-data-labels.enum';
|
|
@@ -11,6 +12,7 @@ import { ReportValueFormula } from '../enums/report-value-formula.enum';
|
|
|
11
12
|
import { ComponentDataApplied } from './component-data-applied.interface';
|
|
12
13
|
import { ComponentDataDrill } from './component-data-drill.interface';
|
|
13
14
|
import { ReportDrillStep } from './report-drill-step.interface';
|
|
15
|
+
import { GridConfig } from './report-grid-config.interface';
|
|
14
16
|
import { ReportViewerFeature } from './report-viewer-feature.type';
|
|
15
17
|
export type ReportLocaleTag = string;
|
|
16
18
|
export type ReportCurrencyCode = string;
|
|
@@ -84,7 +86,7 @@ export interface ReportPage {
|
|
|
84
86
|
components: ReportComponent[];
|
|
85
87
|
values?: ReportComponent[];
|
|
86
88
|
}
|
|
87
|
-
export type ReportComponentType = 'chart' | 'list' | 'kpi' | 'text' | 'value';
|
|
89
|
+
export type ReportComponentType = 'chart' | 'list' | 'grid' | 'kpi' | 'text' | 'value';
|
|
88
90
|
export interface ReportComponent {
|
|
89
91
|
id: number;
|
|
90
92
|
type: ReportComponentType;
|
|
@@ -95,8 +97,13 @@ export interface ReportComponent {
|
|
|
95
97
|
h: number;
|
|
96
98
|
autoHeight: boolean;
|
|
97
99
|
sql: string | null;
|
|
98
|
-
config: ChartConfig & ListConfig & KpiConfig & TextConfig & ValueConfig & ComponentLayoutConfig & Record<string, unknown>;
|
|
100
|
+
config: ChartConfig & ListConfig & GridConfig & KpiConfig & TextConfig & ValueConfig & ComponentLayoutConfig & Record<string, unknown>;
|
|
99
101
|
filters: ReportFilter[];
|
|
102
|
+
followsGroupBy?: ReportGroupByField | null;
|
|
103
|
+
}
|
|
104
|
+
export interface ReportGroupByField {
|
|
105
|
+
field: string;
|
|
106
|
+
granularity: ChartGranularity | null;
|
|
100
107
|
}
|
|
101
108
|
export interface ReportComponentSql {
|
|
102
109
|
sql: string | null;
|
|
@@ -323,6 +330,7 @@ export interface ComponentDataState {
|
|
|
323
330
|
hiddenColumns?: string[];
|
|
324
331
|
drill?: ReportDrillStep[];
|
|
325
332
|
matchAnyGroupIds?: number[];
|
|
333
|
+
layout?: GridLayout;
|
|
326
334
|
unchangedIfUnreached?: true;
|
|
327
335
|
}
|
|
328
336
|
export interface ComponentData {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { GridLayout } from '@firestitch/grid';
|
|
1
2
|
import { ReportChatViewerDrill } from './interfaces/report-chat-viewer-drill.interface';
|
|
2
3
|
import { ReportChatViewerState } from './interfaces/report-chat-viewer-state.interface';
|
|
4
|
+
import { ReportChatViewerTile } from './interfaces/report-chat-viewer-tile.interface';
|
|
3
5
|
import { ReportStateSnapshot } from './interfaces/report-state-snapshot.interface';
|
|
4
|
-
import { ReportLocaleTag } from './interfaces/report.interface';
|
|
6
|
+
import { Report, ReportComponent, ReportLocaleTag } from './interfaces/report.interface';
|
|
5
7
|
export declare const CHAT_DRILLS_MAX = 10;
|
|
6
8
|
export declare const CHAT_LABEL_MAX = 100;
|
|
7
9
|
export declare function chatViewerMatch(snapshot: ReportStateSnapshot): Pick<ReportChatViewerState, 'match'>;
|
|
8
10
|
export declare function chatViewerDrills(snapshot: ReportStateSnapshot, locale: ReportLocaleTag): ReportChatViewerDrill[];
|
|
11
|
+
export declare function chatViewerTiles(report: Report | null, pageId: number | null, layoutOf: (component: ReportComponent) => GridLayout | null): ReportChatViewerTile[];
|
|
@@ -39,7 +39,7 @@ export declare function matchFromQuery(query: Record<string, unknown>): ReportFi
|
|
|
39
39
|
export declare const LIST_SEARCH_ITEM = "listSearch";
|
|
40
40
|
export declare const LIST_SEARCH_MAX_LENGTH = 100;
|
|
41
41
|
export declare function listSearchItem(value: string | null): IFilterConfigItem;
|
|
42
|
-
export declare function
|
|
42
|
+
export declare function hasGroupByTile(report: Report | null): boolean;
|
|
43
43
|
export declare function isGranularityOffered(report: Report, granularity: ChartGranularity | null): boolean;
|
|
44
44
|
export declare function groupByFilterItem(report: Report, initial?: ChartGranularity | null): IFilterConfigItem | null;
|
|
45
45
|
export declare function groupBySignature(report: Report | null): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GridClearedFilter, GridGranularity, GridLayout } from '@firestitch/grid';
|
|
2
|
+
import { ChartGranularity, ReportComponent } from './interfaces/report.interface';
|
|
3
|
+
export declare const GRID_GRANULARITIES: Record<ChartGranularity, GridGranularity>;
|
|
4
|
+
export declare function authoredGridLayout(component: ReportComponent): GridLayout;
|
|
5
|
+
export declare function gridLayoutKey(layout: GridLayout): string;
|
|
6
|
+
export declare function rebasedGridLayout(session: GridLayout, base: string, authored: GridLayout): GridLayout;
|
|
7
|
+
export declare function grainedGridLayout(layout: GridLayout, field: string, granularity: ChartGranularity): {
|
|
8
|
+
layout: GridLayout;
|
|
9
|
+
cleared: GridClearedFilter | null;
|
|
10
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridClearedFilter, GridExpansion, GridLayout } from '@firestitch/grid';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
3
|
import { ReportChatViewerFilter } from '../interfaces/report-chat-viewer-filter.interface';
|
|
3
4
|
import { ReportDrillStep } from '../interfaces/report-drill-step.interface';
|
|
@@ -49,6 +50,9 @@ export declare class ReportFilterStateService {
|
|
|
49
50
|
private _match;
|
|
50
51
|
private _drills;
|
|
51
52
|
private _drillChanged$;
|
|
53
|
+
private _gridLayouts;
|
|
54
|
+
private _gridExpansions;
|
|
55
|
+
private _gridClearedFilters;
|
|
52
56
|
private _temporary;
|
|
53
57
|
init(report: Report): void;
|
|
54
58
|
value(groupId: number): FilterGroupValue | undefined;
|
|
@@ -82,6 +86,12 @@ export declare class ReportFilterStateService {
|
|
|
82
86
|
setDrill(componentId: number, path: readonly ReportDrillStep[]): void;
|
|
83
87
|
drillChanges(componentId: number): Observable<void>;
|
|
84
88
|
adoptDrill(componentId: number, path: readonly ReportDrillStep[]): boolean;
|
|
89
|
+
gridLayout(component: ReportComponent): GridLayout;
|
|
90
|
+
gridSessionLayout(component: ReportComponent): GridLayout | null;
|
|
91
|
+
setGridLayout(component: ReportComponent, layout: GridLayout): void;
|
|
92
|
+
gridClearedFilter(component: ReportComponent): GridClearedFilter | null;
|
|
93
|
+
gridExpansion(component: ReportComponent): GridExpansion | undefined;
|
|
94
|
+
setGridExpansion(component: ReportComponent, expansion: GridExpansion | undefined): void;
|
|
85
95
|
snapshot(): ReportStateSnapshot;
|
|
86
96
|
authoredConfig(): ReportStateSnapshot;
|
|
87
97
|
resetToDefaults(): void;
|
|
@@ -103,10 +113,13 @@ export declare class ReportFilterStateService {
|
|
|
103
113
|
private _snapshotTiles;
|
|
104
114
|
private _seedAuthored;
|
|
105
115
|
private _clearTiles;
|
|
116
|
+
private _putGridLayout;
|
|
117
|
+
private _grainGridLayouts;
|
|
106
118
|
private _setDrillPath;
|
|
107
119
|
private _notifyReset;
|
|
108
120
|
private _tiles;
|
|
109
121
|
private _isChart;
|
|
122
|
+
private _pruneGridLayouts;
|
|
110
123
|
private _prunePageState;
|
|
111
124
|
private _resolveExcludeAndRange;
|
|
112
125
|
private _excludeOrRangeDefault;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { GridLayout } from '@firestitch/grid';
|
|
1
2
|
import { ReportStateSnapshot } from './interfaces/report-state-snapshot.interface';
|
|
2
3
|
import { ComponentDataState, Report, ReportComponent } from './interfaces/report.interface';
|
|
3
|
-
export declare function isTimeSeriesChart(component: ReportComponent): boolean;
|
|
4
4
|
export declare function tileDataState(report: Report | null, component: ReportComponent, snapshot: ReportStateSnapshot): ComponentDataState;
|
|
5
|
-
export declare function zipExportStates(report: Report, snapshot: ReportStateSnapshot, pageId?: number | null): Record<number, ComponentDataState>;
|
|
5
|
+
export declare function zipExportStates(report: Report, snapshot: ReportStateSnapshot, pageId?: number | null, gridLayout?: (component: ReportComponent) => GridLayout | null): Record<number, ComponentDataState>;
|
|
6
6
|
export declare function valuesMatchAnyGroupIds(report: Report | null, layerId: number | null, snapshot: ReportStateSnapshot): number[];
|
|
7
7
|
export declare function tilePageId(report: Report, component: ReportComponent, snapshot: ReportStateSnapshot): number | null;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, computed, inject, input, signal, } from '@angular/core';
|
|
2
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
3
|
+
import { FsGridCellDirective, FsGridComponent } from '@firestitch/grid';
|
|
4
|
+
import { filter, map, of, switchMap, tap, timer } from 'rxjs';
|
|
5
|
+
import { ReportData } from '../../data/report.data';
|
|
6
|
+
import { ReportGridSource } from '../../data/report-grid-source';
|
|
7
|
+
import { followsGroupBy } from '../../group-by';
|
|
8
|
+
import { ReportFilterStateService } from '../../services/report-filter-state.service';
|
|
9
|
+
import { TILE_REFRESH_DEBOUNCE_MS } from '../../tile-loads';
|
|
10
|
+
import { ComponentNoteComponent } from '../component-note/component-note.component';
|
|
11
|
+
import { ReportGridCellPipe } from './report-grid-cell.pipe';
|
|
12
|
+
import { reportGridFormatter } from './report-grid-formatter';
|
|
13
|
+
import * as i0 from "@angular/core";
|
|
14
|
+
// A grid tile: fs-grid over the tile's rows, read through ReportGridSource.
|
|
15
|
+
//
|
|
16
|
+
// - The params (the report filters the tile resolves to and the 'any'
|
|
17
|
+
// groups) are seeded before the first render, so no read goes out without
|
|
18
|
+
// them. After that a change to one of the tile's filter groups settles for
|
|
19
|
+
// TILE_REFRESH_DEBOUNCE_MS, so a sweep of changes costs one read; one sent
|
|
20
|
+
// under an older state version is dropped.
|
|
21
|
+
// - The layout on screen is the state service's (gridLayout): the viewer's
|
|
22
|
+
// own while they changed it from the layout authored now, else the
|
|
23
|
+
// authored one. It outlives a page switch, and the chat reads it. So do
|
|
24
|
+
// the groups the viewer left open (gridExpansion), which a Clear leaves.
|
|
25
|
+
// - A state version move (Clear filters, a saved filter) skips the wait; the
|
|
26
|
+
// reset has put the authored layout back in the same tick, so it costs one
|
|
27
|
+
// read.
|
|
28
|
+
// - A table that follows the report's group-by (followsGroupBy) sends its
|
|
29
|
+
// grain, and reads again at once when it changes. The state service has
|
|
30
|
+
// moved its filter on the group-by's field to the new grain by then, or
|
|
31
|
+
// taken it out (clearedFilter, which the status line names), so one read
|
|
32
|
+
// goes out and nothing paints unfiltered.
|
|
33
|
+
// - fs-grid compares the layout and params by value: a cloned value never
|
|
34
|
+
// reads again.
|
|
35
|
+
// - An output's detail cell is drawn by fsReportGridCell, so a change tells
|
|
36
|
+
// a missing prior from a zero one and says why on hover, as a list does.
|
|
37
|
+
export class ComponentGridComponent {
|
|
38
|
+
reportId = input.required();
|
|
39
|
+
component = input.required();
|
|
40
|
+
params = signal(null);
|
|
41
|
+
controls = computed(() => this.component().config?.controls ?? {});
|
|
42
|
+
source = computed(() => new ReportGridSource(this._reportData, this.reportId(), this._componentId(), {
|
|
43
|
+
locale: () => this._filterState.formatContext().locale,
|
|
44
|
+
}));
|
|
45
|
+
layout = computed(() => this._filterState.gridLayout(this.component()));
|
|
46
|
+
clearedFilter = computed(() => this._filterState.gridClearedFilter(this.component()));
|
|
47
|
+
// Read once: fs-grid owns the open groups from then on and writes them out.
|
|
48
|
+
expansion = signal(undefined);
|
|
49
|
+
noteData = computed(() => this.source().report());
|
|
50
|
+
formatContext = computed(() => this._filterState.formatContext());
|
|
51
|
+
formatter = computed(() => reportGridFormatter({
|
|
52
|
+
format: this._filterState.formatContext(),
|
|
53
|
+
timezone: this._filterState.timezone(),
|
|
54
|
+
report: this.source().report(),
|
|
55
|
+
}));
|
|
56
|
+
_componentId = computed(() => this.component().id);
|
|
57
|
+
_reportData = inject(ReportData);
|
|
58
|
+
_filterState = inject(ReportFilterStateService);
|
|
59
|
+
_destroyRef = inject(DestroyRef);
|
|
60
|
+
// The state version the params on screen were read under.
|
|
61
|
+
_paramsVersion = 0;
|
|
62
|
+
ngOnInit() {
|
|
63
|
+
this.expansion.set(this._filterState.gridExpansion(this.component()));
|
|
64
|
+
this._init();
|
|
65
|
+
}
|
|
66
|
+
setLayout(layout) {
|
|
67
|
+
this._filterState.setGridLayout(this.component(), layout);
|
|
68
|
+
}
|
|
69
|
+
setExpansion(expansion) {
|
|
70
|
+
this._filterState.setGridExpansion(this.component(), expansion);
|
|
71
|
+
}
|
|
72
|
+
_init() {
|
|
73
|
+
this._paramsVersion = this._filterState.stateVersion();
|
|
74
|
+
this.params.set(this._readParams());
|
|
75
|
+
this._filterState.changesFor(this.component())
|
|
76
|
+
.pipe(switchMap(() => this._settled$()), tap(() => this._applyParams()), takeUntilDestroyed(this._destroyRef))
|
|
77
|
+
.subscribe();
|
|
78
|
+
if (followsGroupBy(this.component())) {
|
|
79
|
+
this._filterState.frequencyChanges()
|
|
80
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
81
|
+
.subscribe(() => this._applyParams());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// A change, once it has settled: at once when the state version moved,
|
|
85
|
+
// else after the debounce; dropped when the version moves while it waits,
|
|
86
|
+
// since that move brings its own change.
|
|
87
|
+
_settled$() {
|
|
88
|
+
const version = this._filterState.stateVersion();
|
|
89
|
+
const moved = version !== this._paramsVersion;
|
|
90
|
+
return (moved ? of(0) : timer(TILE_REFRESH_DEBOUNCE_MS))
|
|
91
|
+
.pipe(filter(() => this._filterState.stateVersion() === version), map(() => undefined));
|
|
92
|
+
}
|
|
93
|
+
_applyParams() {
|
|
94
|
+
this._paramsVersion = this._filterState.stateVersion();
|
|
95
|
+
this.params.set(this._readParams());
|
|
96
|
+
}
|
|
97
|
+
// The tile's report filters, 'any' groups and group-by grain as they stand
|
|
98
|
+
// (tileState()).
|
|
99
|
+
_readParams() {
|
|
100
|
+
const component = this.component();
|
|
101
|
+
const { matchAnyGroupIds, frequency } = this._filterState.tileState(component);
|
|
102
|
+
return {
|
|
103
|
+
filters: this._filterState.resolveForComponent(component),
|
|
104
|
+
...(matchAnyGroupIds?.length ? { matchAnyGroupIds } : {}),
|
|
105
|
+
...(frequency ? { frequency } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
109
|
+
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 });
|
|
110
|
+
}
|
|
111
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentGridComponent, decorators: [{
|
|
112
|
+
type: Component,
|
|
113
|
+
args: [{ selector: 'app-report-component-grid', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
114
|
+
FsGridComponent,
|
|
115
|
+
FsGridCellDirective,
|
|
116
|
+
ComponentNoteComponent,
|
|
117
|
+
ReportGridCellPipe,
|
|
118
|
+
], 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"] }]
|
|
119
|
+
}] });
|
|
120
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LWdyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWdyaWQvY29tcG9uZW50LWdyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWdyaWQvY29tcG9uZW50LWdyaWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQVUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxHQUN4RixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVoRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsZUFBZSxFQUE2QixNQUFNLGtCQUFrQixDQUFDO0FBRW5HLE9BQU8sRUFBYyxNQUFNLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUUxRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDakUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR2hELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQ3RGLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRXBGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdELE9BQU8s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QUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ3BDLENBQUM7SUFDSixDQUFDO3dHQTdGVSxzQkFBc0I7NEZBQXRCLHNCQUFzQixvV0MxRG5DLHlzQ0E4QkEscUpEc0JJLGVBQWUsMlBBQ2YsbUJBQW1CLHlEQUNuQixzQkFBc0IsbUlBQ3RCLGtCQUFrQjs7NEZBR1Qsc0JBQXNCO2tCQWJsQyxTQUFTOytCQUNFLDJCQUEyQixtQkFHcEIsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJLFdBQ1A7d0JBQ1AsZUFBZTt3QkFDZixtQkFBbUI7d0JBQ25CLHNCQUFzQjt3QkFDdEIsa0JBQWtCO3FCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIERlc3Ryb3lSZWYsIE9uSW5pdCwgY29tcHV0ZWQsIGluamVjdCwgaW5wdXQsIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IEZzR3JpZENlbGxEaXJlY3RpdmUsIEZzR3JpZENvbXBvbmVudCwgR3JpZEV4cGFuc2lvbiwgR3JpZExheW91dCB9IGZyb20gJ0BmaXJlc3RpdGNoL2dyaWQnO1xuXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmaWx0ZXIsIG1hcCwgb2YsIHN3aXRjaE1hcCwgdGFwLCB0aW1lciB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBSZXBvcnRHcmlkU291cmNlIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQtZ3JpZC1zb3VyY2UnO1xuaW1wb3J0IHsgZm9sbG93c0dyb3VwQnkgfSBmcm9tICcuLi8uLi9ncm91cC1ieSc7XG5pbXBvcnQgeyBSZXBvcnRHcmlkUGFyYW1zIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9yZXBvcnQtZ3JpZC1wYXJhbXMuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydENvbXBvbmVudCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRGaWx0ZXJTdGF0ZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9yZXBvcnQtZmlsdGVyLXN0YXRlLnNlcnZpY2UnO1xuaW1wb3J0IHsgVElMRV9SRUZSRVNIX0RFQk9VTkNFX01TIH0gZnJvbSAnLi4vLi4vdGlsZS1sb2Fkcyc7XG5pbXBvcnQgeyBDb21wb25lbnROb3RlQ29tcG9uZW50IH0gZnJvbSAnLi4vY29tcG9uZW50LW5vdGUvY29tcG9uZW50LW5vdGUuY29tcG9uZW50JztcblxuaW1wb3J0IHsgUmVwb3J0R3JpZENlbGxQaXBlIH0gZnJvbSAnLi9yZXBvcnQtZ3JpZC1jZWxsLnBpcGUnO1xuaW1wb3J0IHsgcmVwb3J0R3JpZEZvcm1hdHRlciB9IGZyb20gJy4vcmVwb3J0LWdyaWQtZm9ybWF0dGVyJztcblxuXG4vLyBBIGdyaWQgdGlsZTogZnMtZ3JpZCBvdmVyIHRoZSB0aWxlJ3Mgcm93cywgcmVhZCB0aHJvdWdoIFJlcG9ydEdyaWRTb3VyY2UuXG4vL1xuLy8gLSBUaGUgcGFyYW1zICh0aGUgcmVwb3J0IGZpbHRlcnMgdGhlIHRpbGUgcmVzb2x2ZXMgdG8gYW5kIHRoZSAnYW55J1xuLy8gICBncm91cHMpIGFyZSBzZWVkZWQgYmVmb3JlIHRoZSBmaXJzdCByZW5kZXIsIHNvIG5vIHJlYWQgZ29lcyBvdXQgd2l0aG91dFxuLy8gICB0aGVtLiBBZnRlciB0aGF0IGEgY2hhbmdlIHRvIG9uZSBvZiB0aGUgdGlsZSdzIGZpbHRlciBncm91cHMgc2V0dGxlcyBmb3Jcbi8vICAgVElMRV9SRUZSRVNIX0RFQk9VTkNFX01TLCBzbyBhIHN3ZWVwIG9mIGNoYW5nZXMgY29zdHMgb25lIHJlYWQ7IG9uZSBzZW50XG4vLyAgIHVuZGVyIGFuIG9sZGVyIHN0YXRlIHZlcnNpb24gaXMgZHJvcHBlZC5cbi8vIC0gVGhlIGxheW91dCBvbiBzY3JlZW4gaXMgdGhlIHN0YXRlIHNlcnZpY2UncyAoZ3JpZExheW91dCk6IHRoZSB2aWV3ZXInc1xuLy8gICBvd24gd2hpbGUgdGhleSBjaGFuZ2VkIGl0IGZyb20gdGhlIGxheW91dCBhdXRob3JlZCBub3csIGVsc2UgdGhlXG4vLyAgIGF1dGhvcmVkIG9uZS4gSXQgb3V0bGl2ZXMgYSBwYWdlIHN3aXRjaCwgYW5kIHRoZSBjaGF0IHJlYWRzIGl0LiBTbyBkb1xuLy8gICB0aGUgZ3JvdXBzIHRoZSB2aWV3ZXIgbGVmdCBvcGVuIChncmlkRXhwYW5zaW9uKSwgd2hpY2ggYSBDbGVhciBsZWF2ZXMuXG4vLyAtIEEgc3RhdGUgdmVyc2lvbiBtb3ZlIChDbGVhciBmaWx0ZXJzLCBhIHNhdmVkIGZpbHRlcikgc2tpcHMgdGhlIHdhaXQ7IHRoZVxuLy8gICByZXNldCBoYXMgcHV0IHRoZSBhdXRob3JlZCBsYXlvdXQgYmFjayBpbiB0aGUgc2FtZSB0aWNrLCBzbyBpdCBjb3N0cyBvbmVcbi8vICAgcmVhZC5cbi8vIC0gQSB0YWJsZSB0aGF0IGZvbGxvd3MgdGhlIHJlcG9ydCdzIGdyb3VwLWJ5IChmb2xsb3dzR3JvdXBCeSkgc2VuZHMgaXRzXG4vLyAgIGdyYWluLCBhbmQgcmVhZHMgYWdhaW4gYXQgb25jZSB3aGVuIGl0IGNoYW5nZXMuIFRoZSBzdGF0ZSBzZXJ2aWNlIGhhc1xuLy8gICBtb3ZlZCBpdHMgZmlsdGVyIG9uIHRoZSBncm91cC1ieSdzIGZpZWxkIHRvIHRoZSBuZXcgZ3JhaW4gYnkgdGhlbiwgb3Jcbi8vICAgdGFrZW4gaXQgb3V0IChjbGVhcmVkRmlsdGVyLCB3aGljaCB0aGUgc3RhdHVzIGxpbmUgbmFtZXMpLCBzbyBvbmUgcmVhZFxuLy8gICBnb2VzIG91dCBhbmQgbm90aGluZyBwYWludHMgdW5maWx0ZXJlZC5cbi8vIC0gZnMtZ3JpZCBjb21wYXJlcyB0aGUgbGF5b3V0IGFuZCBwYXJhbXMgYnkgdmFsdWU6IGEgY2xvbmVkIHZhbHVlIG5ldmVyXG4vLyAgIHJlYWRzIGFnYWluLlxuLy8gLSBBbiBvdXRwdXQncyBkZXRhaWwgY2VsbCBpcyBkcmF3biBieSBmc1JlcG9ydEdyaWRDZWxsLCBzbyBhIGNoYW5nZSB0ZWxsc1xuLy8gICBhIG1pc3NpbmcgcHJpb3IgZnJvbSBhIHplcm8gb25lIGFuZCBzYXlzIHdoeSBvbiBob3ZlciwgYXMgYSBsaXN0IGRvZXMuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtcmVwb3J0LWNvbXBvbmVudC1ncmlkJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbXBvbmVudC1ncmlkLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vY29tcG9uZW50LWdyaWQuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBGc0dyaWRDb21wb25lbnQsXG4gICAgRnNHcmlkQ2VsbERpcmVjdGl2ZSxcbiAgICBDb21wb25lbnROb3RlQ29tcG9uZW50LFxuICAgIFJlcG9ydEdyaWRDZWxsUGlwZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgQ29tcG9uZW50R3JpZENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgcHVibGljIHJlYWRvbmx5IHJlcG9ydElkID0gaW5wdXQucmVxdWlyZWQ8bnVtYmVyPigpO1xuICBwdWJsaWMgcmVhZG9ubHkgY29tcG9uZW50ID0gaW5wdXQucmVxdWlyZWQ8UmVwb3J0Q29tcG9uZW50PigpO1xuXG4gIHB1YmxpYyByZWFkb25seSBwYXJhbXMgPSBzaWduYWw8UmVwb3J0R3JpZFBhcmFtcyB8IG51bGw+KG51bGwpO1xuICBwdWJsaWMgcmVhZG9ubHkgY29udHJvbHMgPSBjb21wdXRlZCgoKSA9PiB0aGlzLmNvbXBvbmVudCgpLmNvbmZpZz8uY29udHJvbHMgPz8ge30pO1xuICBwdWJsaWMgcmVhZG9ubHkgc291cmNlID0gY29tcHV0ZWQoKCkgPT4gbmV3IFJlcG9ydEdyaWRTb3VyY2UodGhpcy5fcmVwb3J0RGF0YSwgdGhpcy5yZXBvcnRJZCgpLCB0aGlzLl9jb21wb25lbnRJZCgpLCB7XG4gICAgbG9jYWxlOiAoKSA9PiB0aGlzLl9maWx0ZXJTdGF0ZS5mb3JtYXRDb250ZXh0KCkubG9jYWxlLFxuICB9KSk7XG5cbiAgcHVibGljIHJlYWRvbmx5IGxheW91dCA9IGNvbXB1dGVkKCgpID0+IHRoaXMuX2ZpbHRlclN0YXRlLmdyaWRMYXlvdXQodGhpcy5jb21wb25lbnQoKSkpO1xuICBwdWJsaWMgcmVhZG9ubHkgY2xlYXJlZEZpbHRlciA9IGNvbXB1dGVkKCgpID0+IHRoaXMuX2ZpbHRlclN0YXRlLmdyaWRDbGVhcmVkRmlsdGVyKHRoaXMuY29tcG9uZW50KCkpKTtcbiAgLy8gUmVhZCBvbmNlOiBmcy1ncmlkIG93bnMgdGhlIG9wZW4gZ3JvdXBzIGZyb20gdGhlbiBvbiBhbmQgd3JpdGVzIHRoZW0gb3V0LlxuICBwdWJsaWMgcmVhZG9ubHkgZXhwYW5zaW9uID0gc2lnbmFsPEdyaWRFeHBhbnNpb24gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG5cbiAgcHVibGljIHJlYWRvbmx5IG5vdGVEYXRhID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5zb3VyY2UoKS5yZXBvcnQoKSk7XG4gIHB1YmxpYyByZWFkb25seSBmb3JtYXRDb250ZXh0ID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5fZmlsdGVyU3RhdGUuZm9ybWF0Q29udGV4dCgpKTtcbiAgcHVibGljIHJlYWRvbmx5IGZvcm1hdHRlciA9IGNvbXB1dGVkKCgpID0+IHJlcG9ydEdyaWRGb3JtYXR0ZXIoe1xuICAgIGZvcm1hdDogdGhpcy5fZmlsdGVyU3RhdGUuZm9ybWF0Q29udGV4dCgpLFxuICAgIHRpbWV6b25lOiB0aGlzLl9maWx0ZXJTdGF0ZS50aW1lem9uZSgpLFxuICAgIHJlcG9ydDogdGhpcy5zb3VyY2UoKS5yZXBvcnQoKSxcbiAgfSkpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX2NvbXBvbmVudElkID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5jb21wb25lbnQoKS5pZCk7XG4gIHByaXZhdGUgX3JlcG9ydERhdGEgPSBpbmplY3QoUmVwb3J0RGF0YSk7XG4gIHByaXZhdGUgX2ZpbHRlclN0YXRlID0gaW5qZWN0KFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSk7XG4gIHByaXZhdGUgX2Rlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG4gIC8vIFRoZSBzdGF0ZSB2ZXJzaW9uIHRoZSBwYXJhbXMgb24gc2NyZWVuIHdlcmUgcmVhZCB1bmRlci5cbiAgcHJpdmF0ZSBfcGFyYW1zVmVyc2lvbiA9IDA7XG5cbiAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZXhwYW5zaW9uLnNldCh0aGlzLl9maWx0ZXJTdGF0ZS5ncmlkRXhwYW5zaW9uKHRoaXMuY29tcG9uZW50KCkpKTtcbiAgICB0aGlzLl9pbml0KCk7XG4gIH1cblxuICBwdWJsaWMgc2V0TGF5b3V0KGxheW91dDogR3JpZExheW91dCk6IHZvaWQge1xuICAgIHRoaXMuX2ZpbHRlclN0YXRlLnNldEdyaWRMYXlvdXQodGhpcy5jb21wb25lbnQoKSwgbGF5b3V0KTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRFeHBhbnNpb24oZXhwYW5zaW9uOiBHcmlkRXhwYW5zaW9uIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0R3JpZEV4cGFuc2lvbih0aGlzLmNvbXBvbmVudCgpLCBleHBhbnNpb24pO1xuICB9XG5cbiAgcHJpdmF0ZSBfaW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLl9wYXJhbXNWZXJzaW9uID0gdGhpcy5fZmlsdGVyU3RhdGUuc3RhdGVWZXJzaW9uKCk7XG4gICAgdGhpcy5wYXJhbXMuc2V0KHRoaXMuX3JlYWRQYXJhbXMoKSk7XG5cbiAgICB0aGlzLl9maWx0ZXJTdGF0ZS5jaGFuZ2VzRm9yKHRoaXMuY29tcG9uZW50KCkpXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuX3NldHRsZWQkKCkpLFxuICAgICAgICB0YXAoKCkgPT4gdGhpcy5fYXBwbHlQYXJhbXMoKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKTtcblxuICAgIGlmIChmb2xsb3dzR3JvdXBCeSh0aGlzLmNvbXBvbmVudCgpKSkge1xuICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuZnJlcXVlbmN5Q2hhbmdlcygpXG4gICAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLl9hcHBseVBhcmFtcygpKTtcbiAgICB9XG4gIH1cblxuICAvLyBBIGNoYW5nZSwgb25jZSBpdCBoYXMgc2V0dGxlZDogYXQgb25jZSB3aGVuIHRoZSBzdGF0ZSB2ZXJzaW9uIG1vdmVkLFxuICAvLyBlbHNlIGFmdGVyIHRoZSBkZWJvdW5jZTsgZHJvcHBlZCB3aGVuIHRoZSB2ZXJzaW9uIG1vdmVzIHdoaWxlIGl0IHdhaXRzLFxuICAvLyBzaW5jZSB0aGF0IG1vdmUgYnJpbmdzIGl0cyBvd24gY2hhbmdlLlxuICBwcml2YXRlIF9zZXR0bGVkJCgpOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICBjb25zdCB2ZXJzaW9uID0gdGhpcy5fZmlsdGVyU3RhdGUuc3RhdGVWZXJzaW9uKCk7XG4gICAgY29uc3QgbW92ZWQgPSB2ZXJzaW9uICE9PSB0aGlzLl9wYXJhbXNWZXJzaW9uO1xuXG4gICAgcmV0dXJuIChtb3ZlZCA/IG9mKDApIDogdGltZXIoVElMRV9SRUZSRVNIX0RFQk9VTkNFX01TKSlcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5fZmlsdGVyU3RhdGUuc3RhdGVWZXJzaW9uKCkgPT09IHZlcnNpb24pLFxuICAgICAgICBtYXAoKCkgPT4gdW5kZWZpbmVkKSxcbiAgICAgICk7XG4gIH1cblxuICBwcml2YXRlIF9hcHBseVBhcmFtcygpOiB2b2lkIHtcbiAgICB0aGlzLl9wYXJhbXNWZXJzaW9uID0gdGhpcy5fZmlsdGVyU3RhdGUuc3RhdGVWZXJzaW9uKCk7XG4gICAgdGhpcy5wYXJhbXMuc2V0KHRoaXMuX3JlYWRQYXJhbXMoKSk7XG4gIH1cblxuICAvLyBUaGUgdGlsZSdzIHJlcG9ydCBmaWx0ZXJzLCAnYW55JyBncm91cHMgYW5kIGdyb3VwLWJ5IGdyYWluIGFzIHRoZXkgc3RhbmRcbiAgLy8gKHRpbGVTdGF0ZSgpKS5cbiAgcHJpdmF0ZSBfcmVhZFBhcmFtcygpOiBSZXBvcnRHcmlkUGFyYW1zIHtcbiAgICBjb25zdCBjb21wb25lbnQgPSB0aGlzLmNvbXBvbmVudCgpO1xuICAgIGNvbnN0IHsgbWF0Y2hBbnlHcm91cElkcywgZnJlcXVlbmN5IH0gPSB0aGlzLl9maWx0ZXJTdGF0ZS50aWxlU3RhdGUoY29tcG9uZW50KTtcblxuICAgIHJldHVybiB7XG4gICAgICBmaWx0ZXJzOiB0aGlzLl9maWx0ZXJTdGF0ZS5yZXNvbHZlRm9yQ29tcG9uZW50KGNvbXBvbmVudCksXG4gICAgICAuLi4obWF0Y2hBbnlHcm91cElkcz8ubGVuZ3RoID8geyBtYXRjaEFueUdyb3VwSWRzIH0gOiB7fSksXG4gICAgICAuLi4oZnJlcXVlbmN5ID8geyBmcmVxdWVuY3kgfSA6IHt9KSxcbiAgICB9O1xuICB9XG5cbn1cbiIsIjwhLS0gVGhlIGNvbXBhcmlzb24gYW5kIHdpbmRvdyBub3RlIHN0cmlwIGFib3ZlIHRoZSB0YWJsZSwgZnJvbSB0aGUgcmVwb3J0XG4gICAgIGxpbmUgb2YgdGhlIGxhdGVzdCByZWFkOyB0aGUgd2luZG93cycgZGVzY3JpcHRpb25zIGFuZCBub3RlcyBnbyBpbiBlYWNoXG4gICAgIGNvbHVtbidzIFwiQWJvdXQgdGhpcyBjb2x1bW5cIiBpbnN0ZWFkLiAtLT5cbjxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gZ3JpZC1wYW5lXCI+XG4gIDxhcHAtcmVwb3J0LWNvbXBvbmVudC1ub3RlXG4gICAgW2RhdGFdPVwibm90ZURhdGEoKVwiXG4gICAgW3dpbmRvd05vdGVzXT1cImZhbHNlXCI+XG4gIDwvYXBwLXJlcG9ydC1jb21wb25lbnQtbm90ZT5cbiAgPCEtLSBUaGUgcGFyYW1zIGFyZSBzZWVkZWQgYmVmb3JlIHRoZSBmaXJzdCByZW5kZXIsIHNvIHRoZSBncmlkJ3MgZmlyc3QgcmVhZFxuICAgICAgIGNhcnJpZXMgdGhlIHRpbGUncyByZXBvcnQgZmlsdGVycy4gLS0+XG4gIEBpZiAocGFyYW1zKCk7IGFzIHBhcmFtcykge1xuICAgIDxmcy1ncmlkXG4gICAgICBjbGFzcz1cImZzLWZsZXhcIlxuICAgICAgW3NvdXJjZV09XCJzb3VyY2UoKVwiXG4gICAgICBbbGF5b3V0XT1cImxheW91dCgpXCJcbiAgICAgIFtleHBhbnNpb25dPVwiZXhwYW5zaW9uKClcIlxuICAgICAgW2NsZWFyZWRGaWx0ZXJdPVwiY2xlYXJlZEZpbHRlcigpXCJcbiAgICAgIChleHBhbnNpb25DaGFuZ2UpPVwic2V0RXhwYW5zaW9uKCRldmVudClcIlxuICAgICAgW3BhcmFtc109XCJwYXJhbXNcIlxuICAgICAgW2NvbnRyb2xzXT1cImNvbnRyb2xzKClcIlxuICAgICAgW2Zvcm1hdHRlcl09XCJmb3JtYXR0ZXIoKVwiXG4gICAgICAobGF5b3V0Q2hhbmdlKT1cInNldExheW91dCgkZXZlbnQpXCI+XG4gICAgICA8bmctdGVtcGxhdGUgZnNHcmlkQ2VsbCBsZXQtdmFsdWUgbGV0LWZpZWxkPVwiZmllbGRcIiBsZXQtcmVjb3JkPVwicmVjb3JkXCIgbGV0LXRleHQ9XCJ0ZXh0XCI+XG4gICAgICAgIEBpZiAodmFsdWUgfCBmc1JlcG9ydEdyaWRDZWxsOiBmaWVsZCA6IHJlY29yZCA6IHRleHQgOiBub3RlRGF0YSgpIDogZm9ybWF0Q29udGV4dCgpOyBhcyBzaG93bikge1xuICAgICAgICAgIDxzcGFuIFthdHRyLnRpdGxlXT1cInNob3duLnRpdGxlXCI+e3sgc2hvd24udGV4dCB9fTwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICA8L2ZzLWdyaWQ+XG4gIH1cbjwvZGl2PlxuIl19
|