@theseam/ui-common 1.0.2-beta.23 → 1.0.2-beta.29
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/fesm2022/theseam-ui-common-data-exporter.mjs +1 -2
- package/fesm2022/theseam-ui-common-data-exporter.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-graphql.mjs +73 -17
- package/fesm2022/theseam-ui-common-graphql.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-utils.mjs +31 -60
- package/fesm2022/theseam-ui-common-utils.mjs.map +1 -1
- package/graphql/index.d.ts +40 -16
- package/package.json +3 -3
- package/utils/index.d.ts +5 -6
|
@@ -5,7 +5,6 @@ import { from } from 'rxjs';
|
|
|
5
5
|
import { faFileCsv, faFileExcel } from '@fortawesome/free-solid-svg-icons';
|
|
6
6
|
import FileSaver from 'file-saver';
|
|
7
7
|
import { wrapIntoObservable, fileDataFromBuffer } from '@theseam/ui-common/utils';
|
|
8
|
-
import { Buffer } from 'buffer/';
|
|
9
8
|
|
|
10
9
|
const THESEAM_DATA_EXPORTER = new InjectionToken('TheSeamDataExporter');
|
|
11
10
|
function exportOperator(exportFn) {
|
|
@@ -65,7 +64,7 @@ class XLSXDataExporter {
|
|
|
65
64
|
const ws = XLSX.utils.json_to_sheet(data);
|
|
66
65
|
const wb = { Sheets: { data: ws }, SheetNames: ['data'] };
|
|
67
66
|
const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
68
|
-
return from(fileDataFromBuffer(
|
|
67
|
+
return from(fileDataFromBuffer(excelBuffer)).pipe(tap((fileData) => {
|
|
69
68
|
FileSaver.saveAs(fileData.blob, `Export.xlsx`);
|
|
70
69
|
}), mapTo(true));
|
|
71
70
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theseam-ui-common-data-exporter.mjs","sources":["../../../projects/ui-common/data-exporter/data-exporter.ts","../../../projects/ui-common/data-exporter/import-xlsx.ts","../../../projects/ui-common/data-exporter/exporters/csv-exporter.ts","../../../projects/ui-common/data-exporter/exporters/xlsx-exporter.ts","../../../projects/ui-common/data-exporter/data-exporter.module.ts","../../../projects/ui-common/data-exporter/theseam-ui-common-data-exporter.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core'\nimport { Observable } from 'rxjs'\nimport { switchMap } from 'rxjs/operators'\n\nimport { IconProp } from '@fortawesome/fontawesome-svg-core'\n\nexport type IDataExporterFunction = <T>(data: T[]) => Observable<T[]>\n\nexport interface IDataExporter {\n /**\n * Name to identify the exporter.\n */\n readonly name: string\n\n /**\n * Label to use for exporter in user visible text.\n *\n * default: `name`\n */\n label?: string\n\n /**\n * Icon to represent exporter.\n */\n icon?: string | IconProp\n\n /**\n * Pass the rows directly to the export function without any mapping.\n */\n skipDataMapping?: boolean\n\n /**\n * Export the data based on the data to some format.\n */\n export<T>(data: T[]): Observable<boolean>\n}\n\nexport const THESEAM_DATA_EXPORTER = new InjectionToken<IDataExporter>(\n 'TheSeamDataExporter',\n)\n\nexport function exportOperator<T>(exportFn: IDataExporterFunction) {\n return (source$: Observable<T[]>) => source$.pipe(switchMap(exportFn))\n}\n","// TODO: We may be able to avoid this by getting the Storybook tsconfig and our\n// apps Angular builds more in-sync or when Storybook updates the builder that\n// it uses. For now, this should give a reliable ESM and CJS interop for the\n// XLSX library.\n\n/**\n * Imports the XLSX library.\n *\n * This should be used instead of direct dynamic imports to ensure\n * compatibility. It may be better to just import normally, but most datatables\n * don't do client-side XLSX processing so dynamic imports are preferred.\n *\n * @returns The XLSX library.\n */\nexport async function importXlsx(): Promise<any> {\n // TODO: Fix typing for the dynamic imports\n const XLSX = await import('xlsx')\n return XLSX.default ?? XLSX\n}\n","import { Injectable } from '@angular/core'\nimport { from, Observable } from 'rxjs'\nimport { mapTo, switchMap, tap } from 'rxjs/operators'\n\nimport { faFileCsv } from '@fortawesome/free-solid-svg-icons'\nimport FileSaver from 'file-saver'\n\nimport {\n fileDataFromBuffer,\n wrapIntoObservable,\n} from '@theseam/ui-common/utils'\n\nimport { IDataExporter } from '../data-exporter'\nimport { importXlsx } from '../import-xlsx'\n\n@Injectable()\nexport class CSVDataExporter implements IDataExporter {\n public readonly name = 'exporter:csv'\n\n public label = 'CSV'\n\n public icon = faFileCsv\n\n public export<T>(data: T[]): Observable<boolean> {\n return wrapIntoObservable(importXlsx()).pipe(\n switchMap((XLSX: any) => {\n const ws = XLSX.utils.json_to_sheet(data)\n\n const out = XLSX.utils.sheet_to_csv(ws)\n\n // NOTE: `out` should not be passed as a string, but the fileDataFromBuffer\n // function happens to works with a string. When the build issue about the\n // function argument is figured out then this should be fixed.\n return (\n from(fileDataFromBuffer(out as any))\n // return from(fileDataFromBuffer(Buffer.from(out)))\n .pipe(\n tap((fileData) => {\n FileSaver.saveAs(fileData.blob, `Export.csv`)\n }),\n mapTo(true),\n )\n )\n }),\n )\n }\n}\n","import { Injectable } from '@angular/core'\nimport { from, Observable } from 'rxjs'\nimport { mapTo, switchMap, tap } from 'rxjs/operators'\n\nimport { faFileExcel } from '@fortawesome/free-solid-svg-icons'\nimport
|
|
1
|
+
{"version":3,"file":"theseam-ui-common-data-exporter.mjs","sources":["../../../projects/ui-common/data-exporter/data-exporter.ts","../../../projects/ui-common/data-exporter/import-xlsx.ts","../../../projects/ui-common/data-exporter/exporters/csv-exporter.ts","../../../projects/ui-common/data-exporter/exporters/xlsx-exporter.ts","../../../projects/ui-common/data-exporter/data-exporter.module.ts","../../../projects/ui-common/data-exporter/theseam-ui-common-data-exporter.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core'\nimport { Observable } from 'rxjs'\nimport { switchMap } from 'rxjs/operators'\n\nimport { IconProp } from '@fortawesome/fontawesome-svg-core'\n\nexport type IDataExporterFunction = <T>(data: T[]) => Observable<T[]>\n\nexport interface IDataExporter {\n /**\n * Name to identify the exporter.\n */\n readonly name: string\n\n /**\n * Label to use for exporter in user visible text.\n *\n * default: `name`\n */\n label?: string\n\n /**\n * Icon to represent exporter.\n */\n icon?: string | IconProp\n\n /**\n * Pass the rows directly to the export function without any mapping.\n */\n skipDataMapping?: boolean\n\n /**\n * Export the data based on the data to some format.\n */\n export<T>(data: T[]): Observable<boolean>\n}\n\nexport const THESEAM_DATA_EXPORTER = new InjectionToken<IDataExporter>(\n 'TheSeamDataExporter',\n)\n\nexport function exportOperator<T>(exportFn: IDataExporterFunction) {\n return (source$: Observable<T[]>) => source$.pipe(switchMap(exportFn))\n}\n","// TODO: We may be able to avoid this by getting the Storybook tsconfig and our\n// apps Angular builds more in-sync or when Storybook updates the builder that\n// it uses. For now, this should give a reliable ESM and CJS interop for the\n// XLSX library.\n\n/**\n * Imports the XLSX library.\n *\n * This should be used instead of direct dynamic imports to ensure\n * compatibility. It may be better to just import normally, but most datatables\n * don't do client-side XLSX processing so dynamic imports are preferred.\n *\n * @returns The XLSX library.\n */\nexport async function importXlsx(): Promise<any> {\n // TODO: Fix typing for the dynamic imports\n const XLSX = await import('xlsx')\n return XLSX.default ?? XLSX\n}\n","import { Injectable } from '@angular/core'\nimport { from, Observable } from 'rxjs'\nimport { mapTo, switchMap, tap } from 'rxjs/operators'\n\nimport { faFileCsv } from '@fortawesome/free-solid-svg-icons'\nimport FileSaver from 'file-saver'\n\nimport {\n fileDataFromBuffer,\n wrapIntoObservable,\n} from '@theseam/ui-common/utils'\n\nimport { IDataExporter } from '../data-exporter'\nimport { importXlsx } from '../import-xlsx'\n\n@Injectable()\nexport class CSVDataExporter implements IDataExporter {\n public readonly name = 'exporter:csv'\n\n public label = 'CSV'\n\n public icon = faFileCsv\n\n public export<T>(data: T[]): Observable<boolean> {\n return wrapIntoObservable(importXlsx()).pipe(\n switchMap((XLSX: any) => {\n const ws = XLSX.utils.json_to_sheet(data)\n\n const out = XLSX.utils.sheet_to_csv(ws)\n\n // NOTE: `out` should not be passed as a string, but the fileDataFromBuffer\n // function happens to works with a string. When the build issue about the\n // function argument is figured out then this should be fixed.\n return (\n from(fileDataFromBuffer(out as any))\n // return from(fileDataFromBuffer(Buffer.from(out)))\n .pipe(\n tap((fileData) => {\n FileSaver.saveAs(fileData.blob, `Export.csv`)\n }),\n mapTo(true),\n )\n )\n }),\n )\n }\n}\n","import { Injectable } from '@angular/core'\nimport { from, Observable } from 'rxjs'\nimport { mapTo, switchMap, tap } from 'rxjs/operators'\n\nimport { faFileExcel } from '@fortawesome/free-solid-svg-icons'\nimport FileSaver from 'file-saver'\n\nimport {\n fileDataFromBuffer,\n wrapIntoObservable,\n} from '@theseam/ui-common/utils'\n\nimport { IDataExporter } from '../data-exporter'\nimport { importXlsx } from '../import-xlsx'\n\n@Injectable()\nexport class XLSXDataExporter implements IDataExporter {\n public readonly name = 'exporter:xlsx'\n\n public label = 'XLSX'\n\n public icon = faFileExcel\n\n public export<T>(data: T[]): Observable<boolean> {\n return wrapIntoObservable(importXlsx()).pipe(\n switchMap((XLSX: any) => {\n const ws = XLSX.utils.json_to_sheet(data)\n const wb = { Sheets: { data: ws }, SheetNames: ['data'] }\n const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })\n\n return from(fileDataFromBuffer(excelBuffer)).pipe(\n tap((fileData) => {\n FileSaver.saveAs(fileData.blob, `Export.xlsx`)\n }),\n mapTo(true),\n )\n }),\n )\n }\n}\n","import { NgModule } from '@angular/core'\n\nimport { CSVDataExporter } from './exporters/csv-exporter'\nimport { XLSXDataExporter } from './exporters/xlsx-exporter'\n\nimport { THESEAM_DATA_EXPORTER } from './data-exporter'\n\n@NgModule({\n declarations: [],\n imports: [],\n providers: [\n { provide: THESEAM_DATA_EXPORTER, useClass: CSVDataExporter, multi: true },\n { provide: THESEAM_DATA_EXPORTER, useClass: XLSXDataExporter, multi: true },\n ],\n})\nexport class TheSeamDataExporterModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApolloLink, NetworkStatus, Observable as Observable$1 } from '@apollo/client/core';
|
|
2
|
-
import { print, visit as visit$1, parse, BREAK as BREAK$1, parseValue } from 'graphql';
|
|
2
|
+
import { print, visit as visit$1, parse, BREAK as BREAK$1, parseValue, Kind, valueFromASTUntyped } from 'graphql';
|
|
3
3
|
import { hasProperty, notNullOrUndefined, isNullOrUndefined, withoutProperty, wrapIntoObservable, withoutProperties } from '@theseam/ui-common/utils';
|
|
4
4
|
import { visit, BREAK } from 'graphql/language';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
@@ -538,39 +538,57 @@ const queryProcessingLink = new ApolloLink((operation, forward) => {
|
|
|
538
538
|
/**
|
|
539
539
|
* Creates a {@link SortsMapper} from a declarative field-name map.
|
|
540
540
|
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
541
|
+
* By default, `autoMap` is enabled: columns not listed in the field map
|
|
542
|
+
* are automatically mapped using their `prop` as the GQL field name,
|
|
543
|
+
* provided the column exists in the datatable and has `sortable` not
|
|
544
|
+
* explicitly set to `false`. This guards against stale sort preferences
|
|
545
|
+
* for removed columns.
|
|
546
|
+
*
|
|
547
|
+
* Each key in `fieldMap` must correspond to a datatable column `prop`
|
|
548
|
+
* value. The value controls how that column's sort is translated:
|
|
543
549
|
*
|
|
544
550
|
* - `string` – emits `{ [gqlField]: 'ASC' | 'DESC' }`
|
|
545
551
|
* - `null` – column is not sortable; the sort item is dropped
|
|
546
552
|
* - `function` – called with `(prop, context)` and may return a field
|
|
547
553
|
* name or `null` to drop the item dynamically
|
|
548
554
|
*
|
|
549
|
-
* In dev mode an error is thrown when a sort item's `prop` is not present
|
|
550
|
-
* in the map. In production the item is silently dropped.
|
|
551
|
-
*
|
|
552
555
|
* @example
|
|
553
|
-
* //
|
|
556
|
+
* // Auto-map all columns, override one
|
|
554
557
|
* const mapSorts = createSortsMapper<MyRow>({
|
|
555
|
-
*
|
|
556
|
-
* name: 'name',
|
|
558
|
+
* computedField: 'gql_computed_field',
|
|
557
559
|
* })
|
|
558
560
|
*
|
|
559
561
|
* @example
|
|
560
|
-
* //
|
|
562
|
+
* // Opt out of auto-mapping (explicit field map required)
|
|
561
563
|
* const mapSorts = createSortsMapper<MyRow>({
|
|
562
564
|
* id: 'id',
|
|
563
565
|
* name: 'name',
|
|
564
|
-
*
|
|
565
|
-
* context.extraVariables.useAlt ? 'altField' : prop,
|
|
566
|
-
* })
|
|
566
|
+
* }, { autoMap: false })
|
|
567
567
|
*/
|
|
568
|
-
function createSortsMapper(fieldMap) {
|
|
568
|
+
function createSortsMapper(fieldMap, options) {
|
|
569
|
+
const autoMap = options?.autoMap ?? true;
|
|
569
570
|
return (sorts, context) => {
|
|
570
571
|
const result = [];
|
|
571
572
|
for (const s of sorts) {
|
|
572
573
|
const prop = s?.prop;
|
|
573
574
|
if (!(prop in fieldMap)) {
|
|
575
|
+
if (autoMap) {
|
|
576
|
+
const columns = context.columns;
|
|
577
|
+
if (columns) {
|
|
578
|
+
const column = columns.find((c) => c.prop === prop);
|
|
579
|
+
if (column && column.sortable !== false) {
|
|
580
|
+
const dir = s?.dir?.toUpperCase();
|
|
581
|
+
result.push({ [prop]: dir });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
else if (isDevMode()) {
|
|
585
|
+
// autoMap is enabled but no columns in context — likely a
|
|
586
|
+
// wiring issue where columns$ is not being piped through.
|
|
587
|
+
console.warn(`createSortsMapper: autoMap is enabled but no columns found in context for prop "${prop}". ` +
|
|
588
|
+
`Ensure columns are provided via MapperContext.`);
|
|
589
|
+
}
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
574
592
|
if (isDevMode()) {
|
|
575
593
|
throw new Error(`createSortsMapper: no mapping found for column prop "${prop}". ` +
|
|
576
594
|
`Add an entry to the field map or set the value to null to ignore it.`);
|
|
@@ -735,7 +753,7 @@ function observeRowsWithGqlInputsHandling(queryRef, rows, datatable, extraVariab
|
|
|
735
753
|
// only one setVariables call is made per event-loop turn.
|
|
736
754
|
const handleQueryInputs = combineLatest([extraVariables$, pageInfo$]).pipe(auditTime(0), switchMap(([_extraVariables, pageInfo]) => {
|
|
737
755
|
const context = { extraVariables: _extraVariables };
|
|
738
|
-
const sorts$ =
|
|
756
|
+
const sorts$ = _createSortsAndColumnsObservable(datatable$).pipe(switchMap(({ sorts, columns }) => wrapIntoObservable(sortsMapper(sorts, { ...context, columns }))));
|
|
739
757
|
const filterInfo$ = _createFilterStatesObservable(datatable$).pipe(switchMap((x) => mapFilterStates(x, filterStateMappers, context)),
|
|
740
758
|
// TODO: Remove when the datatable fixes the bug causing it to emit more than it should.
|
|
741
759
|
distinctUntilChanged((x, y) => JSON.stringify(x) === JSON.stringify(y)));
|
|
@@ -781,7 +799,7 @@ function observeRowsWithGqlInputsHandling(queryRef, rows, datatable, extraVariab
|
|
|
781
799
|
return of([]);
|
|
782
800
|
}), shareReplay({ bufferSize: 1, refCount: true }));
|
|
783
801
|
}
|
|
784
|
-
function
|
|
802
|
+
function _createSortsAndColumnsObservable(datatable$) {
|
|
785
803
|
// NOTE: There is a bug in our datatable wrapper that isn't propagating
|
|
786
804
|
// external sorting changes to the wrapped datatable component, which we observe
|
|
787
805
|
// sort events from. This workaround observes our wrapper's internal column
|
|
@@ -795,7 +813,12 @@ function _createSortsObservable(datatable$) {
|
|
|
795
813
|
}
|
|
796
814
|
return dt._columnsAlterationsManager.changes.pipe(map(() => (dt.externalSorting ? dt._sorts : dt.sorts)), startWith(dt.externalSorting ? dt._sorts : dt.sorts));
|
|
797
815
|
};
|
|
798
|
-
return datatable$.pipe(switchMap((dt) =>
|
|
816
|
+
return datatable$.pipe(switchMap((dt) => dt
|
|
817
|
+
? combineLatest([_observeSortsWorkaround(dt), dt.columns$]).pipe(map(([sorts, columns]) => ({ sorts, columns })))
|
|
818
|
+
: of({
|
|
819
|
+
sorts: [],
|
|
820
|
+
columns: [],
|
|
821
|
+
})), shareReplay({ bufferSize: 1, refCount: true }));
|
|
799
822
|
}
|
|
800
823
|
function _createFilterStatesObservable(datatable$) {
|
|
801
824
|
return datatable$.pipe(switchMap((dt) => (dt ? dt.filterStates : of([]))));
|
|
@@ -1841,6 +1864,8 @@ function filteredResults(items, args) {
|
|
|
1841
1864
|
}
|
|
1842
1865
|
|
|
1843
1866
|
class MockDatatable {
|
|
1867
|
+
_columnsSubject = new BehaviorSubject([]);
|
|
1868
|
+
columns$ = this._columnsSubject.asObservable();
|
|
1844
1869
|
_filterStatesSubject = new BehaviorSubject([]);
|
|
1845
1870
|
_sorts = [];
|
|
1846
1871
|
_rows = [];
|
|
@@ -1877,6 +1902,9 @@ class MockDatatable {
|
|
|
1877
1902
|
count: this._rows.length,
|
|
1878
1903
|
};
|
|
1879
1904
|
}
|
|
1905
|
+
setColumns(v) {
|
|
1906
|
+
this._columnsSubject.next(v);
|
|
1907
|
+
}
|
|
1880
1908
|
setSorts(v) {
|
|
1881
1909
|
this._sorts = v;
|
|
1882
1910
|
this.sort.emit({ sorts: this._sorts });
|
|
@@ -2002,10 +2030,38 @@ function _isOneOfIndices(indices, index) {
|
|
|
2002
2030
|
return false;
|
|
2003
2031
|
}
|
|
2004
2032
|
|
|
2033
|
+
/**
|
|
2034
|
+
* Extracts the effective field arguments from the top-level selections of a
|
|
2035
|
+
* processed query, merging inlined literal values back with the remaining
|
|
2036
|
+
* operation variables.
|
|
2037
|
+
*
|
|
2038
|
+
* When {@link queryProcessingLink} inlines a variable (e.g. `where`) into the
|
|
2039
|
+
* query AST, it removes that variable from `operation.variables`. A real
|
|
2040
|
+
* GraphQL server would still resolve the inlined literal when executing the
|
|
2041
|
+
* field resolver, but a mock link that only looks at `operation.variables`
|
|
2042
|
+
* would miss it. This function bridges that gap.
|
|
2043
|
+
*/
|
|
2044
|
+
function resolveEffectiveVariables(operation) {
|
|
2045
|
+
const merged = { ...operation.variables };
|
|
2046
|
+
const opDef = operation.query.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
|
|
2047
|
+
if (!opDef)
|
|
2048
|
+
return merged;
|
|
2049
|
+
for (const sel of opDef.selectionSet.selections) {
|
|
2050
|
+
if (sel.kind === Kind.FIELD && sel.arguments) {
|
|
2051
|
+
for (const arg of sel.arguments) {
|
|
2052
|
+
if (arg.value.kind !== Kind.VARIABLE) {
|
|
2053
|
+
merged[arg.name.value] = valueFromASTUntyped(arg.value, operation.variables);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
return merged;
|
|
2059
|
+
}
|
|
2005
2060
|
function mockGraphQLLink(options) {
|
|
2006
2061
|
return new ApolloLink((operation, forward) => {
|
|
2007
2062
|
return new Observable$1((subscriber) => {
|
|
2008
2063
|
const execute = () => {
|
|
2064
|
+
operation.variables = resolveEffectiveVariables(operation);
|
|
2009
2065
|
const response = options.resolve(operation);
|
|
2010
2066
|
operation.setContext({ response });
|
|
2011
2067
|
subscriber.next(response);
|