ag-grid-url-sync 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +339 -66
  2. package/dist/core/ag-grid-url-sync.d.ts +16 -9
  3. package/dist/core/ag-grid-url-sync.js +23 -19
  4. package/dist/core/ag-grid-url-sync.js.map +1 -1
  5. package/dist/core/codecs.d.ts +28 -0
  6. package/dist/core/codecs.js +39 -0
  7. package/dist/core/codecs.js.map +1 -0
  8. package/dist/core/data-issue-codes.d.ts +3 -0
  9. package/dist/core/data-issue-codes.js +10 -0
  10. package/dist/core/data-issue-codes.js.map +1 -0
  11. package/dist/core/grid-integration.d.ts +38 -2
  12. package/dist/core/grid-integration.js +169 -128
  13. package/dist/core/grid-integration.js.map +1 -1
  14. package/dist/core/grid-url-sync.d.ts +62 -0
  15. package/dist/core/grid-url-sync.js +738 -0
  16. package/dist/core/grid-url-sync.js.map +1 -0
  17. package/dist/core/index.d.ts +4 -1
  18. package/dist/core/index.js +4 -1
  19. package/dist/core/index.js.map +1 -1
  20. package/dist/core/individual-params.d.ts +12 -5
  21. package/dist/core/individual-params.js +38 -62
  22. package/dist/core/individual-params.js.map +1 -1
  23. package/dist/core/issue-columns.d.ts +2 -0
  24. package/dist/core/issue-columns.js +11 -0
  25. package/dist/core/issue-columns.js.map +1 -0
  26. package/dist/core/issues.d.ts +34 -0
  27. package/dist/core/issues.js +51 -0
  28. package/dist/core/issues.js.map +1 -0
  29. package/dist/core/operators.d.ts +189 -0
  30. package/dist/core/operators.js +60 -0
  31. package/dist/core/operators.js.map +1 -0
  32. package/dist/core/options.d.ts +21 -0
  33. package/dist/core/options.js +21 -0
  34. package/dist/core/options.js.map +1 -0
  35. package/dist/core/own-write.d.ts +138 -0
  36. package/dist/core/own-write.js +133 -0
  37. package/dist/core/own-write.js.map +1 -0
  38. package/dist/core/schemas.d.ts +51 -0
  39. package/dist/core/schemas.js +59 -0
  40. package/dist/core/schemas.js.map +1 -0
  41. package/dist/core/serialization/formats.d.ts +7 -7
  42. package/dist/core/serialization/formats.js +34 -28
  43. package/dist/core/serialization/formats.js.map +1 -1
  44. package/dist/core/serialization/grouped.d.ts +9 -12
  45. package/dist/core/serialization/grouped.js +24 -17
  46. package/dist/core/serialization/grouped.js.map +1 -1
  47. package/dist/core/to-error.d.ts +5 -0
  48. package/dist/core/to-error.js +4 -0
  49. package/dist/core/to-error.js.map +1 -0
  50. package/dist/core/types.d.ts +296 -43
  51. package/dist/core/types.js +39 -108
  52. package/dist/core/types.js.map +1 -1
  53. package/dist/core/url-generator.d.ts +4 -4
  54. package/dist/core/url-generator.js +9 -7
  55. package/dist/core/url-generator.js.map +1 -1
  56. package/dist/core/url-parser.d.ts +4 -4
  57. package/dist/core/url-parser.js +6 -4
  58. package/dist/core/url-parser.js.map +1 -1
  59. package/dist/core/validation.d.ts +21 -14
  60. package/dist/core/validation.js +58 -54
  61. package/dist/core/validation.js.map +1 -1
  62. package/dist/core/view-storage.js +21 -19
  63. package/dist/core/view-storage.js.map +1 -1
  64. package/dist/index.d.ts +4 -1
  65. package/dist/index.js +4 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/react/index.d.ts +3 -2
  68. package/dist/react/index.js +1 -0
  69. package/dist/react/index.js.map +1 -1
  70. package/dist/react/sync-holder.d.ts +22 -0
  71. package/dist/react/sync-holder.js +68 -0
  72. package/dist/react/sync-holder.js.map +1 -0
  73. package/dist/react/sync-options.d.ts +17 -0
  74. package/dist/react/sync-options.js +22 -0
  75. package/dist/react/sync-options.js.map +1 -0
  76. package/dist/react/types.d.ts +101 -14
  77. package/dist/react/use-ag-grid-url-sync.d.ts +3 -0
  78. package/dist/react/use-ag-grid-url-sync.js +344 -499
  79. package/dist/react/use-ag-grid-url-sync.js.map +1 -1
  80. package/dist/react/use-grid-url-sync.d.ts +14 -0
  81. package/dist/react/use-grid-url-sync.js +206 -0
  82. package/dist/react/use-grid-url-sync.js.map +1 -0
  83. package/package.json +35 -15
@@ -1,10 +1,15 @@
1
1
  import type { GridApi } from 'ag-grid-community';
2
- import type { AGGridUrlSyncConfig, FilterState, SerializationFormat, SerializationMode } from './types.js';
2
+ import type { AGGridUrlSyncConfig, FilterState, ApplyResult, SerializationFormat, SerializationMode, UrlState } from './types.js';
3
3
  /**
4
4
  * AGGridUrlSync class for synchronizing AG Grid text filters with URL parameters
5
+ *
6
+ * @deprecated Use `createGridUrlSync({ api })`: it also listens to the grid
7
+ * and can write the address bar (#221). `AGGridUrlSync` and `createUrlSync`
8
+ * will be removed in 0.6.0.
5
9
  */
6
10
  export declare class AGGridUrlSync {
7
- private config;
11
+ private readonly gridApi;
12
+ private readonly options;
8
13
  /**
9
14
  * Creates a new instance of AGGridUrlSync
10
15
  * @param gridApi - AG Grid API instance
@@ -26,10 +31,7 @@ export declare class AGGridUrlSync {
26
31
  * also keeps the page's own params (#215).
27
32
  * @param baseUrl - Optional base URL (defaults to current URL)
28
33
  */
29
- getUrlState(baseUrl?: string): {
30
- url: string;
31
- hasFilters: boolean;
32
- };
34
+ getUrlState(baseUrl?: string): UrlState;
33
35
  /**
34
36
  * Gets the current filter state as URL query parameters
35
37
  * @returns Query parameter string
@@ -38,17 +40,20 @@ export declare class AGGridUrlSync {
38
40
  /**
39
41
  * Applies filters from a URL to the grid
40
42
  * @param url - Optional URL to parse (defaults to current URL)
43
+ * @returns The issues of this call: filters in the URL that were dropped
41
44
  */
42
- applyFromUrl(url?: string): void;
45
+ applyFromUrl(url?: string): ApplyResult;
43
46
  /**
44
47
  * Applies a filter state object to the grid
45
48
  * @param filterState - Filter state to apply
49
+ * @returns The issues of this call: filters that were dropped
46
50
  */
47
- applyFilters(filterState: FilterState): void;
51
+ applyFilters(filterState: FilterState): ApplyResult;
48
52
  /**
49
53
  * Clears all text filters from the grid
54
+ * @returns The issues of this call
50
55
  */
51
- clearFilters(): void;
56
+ clearFilters(): ApplyResult;
52
57
  /**
53
58
  * Cleans up any resources or event listeners
54
59
  */
@@ -74,5 +79,7 @@ export declare class AGGridUrlSync {
74
79
  * @param gridApi - AG Grid API instance
75
80
  * @param config - Optional configuration options
76
81
  * @returns AGGridUrlSync instance
82
+ * @deprecated Use `createGridUrlSync({ api })` (#221). This function will be
83
+ * removed in 0.6.0.
77
84
  */
78
85
  export declare function createUrlSync(gridApi: GridApi, config?: AGGridUrlSyncConfig): AGGridUrlSync;
@@ -1,27 +1,27 @@
1
- import { DEFAULT_CONFIG } from './validation.js';
1
+ import { resolveOptions } from './options.js';
2
+ import { collectIssues } from './issues.js';
2
3
  import { parseUrlFilters } from './url-parser.js';
3
4
  import { generateUrl } from './url-generator.js';
4
5
  import { getFilterModel, applyFilterModel } from './grid-integration.js';
5
6
  import { serializeGrouped } from './serialization/grouped.js';
6
7
  export class AGGridUrlSync {
7
- config;
8
+ gridApi;
9
+ options;
8
10
  constructor(gridApi, config = {}) {
9
- const definedConfig = Object.fromEntries(Object.entries(config).filter(([, value]) => value !== undefined));
10
- this.config = {
11
- gridApi,
12
- ...DEFAULT_CONFIG,
13
- ...definedConfig
14
- };
11
+ this.gridApi = gridApi;
12
+ this.options = resolveOptions(config);
15
13
  }
16
14
  generateUrl(baseUrl) {
17
15
  return this.getUrlState(baseUrl).url;
18
16
  }
19
17
  getUrlState(baseUrl) {
20
- const filterState = getFilterModel(this.config);
18
+ const { options, issues } = collectIssues(this.options);
19
+ const filterState = getFilterModel(this.gridApi, options);
21
20
  const url = baseUrl ?? window.location.href;
22
21
  return {
23
- url: generateUrl(url, filterState, this.config),
24
- hasFilters: Object.keys(filterState).length > 0
22
+ url: generateUrl(url, filterState, options),
23
+ hasFilters: Object.keys(filterState).length > 0,
24
+ issues
25
25
  };
26
26
  }
27
27
  getQueryParams() {
@@ -30,28 +30,32 @@ export class AGGridUrlSync {
30
30
  return urlObj.search;
31
31
  }
32
32
  applyFromUrl(url) {
33
+ const { options, issues } = collectIssues(this.options);
33
34
  const urlToParse = url ?? window.location.href;
34
- const filterState = parseUrlFilters(urlToParse, this.config);
35
- this.applyFilters(filterState);
35
+ const filterState = parseUrlFilters(urlToParse, options);
36
+ const applied = this.applyFilters(filterState);
37
+ return { issues: [...issues, ...(applied?.issues ?? [])] };
36
38
  }
37
39
  applyFilters(filterState) {
38
- applyFilterModel(filterState, this.config);
40
+ const { options, issues } = collectIssues(this.options);
41
+ applyFilterModel(filterState, this.gridApi, options);
42
+ return { issues };
39
43
  }
40
44
  clearFilters() {
41
- this.applyFilters({});
45
+ return this.applyFilters({});
42
46
  }
43
47
  destroy() {
44
48
  }
45
49
  getSerializationMode() {
46
- return this.config.serialization;
50
+ return this.options.serialization;
47
51
  }
48
52
  getCurrentFormat() {
49
- return this.config.format;
53
+ return this.options.format;
50
54
  }
51
55
  getFiltersAsFormat(format) {
52
- const filterState = getFilterModel(this.config);
56
+ const filterState = getFilterModel(this.gridApi, this.options);
53
57
  const tempConfig = {
54
- ...this.config,
58
+ ...this.options,
55
59
  format,
56
60
  serialization: 'grouped'
57
61
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ag-grid-url-sync.js","sourceRoot":"","sources":["../../src/core/ag-grid-url-sync.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAK7D,MAAM,OAAO,aAAa;IAChB,MAAM,CAAgB;IAO9B,YAAY,OAAgB,EAAE,MAAM,GAAwB,EAAE;QAI5D,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAC3C,CAAA;QAExB,IAAI,CAAC,MAAM,GAAG;YACZ,OAAO;YACP,GAAG,cAAc;YACjB,GAAG,aAAa;SACjB,CAAA;IACH,CAAC;IAOD,WAAW,CAAC,OAAgB;QAC1B,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,CAAA;IACtC,CAAC;IAWD,WAAW,CAAC,OAAgB;QAC1B,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/C,MAAM,GAAG,GAAG,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC3C,OAAO;YACL,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC;YAC/C,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;SAChD,CAAA;IACH,CAAC;IAMD,cAAc;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3B,OAAO,MAAM,CAAC,MAAM,CAAA;IACtB,CAAC;IAMD,YAAY,CAAC,GAAY;QACvB,MAAM,UAAU,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC9C,MAAM,WAAW,GAAG,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAC5D,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;IAChC,CAAC;IAMD,YAAY,CAAC,WAAwB;QACnC,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAC5C,CAAC;IAKD,YAAY;QACV,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC;IAKD,OAAO;IAEP,CAAC;IAMD,oBAAoB;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAA;IAClC,CAAC;IAMD,gBAAgB;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA;IAC3B,CAAC;IAKD,kBAAkB,CAAC,MAA2B;QAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAG/C,MAAM,UAAU,GAAG;YACjB,GAAG,IAAI,CAAC,MAAM;YACd,MAAM;YACN,aAAa,EAAE,SAAkB;SAClC,CAAA;QAGD,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;QAExD,OAAO,MAAM,CAAC,KAAK,CAAA;IACrB,CAAC;CACF;AAQD,MAAM,UAAU,aAAa,CAC3B,OAAgB,EAChB,MAA4B;IAE5B,OAAO,IAAI,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;AAC3C,CAAC"}
1
+ {"version":3,"file":"ag-grid-url-sync.js","sourceRoot":"","sources":["../../src/core/ag-grid-url-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Codec, ResolvedOptions, SerializationFormat } from './types.js';
2
+ /** The options that a codec sets */
3
+ export type CodecOptions = Pick<ResolvedOptions, 'serialization' | 'paramPrefix' | 'groupedParam' | 'format'>;
4
+ /**
5
+ * One URL param for each filter, for example `?f_name_contains=jo`
6
+ * @param options.prefix - The start of each param name. Default `'f_'`.
7
+ */
8
+ export declare function individual(options?: {
9
+ prefix?: string | undefined;
10
+ }): Codec;
11
+ /**
12
+ * All the filters in one URL param
13
+ * @param options.param - The param name. Default `'grid_filters'`.
14
+ * @param options.format - `'querystring'` (default), `'json'` or `'base64'`
15
+ */
16
+ export declare function grouped(options?: {
17
+ param?: string | undefined;
18
+ format?: SerializationFormat | undefined;
19
+ }): Codec;
20
+ /** The options of a codec. Throws for an object that no factory made. */
21
+ export declare function codecOptions(codec: Codec): CodecOptions;
22
+ /**
23
+ * A codec with all four settings, for the React hook (#222). Internal: the
24
+ * hook's old options name the params of both modes, and the URL must strip
25
+ * the names that the app set, as the class does. Not exported from the
26
+ * package.
27
+ */
28
+ export declare function codecFromOptions(options: CodecOptions): Codec;
@@ -0,0 +1,39 @@
1
+ import { DEFAULT_CONFIG } from './options.js';
2
+ const settings = new WeakMap();
3
+ function makeCodec(options) {
4
+ const codec = Object.freeze({});
5
+ settings.set(codec, options);
6
+ return codec;
7
+ }
8
+ export function individual(options = {}) {
9
+ return makeCodec({
10
+ serialization: 'individual',
11
+ paramPrefix: options.prefix ?? DEFAULT_CONFIG.paramPrefix,
12
+ groupedParam: DEFAULT_CONFIG.groupedParam,
13
+ format: DEFAULT_CONFIG.format
14
+ });
15
+ }
16
+ export function grouped(options = {}) {
17
+ return makeCodec({
18
+ serialization: 'grouped',
19
+ paramPrefix: DEFAULT_CONFIG.paramPrefix,
20
+ groupedParam: options.param ?? DEFAULT_CONFIG.groupedParam,
21
+ format: options.format ?? DEFAULT_CONFIG.format
22
+ });
23
+ }
24
+ export function codecOptions(codec) {
25
+ const options = settings.get(codec);
26
+ if (!options) {
27
+ throw new TypeError('codec must come from individual() or grouped()');
28
+ }
29
+ return options;
30
+ }
31
+ export function codecFromOptions(options) {
32
+ return makeCodec({
33
+ serialization: options.serialization,
34
+ paramPrefix: options.paramPrefix,
35
+ groupedParam: options.groupedParam,
36
+ format: options.format
37
+ });
38
+ }
39
+ //# sourceMappingURL=codecs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codecs.js","sourceRoot":"","sources":["../../src/core/codecs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAY7C,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAuB,CAAA;AAEnD,SAAS,SAAS,CAAC,OAAqB;IAGtC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAU,CAAA;IACxC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAE5B,OAAO,KAAK,CAAA;AACd,CAAC;AAMD,MAAM,UAAU,UAAU,CACxB,OAAO,GAAoC,EAAE;IAE7C,OAAO,SAAS,CAAC;QACf,aAAa,EAAE,YAAY;QAC3B,WAAW,EAAE,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,WAAW;QACzD,YAAY,EAAE,cAAc,CAAC,YAAY;QACzC,MAAM,EAAE,cAAc,CAAC,MAAM;KAC9B,CAAC,CAAA;AACJ,CAAC;AAOD,MAAM,UAAU,OAAO,CACrB,OAAO,GAGH,EAAE;IAEN,OAAO,SAAS,CAAC;QACf,aAAa,EAAE,SAAS;QACxB,WAAW,EAAE,cAAc,CAAC,WAAW;QACvC,YAAY,EAAE,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,YAAY;QAC1D,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM;KAChD,CAAC,CAAA;AACJ,CAAC;AAGD,MAAM,UAAU,YAAY,CAAC,KAAY;IACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAA;IACvE,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAQD,MAAM,UAAU,gBAAgB,CAAC,OAAqB;IACpD,OAAO,SAAS,CAAC;QACf,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { IssueCode } from './types.js';
2
+ /** The codes for a filter that is dropped or not valid */
3
+ export declare const DATA_ISSUE_CODES: ReadonlySet<IssueCode>;
@@ -0,0 +1,10 @@
1
+ export const DATA_ISSUE_CODES = new Set([
2
+ 'INVALID_PARAM',
3
+ 'INVALID_NUMBER',
4
+ 'INVALID_DATE',
5
+ 'VALUE_TOO_LONG',
6
+ 'INVALID_GROUPED',
7
+ 'TYPE_MISMATCH',
8
+ 'INVALID_URL'
9
+ ]);
10
+ //# sourceMappingURL=data-issue-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-issue-codes.js","sourceRoot":"","sources":["../../src/core/data-issue-codes.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAA2B,IAAI,GAAG,CAAY;IACzE,eAAe;IACf,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,iBAAiB;IACjB,eAAe;IACf,aAAa;CACd,CAAC,CAAA"}
@@ -1,14 +1,50 @@
1
- import type { FilterState, InternalConfig } from './types.js';
2
- import type { GridApi } from 'ag-grid-community';
1
+ import type { AGGridUrlSyncConfig, FilterState, InternalConfig } from './types.js';
2
+ import type { FilterModel, GridApi } from 'ag-grid-community';
3
3
  /**
4
4
  * Detects the expected filter type for a column based on AG Grid configuration
5
5
  */
6
6
  export declare function detectColumnFilterType(gridApi: GridApi, columnId: string): 'text' | 'number' | 'date';
7
+ /**
8
+ * Gets the current filter model from AG Grid as a filter state. Filter types
9
+ * that the library does not support are skipped, and a filter that is not
10
+ * valid is reported through `options.onParseError`.
11
+ *
12
+ * @param gridApi - AG Grid API instance
13
+ * @param options - Optional options. Only `onParseError` is read.
14
+ */
15
+ export declare function getFilterModel(gridApi: GridApi, options?: AGGridUrlSyncConfig): FilterState;
7
16
  /**
8
17
  * Gets the current filter model from AG Grid
18
+ *
19
+ * @deprecated Give the grid API as an argument:
20
+ * `getFilterModel(gridApi, options)`. This form will be removed in 0.6.0.
9
21
  */
10
22
  export declare function getFilterModel(config: InternalConfig): FilterState;
23
+ /**
24
+ * Converts an AG Grid filter model to URL filters. It does not call the grid.
25
+ * Filter types that the library does not support (set, multi) are skipped.
26
+ */
27
+ export declare function fromGridModel(model: FilterModel | null | undefined, options?: AGGridUrlSyncConfig): FilterState;
28
+ /**
29
+ * Applies a filter state to AG Grid. A filter whose type does not match the
30
+ * column is skipped with a warning. An error from the grid is reported
31
+ * through `options.onParseError`.
32
+ *
33
+ * @param filterState - Filter state to apply
34
+ * @param gridApi - AG Grid API instance
35
+ * @param options - Optional options. Only `onParseError` is read.
36
+ */
37
+ export declare function applyFilterModel(filterState: FilterState, gridApi: GridApi, options?: AGGridUrlSyncConfig): void;
11
38
  /**
12
39
  * Applies a filter state to AG Grid
40
+ *
41
+ * @deprecated Give the grid API as an argument:
42
+ * `applyFilterModel(filterState, gridApi, options)`. This form will be
43
+ * removed in 0.6.0.
13
44
  */
14
45
  export declare function applyFilterModel(filterState: FilterState, config: InternalConfig): void;
46
+ /**
47
+ * Converts URL filters to the AG Grid filter model that `applyFilterModel`
48
+ * would write. It does not call `setFilterModel`.
49
+ */
50
+ export declare function toGridModel(filterState: FilterState, gridApi: GridApi, options?: AGGridUrlSyncConfig): FilterModel;
@@ -1,17 +1,26 @@
1
- import { AG_GRID_OPERATION_NAMES, REVERSE_AG_GRID_OPERATION_NAMES, TEXT_FILTER_OPERATIONS, NUMBER_FILTER_OPERATIONS, DATE_FILTER_OPERATIONS } from './types.js';
2
- const AG_GRID_TO_NUMBER_OPERATION_MAP = {
3
- lessThan: 'lessThan',
4
- lessThanOrEqual: 'lessThanOrEqual',
5
- greaterThan: 'greaterThan',
6
- greaterThanOrEqual: 'greaterThanOrEqual',
7
- inRange: 'inRange',
8
- equals: 'eq',
9
- notEqual: 'notEqual',
10
- blank: 'blank',
11
- notBlank: 'notBlank'
12
- };
13
- function isValidNumberOperation(operation) {
14
- return Boolean(operation && operation in AG_GRID_TO_NUMBER_OPERATION_MAP);
1
+ import * as v from 'valibot';
2
+ import { InvalidFilterError, NUMBER_FILTER_OPERATIONS, isDateFilterOperation, isNumberFilterOperation, isTextFilterOperation } from './types.js';
3
+ import { operatorById, operatorFromAgGrid } from './operators.js';
4
+ import { AgGridFilterSchema, JsonObjectSchema } from './schemas.js';
5
+ import { reportIssue, toIssue } from './issues.js';
6
+ import { readNumber } from './validation.js';
7
+ import { resolveOptions } from './options.js';
8
+ function toAgGridOperation(operation) {
9
+ return operatorById(operation)?.agGrid ?? null;
10
+ }
11
+ function hasGridValue(value) {
12
+ return value !== undefined && value !== null && String(value).trim() !== '';
13
+ }
14
+ function gridNumber(value, column) {
15
+ if (!v.is(v.string(), value))
16
+ return Number(value);
17
+ const number = readNumber(value);
18
+ return number instanceof InvalidFilterError
19
+ ? new InvalidFilterError(`${number.message} (column '${column}')`, undefined, {
20
+ code: 'INVALID_NUMBER',
21
+ column
22
+ })
23
+ : number;
15
24
  }
16
25
  function toIsoDateString(val) {
17
26
  if (!val)
@@ -19,15 +28,6 @@ function toIsoDateString(val) {
19
28
  const match = val.match(/^(\d{4}-\d{2}-\d{2})/);
20
29
  return match?.[1] ? match[1] : val || '';
21
30
  }
22
- function isTextFilterOperation(operation) {
23
- return TEXT_FILTER_OPERATIONS.includes(operation);
24
- }
25
- function isNumberFilterOperation(operation) {
26
- return NUMBER_FILTER_OPERATIONS.includes(operation);
27
- }
28
- function isDateFilterOperation(operation) {
29
- return DATE_FILTER_OPERATIONS.includes(operation);
30
- }
31
31
  export function detectColumnFilterType(gridApi, columnId) {
32
32
  try {
33
33
  const column = gridApi.getColumn(columnId);
@@ -52,90 +52,126 @@ export function detectColumnFilterType(gridApi, columnId) {
52
52
  return 'text';
53
53
  }
54
54
  }
55
- export function getFilterModel(config) {
55
+ export function getFilterModel(source, options) {
56
+ if ('gridApi' in source) {
57
+ return readGridFilters(source.gridApi, resolveOptions(source));
58
+ }
59
+ return readGridFilters(source, resolveOptions(options));
60
+ }
61
+ function readGridFilters(gridApi, options) {
62
+ let model;
56
63
  try {
57
- const model = config.gridApi.getFilterModel();
58
- const filterState = {};
59
- if (!model || typeof model !== 'object') {
60
- return filterState;
64
+ model = gridApi.getFilterModel();
65
+ }
66
+ catch (error) {
67
+ reportIssue(options, toIssue(error, 'GRID_ERROR'));
68
+ return {};
69
+ }
70
+ return fromGridModel(model, options);
71
+ }
72
+ export function fromGridModel(model, options) {
73
+ const resolved = resolveOptions(options);
74
+ const filters = new Map();
75
+ if (!v.is(JsonObjectSchema, model)) {
76
+ return {};
77
+ }
78
+ for (const [column, entry] of Object.entries(model)) {
79
+ const parsed = v.safeParse(AgGridFilterSchema, entry);
80
+ if (!parsed.success)
81
+ continue;
82
+ const filter = parsed.output;
83
+ if (filter.filterType === 'text') {
84
+ const operator = operatorFromAgGrid('text', filter.type);
85
+ if (operator && isTextFilterOperation(operator.id)) {
86
+ filters.set(column, {
87
+ filterType: 'text',
88
+ type: operator.id,
89
+ filter: String(filter.filter || '')
90
+ });
91
+ }
61
92
  }
62
- for (const [column, filter] of Object.entries(model)) {
63
- if (!filter || typeof filter !== 'object')
93
+ else if (filter.filterType === 'number') {
94
+ const operator = operatorFromAgGrid('number', filter.type);
95
+ const internalOperation = operator?.id;
96
+ if (!operator ||
97
+ !internalOperation ||
98
+ !isNumberFilterOperation(internalOperation)) {
99
+ reportIssue(resolved, new InvalidFilterError(`Unknown number filter operation '${filter.type}' for column '${column}'. ` +
100
+ `Supported operations: ${NUMBER_FILTER_OPERATIONS.map(toAgGridOperation).join(', ')}`, undefined, { code: 'INVALID_PARAM', column }));
64
101
  continue;
65
- const { filterType, type, filter: value, filterTo, dateFrom, dateTo } = filter;
66
- if (filterType === 'text') {
67
- const internalOperation = REVERSE_AG_GRID_OPERATION_NAMES[type];
68
- if (internalOperation && isTextFilterOperation(internalOperation)) {
69
- filterState[column] = {
70
- filterType: 'text',
71
- type: internalOperation,
72
- filter: String(value || '')
73
- };
74
- }
75
102
  }
76
- else if (filterType === 'number') {
77
- const internalOperation = isValidNumberOperation(type)
78
- ? AG_GRID_TO_NUMBER_OPERATION_MAP[type]
79
- : null;
80
- if (!internalOperation) {
81
- if (config.onParseError) {
82
- config.onParseError(new Error(`Unknown number filter operation '${type}' for column '${column}'. ` +
83
- `Supported operations: ${Object.keys(AG_GRID_TO_NUMBER_OPERATION_MAP).join(', ')}`));
84
- }
85
- continue;
103
+ if (operator.arity === 0) {
104
+ filters.set(column, {
105
+ filterType: 'number',
106
+ type: internalOperation,
107
+ filter: 0
108
+ });
109
+ continue;
110
+ }
111
+ if (!hasGridValue(filter.filter) ||
112
+ (operator.arity === 2 && !hasGridValue(filter.filterTo))) {
113
+ continue;
114
+ }
115
+ const numericValue = gridNumber(filter.filter, column);
116
+ const numericTo = operator.arity === 2 && hasGridValue(filter.filterTo)
117
+ ? gridNumber(filter.filterTo, column)
118
+ : undefined;
119
+ if (numericValue instanceof InvalidFilterError) {
120
+ reportIssue(resolved, numericValue);
121
+ continue;
122
+ }
123
+ if (numericTo instanceof InvalidFilterError) {
124
+ reportIssue(resolved, numericTo);
125
+ continue;
126
+ }
127
+ if (isNaN(numericValue)) {
128
+ continue;
129
+ }
130
+ filters.set(column, internalOperation === 'inRange' && numericTo !== undefined
131
+ ? {
132
+ filterType: 'number',
133
+ type: internalOperation,
134
+ filter: numericValue,
135
+ filterTo: numericTo
86
136
  }
87
- if (internalOperation && isNumberFilterOperation(internalOperation)) {
88
- const numericValue = typeof value === 'number' ? value : Number(value);
89
- if (isNaN(numericValue)) {
90
- continue;
91
- }
92
- const numberFilter = {
93
- filterType: 'number',
94
- type: internalOperation,
95
- filter: numericValue
96
- };
97
- if (internalOperation === 'inRange' && typeof filterTo === 'number') {
98
- ;
99
- numberFilter.filterTo = filterTo;
100
- }
101
- filterState[column] = numberFilter;
137
+ : {
138
+ filterType: 'number',
139
+ type: internalOperation,
140
+ filter: numericValue
141
+ });
142
+ }
143
+ else {
144
+ const operator = operatorFromAgGrid('date', filter.type);
145
+ const mappedOperation = operator?.id;
146
+ if (operator &&
147
+ mappedOperation &&
148
+ isDateFilterOperation(mappedOperation)) {
149
+ if (operator.arity === 0) {
150
+ filters.set(column, {
151
+ filterType: 'date',
152
+ type: mappedOperation,
153
+ filter: ''
154
+ });
155
+ continue;
102
156
  }
103
- }
104
- else if (filterType === 'date') {
105
- const internalOperation = REVERSE_AG_GRID_OPERATION_NAMES[type];
106
- let mappedOperation = internalOperation;
107
- const AG_GRID_TO_DATE_OPERATION_MAP = {
108
- lessThan: 'dateBefore',
109
- lessThanOrEqual: 'dateBeforeOrEqual',
110
- greaterThan: 'dateAfter',
111
- greaterThanOrEqual: 'dateAfterOrEqual',
112
- inRange: 'dateRange'
113
- };
114
- mappedOperation = type
115
- ? AG_GRID_TO_DATE_OPERATION_MAP[type] || internalOperation
116
- : internalOperation;
117
- if (mappedOperation && isDateFilterOperation(mappedOperation)) {
118
- const dateFilter = {
157
+ const from = toIsoDateString(filter.dateFrom || String(filter.filter || ''));
158
+ const to = operator.arity === 2
159
+ ? toIsoDateString(filter.dateTo ?? undefined)
160
+ : '';
161
+ if (!from || (operator.arity === 2 && !to))
162
+ continue;
163
+ filters.set(column, operator.arity === 2
164
+ ? {
119
165
  filterType: 'date',
120
166
  type: mappedOperation,
121
- filter: toIsoDateString(dateFrom || String(value || ''))
122
- };
123
- if (mappedOperation === 'dateRange' && dateTo) {
124
- ;
125
- dateFilter.filterTo = toIsoDateString(dateTo);
167
+ filter: from,
168
+ filterTo: to
126
169
  }
127
- filterState[column] = dateFilter;
128
- }
170
+ : { filterType: 'date', type: mappedOperation, filter: from });
129
171
  }
130
172
  }
131
- return filterState;
132
- }
133
- catch (error) {
134
- if (config.onParseError) {
135
- config.onParseError(error);
136
- }
137
- return {};
138
173
  }
174
+ return Object.fromEntries(filters);
139
175
  }
140
176
  function convertToAGGridFilter(filter) {
141
177
  if (filter.filterType === 'date') {
@@ -155,23 +191,18 @@ function convertToAGGridFilter(filter) {
155
191
  dateTo: null
156
192
  };
157
193
  }
158
- const dateOperationMapping = {
159
- dateBefore: 'lessThan',
160
- dateBeforeOrEqual: 'lessThanOrEqual',
161
- dateAfter: 'greaterThan',
162
- dateAfterOrEqual: 'greaterThanOrEqual'
163
- };
164
- const agOperation = dateOperationMapping[filter.type] ||
165
- AG_GRID_OPERATION_NAMES[filter.type];
166
194
  return {
167
195
  filterType: 'date',
168
- type: agOperation,
196
+ type: toAgGridOperation(filter.type),
169
197
  dateFrom: filter.filter,
170
198
  dateTo: null
171
199
  };
172
200
  }
173
201
  if (filter.filterType === 'number') {
174
- const agGridOperation = AG_GRID_OPERATION_NAMES[filter.type];
202
+ const agGridOperation = toAgGridOperation(filter.type);
203
+ if (filter.type === 'blank' || filter.type === 'notBlank') {
204
+ return { filterType: 'number', type: agGridOperation, filter: null };
205
+ }
175
206
  if (filter.type === 'inRange') {
176
207
  const baseFilter = {
177
208
  filterType: 'number',
@@ -188,39 +219,49 @@ function convertToAGGridFilter(filter) {
188
219
  filter: filter.filter
189
220
  };
190
221
  }
191
- const agGridOperation = AG_GRID_OPERATION_NAMES[filter.type];
222
+ const agGridOperation = toAgGridOperation(filter.type);
192
223
  return {
193
224
  filterType: 'text',
194
225
  type: agGridOperation,
195
226
  filter: filter.filter
196
227
  };
197
228
  }
198
- export function applyFilterModel(filterState, config) {
229
+ export function applyFilterModel(filterState, target, options) {
230
+ if ('gridApi' in target) {
231
+ writeGridFilters(filterState, target.gridApi, resolveOptions(target));
232
+ return;
233
+ }
234
+ writeGridFilters(filterState, target, resolveOptions(options));
235
+ }
236
+ function writeGridFilters(filterState, gridApi, options) {
237
+ const model = toGridModel(filterState, gridApi, options);
199
238
  try {
200
- const model = {};
201
- for (const [column, filter] of Object.entries(filterState)) {
202
- if (!filter || typeof filter !== 'object')
203
- continue;
204
- const expectedType = detectColumnFilterType(config.gridApi, column);
205
- if (filter.filterType === 'date' && expectedType !== 'date') {
206
- console.warn(`Column '${column}' expects a ${expectedType} filter but received a date filter. This may indicate a configuration mismatch in the column definition or filter application.`);
207
- continue;
208
- }
209
- if (filter.filterType === 'number' && expectedType !== 'number') {
210
- console.warn(`Column '${column}' expects a ${expectedType} filter but received a number filter. This may indicate a configuration mismatch in the column definition or filter application.`);
211
- continue;
212
- }
213
- const agGridFilter = convertToAGGridFilter(filter);
214
- if (agGridFilter) {
215
- model[column] = agGridFilter;
216
- }
217
- }
218
- config.gridApi.setFilterModel(model);
239
+ gridApi.setFilterModel(model);
219
240
  }
220
241
  catch (error) {
221
- if (config.onParseError) {
222
- config.onParseError(error);
242
+ reportIssue(options, toIssue(error, 'GRID_ERROR'));
243
+ }
244
+ }
245
+ export function toGridModel(filterState, gridApi, options) {
246
+ const resolved = resolveOptions(options);
247
+ const model = new Map();
248
+ for (const [column, filter] of Object.entries(filterState)) {
249
+ if (!v.is(JsonObjectSchema, filter))
250
+ continue;
251
+ const expectedType = detectColumnFilterType(gridApi, column);
252
+ if (filter.filterType === 'date' && expectedType !== 'date') {
253
+ reportIssue(resolved, new InvalidFilterError(`Column '${column}' expects a ${expectedType} filter but received a date filter. This may indicate a configuration mismatch in the column definition or filter application.`, undefined, { code: 'TYPE_MISMATCH', column }));
254
+ continue;
255
+ }
256
+ if (filter.filterType === 'number' && expectedType !== 'number') {
257
+ reportIssue(resolved, new InvalidFilterError(`Column '${column}' expects a ${expectedType} filter but received a number filter. This may indicate a configuration mismatch in the column definition or filter application.`, undefined, { code: 'TYPE_MISMATCH', column }));
258
+ continue;
259
+ }
260
+ const agGridFilter = convertToAGGridFilter(filter);
261
+ if (agGridFilter) {
262
+ model.set(column, agGridFilter);
223
263
  }
224
264
  }
265
+ return Object.fromEntries(model);
225
266
  }
226
267
  //# sourceMappingURL=grid-integration.js.map