diff --git a/apps/docs/src/app/components/stackblitz/stackblitz-writer.ts b/apps/docs/src/app/components/stackblitz/stackblitz-writer.ts
index df8de2bbf..740cf1c99 100644
--- a/apps/docs/src/app/components/stackblitz/stackblitz-writer.ts
+++ b/apps/docs/src/app/components/stackblitz/stackblitz-writer.ts
@@ -23,22 +23,34 @@ const TEMPLATE_PATH = 'assets/stackblitz/';
*/
const OPTIONAL_PACKAGE_JSON_DEPENDENCIES = {
'country-flag-icons': {
- 'country-flag-icons': '^1.6.20'
+ 'country-flag-icons': '^1'
},
'@koobiq/components/markdown': {
- marked: '^17.0.3'
+ marked: '^17'
},
'@koobiq/components/input': {
- '@maskito/angular': '^5.0.1',
- '@maskito/kit': '^5.0.1'
+ '@maskito/angular': '^5',
+ '@maskito/kit': '^5'
},
'@koobiq/components/code-block': {
- 'highlight.js': '^11.11.1'
+ 'highlight.js': '^11'
},
'@koobiq/ag-grid-angular-theme': {
'@koobiq/ag-grid-angular-theme': '^34',
'ag-grid-angular': '^34',
'ag-grid-community': '^34'
+ },
+ // Used by packages/docs-examples/components/ag-grid/ag-grid-export/ag-grid-export-example.ts
+ jspdf: {
+ jspdf: '^4'
+ },
+ // Used by packages/docs-examples/components/ag-grid/ag-grid-export/ag-grid-export-example.ts
+ 'jspdf-autotable': {
+ 'jspdf-autotable': '^5'
+ },
+ // Used by packages/docs-examples/components/ag-grid/ag-grid-export/ag-grid-export-example.ts
+ xlsx: {
+ xlsx: '^0.18'
}
} as const;
diff --git a/docs/data-grid/ag-grid/ag-grid.en.md b/docs/data-grid/ag-grid/ag-grid.en.md
index 386412021..859361f33 100644
--- a/docs/data-grid/ag-grid/ag-grid.en.md
+++ b/docs/data-grid/ag-grid/ag-grid.en.md
@@ -54,12 +54,26 @@ The `kbqAgGridRowActions` directive adds an action panel that appears when hover
+### Row grouping
+
+The `kbqAgGridRowGroup` directive implements client-side row grouping. Attach it to `ag-grid-angular`, supply raw data via `[kbqAgGridRowGroupRowData]` instead of `[rowData]`, and set the grouped columns via `[(kbqAgGridRowGroupCols)]`.
+
+Collapsed/expanded group state and row selection can each be persisted independently by setting `kbqAgGridRowGroupCollapsedState` and `kbqAgGridRowGroupSelectionState` to a unique key, connecting store providers via `kbqAgGridRowGroupCollapsedStateStoreProvider` and `kbqAgGridRowGroupSelectionStateStoreProvider`.
+
+
+
### Copying selected rows
The `kbqAgGridCopyByCtrlC` directive allows you to copy selected rows to the clipboard using the `Ctrl+C` keyboard shortcut.
+### Export
+
+The grid's own API can be used to export the currently displayed data (respecting active filters, sorting, and formatters). `api.exportDataAsCsv()` downloads a CSV file with no additional dependencies. Other formats can be built on top of the grid's cell values using third-party libraries — for example, XLSX via [`xlsx`](https://www.npmjs.com/package/xlsx), and PDF via [`jspdf`](https://www.npmjs.com/package/jspdf) with [`jspdf-autotable`](https://www.npmjs.com/package/jspdf-autotable).
+
+
+
### Status bar
The `kbqAgGridStatusBar` directive adds a customizable panel below the table.
@@ -96,6 +110,18 @@ The `kbqAgGridExternalFilterState` directive saves the external filter value. Ad
+#### Rows
+
+The `kbqAgGridRowSelectionState` directive saves row selection. Add it with a unique key, connect the store provider via `kbqAgGridRowSelectionStateStoreProvider`, and set `getRowId`.
+
+
+
+#### Focus
+
+The `kbqAgGridRowFocusState` directive saves the focused cell. Add it with a unique key, connect the store provider via `kbqAgGridRowFocusStateStoreProvider`, and set `getRowId`.
+
+
+
### Column menu
The `kbqAgGridColumnMenu` directive adds a button in the top-right corner of the grid that opens a column management menu. The menu allows showing and hiding columns, reordering them via drag-and-drop, pinning them to the left or right, and searching for a column by name. The reset button restores columns to their initial state.
diff --git a/docs/data-grid/ag-grid/ag-grid.ru.md b/docs/data-grid/ag-grid/ag-grid.ru.md
index e1cd7ba64..a11adabed 100644
--- a/docs/data-grid/ag-grid/ag-grid.ru.md
+++ b/docs/data-grid/ag-grid/ag-grid.ru.md
@@ -54,12 +54,26 @@ import { AgGridModule } from 'ag-grid-angular';
+### Группировка строк
+
+Директива `kbqAgGridRowGroup` реализует группировку строк на стороне клиента. Подключите её к `ag-grid-angular`, передайте исходные данные через `[kbqAgGridRowGroupRowData]` вместо `[rowData]` и укажите колонки группировки через `[(kbqAgGridRowGroupCols)]`.
+
+Состояние свёрнутых/развёрнутых групп и выделение строк можно сохранять независимо друг от друга: укажите уникальный ключ в `kbqAgGridRowGroupCollapsedState` и `kbqAgGridRowGroupSelectionState`, подключив провайдеры хранилища через `kbqAgGridRowGroupCollapsedStateStoreProvider` и `kbqAgGridRowGroupSelectionStateStoreProvider`.
+
+
+
### Копирование выделенных строк
Директива `kbqAgGridCopyByCtrlC` позволяет копировать выделенные строки в буфер обмена при помощи комбинации клавиш `Ctrl+C`.
+### Экспорт
+
+Для экспорта отображаемых данных (с учётом активных фильтров, сортировки и форматирования) можно использовать собственный API таблицы. Метод `api.exportDataAsCsv()` позволяет скачать CSV-файл без дополнительных зависимостей. Другие форматы можно получить на основе значений ячеек таблицы с помощью сторонних библиотек — например, XLSX с помощью [`xlsx`](https://www.npmjs.com/package/xlsx), а PDF — с помощью [`jspdf`](https://www.npmjs.com/package/jspdf) и [`jspdf-autotable`](https://www.npmjs.com/package/jspdf-autotable).
+
+
+
### Панель статуса
Директива `kbqAgGridStatusBar` добавляет настраиваемую панель под таблицей.
@@ -96,6 +110,18 @@ import { AgGridModule } from 'ag-grid-angular';
+#### Строки
+
+Директива `kbqAgGridRowSelectionState` сохраняет выделение строк. Добавьте её с уникальным ключом, подключите провайдер хранилища через `kbqAgGridRowSelectionStateStoreProvider` и укажите `getRowId`.
+
+
+
+#### Фокус
+
+Директива `kbqAgGridRowFocusState` сохраняет сфокусированную ячейку. Добавьте её с уникальным ключом, подключите провайдер хранилища через `kbqAgGridRowFocusStateStoreProvider` и укажите `getRowId`.
+
+
+
### Меню колонок
Директива `kbqAgGridColumnMenu` добавляет в правый верхний угол таблицы кнопку, которая открывает меню управления колонками. В меню можно показывать и скрывать колонки, менять их порядок перетаскиванием, закреплять слева или справа и находить колонку по названию. Кнопка сброса возвращает колонки к исходному состоянию.
diff --git a/package.json b/package.json
index f90ddd787..5bcf118c4 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
"@docsearch/js": "^4.6.3",
"@fontsource/inter": "^5.2.8",
"@fontsource/jetbrains-mono": "^5.2.6",
- "@koobiq/ag-grid-angular-theme": "^34.4.0",
+ "@koobiq/ag-grid-angular-theme": "^34.5.1",
"@koobiq/date-adapter": "^3.5.1",
"@koobiq/date-formatter": "^3.5.1",
"@koobiq/icons": "^11.7.1",
@@ -39,10 +39,13 @@
"ag-grid-angular": "^34.3.1",
"ag-grid-community": "^34.3.1",
"highlight.js": "^11.11.1",
+ "jspdf": "^4.2.1",
+ "jspdf-autotable": "^5.0.8",
"marked": "^17.0.3",
"overlayscrollbars": "2.7.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
+ "xlsx": "^0.18.5",
"zone.js": "~0.16.2"
},
"devDependencies": {
diff --git a/packages/components-dev/ag-grid/module.ts b/packages/components-dev/ag-grid/module.ts
index f53088f70..c8f216718 100644
--- a/packages/components-dev/ag-grid/module.ts
+++ b/packages/components-dev/ag-grid/module.ts
@@ -3,6 +3,7 @@ import {
AgGridColumnMenuExample,
AgGridColumnStateExample,
AgGridCopySelectedExample,
+ AgGridExportExample,
AgGridExternalFilterStateExample,
AgGridFilterStateExample,
AgGridInfiniteSelectionExample,
@@ -11,6 +12,9 @@ import {
AgGridQuickFilterStateExample,
AgGridRowActionsExample,
AgGridRowDraggingExample,
+ AgGridRowFocusStateExample,
+ AgGridRowGroupExample,
+ AgGridRowSelectionStateExample,
AgGridSkeletonCellRendererExample,
AgGridStatusBarExample
} from 'packages/docs-examples/components/ag-grid';
@@ -22,13 +26,17 @@ import { DevThemeToggle } from '../theme-toggle';
AgGridColumnMenuExample,
AgGridOverviewExample,
AgGridRowDraggingExample,
+ AgGridRowGroupExample,
AgGridCopySelectedExample,
+ AgGridExportExample,
AgGridStatusBarExample,
AgGridRowActionsExample,
AgGridColumnStateExample,
AgGridFilterStateExample,
AgGridQuickFilterStateExample,
AgGridExternalFilterStateExample,
+ AgGridRowSelectionStateExample,
+ AgGridRowFocusStateExample,
AgGridLoadingOverlayExample,
AgGridSkeletonCellRendererExample,
AgGridInfiniteSelectionExample
@@ -50,12 +58,20 @@ import { DevThemeToggle } from '../theme-toggle';
+
+
+
+
+
+
+
+
diff --git a/packages/components-dev/ag-grid/styles.scss b/packages/components-dev/ag-grid/styles.scss
index 73f957ca9..ec25f9bd3 100644
--- a/packages/components-dev/ag-grid/styles.scss
+++ b/packages/components-dev/ag-grid/styles.scss
@@ -5,4 +5,5 @@
dev-app {
display: block;
max-width: 608px;
+ padding: var(--kbq-size-s);
}
diff --git a/packages/docs-examples/components/actions-panel/actions-panel-overview/actions-panel-overview-example.ts b/packages/docs-examples/components/actions-panel/actions-panel-overview/actions-panel-overview-example.ts
index 61a15a6cf..1f215523b 100644
--- a/packages/docs-examples/components/actions-panel/actions-panel-overview/actions-panel-overview-example.ts
+++ b/packages/docs-examples/components/actions-panel/actions-panel-overview/actions-panel-overview-example.ts
@@ -139,7 +139,6 @@ export class ExampleGrid {
node.setSelected(true);
}
});
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
this.api = api;
}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-column-state/ag-grid-column-state-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-column-state/ag-grid-column-state-example.ts
index d2d165105..774799c4e 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-column-state/ag-grid-column-state-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-column-state/ag-grid-column-state-example.ts
@@ -17,12 +17,12 @@ ModuleRegistry.registerModules([AllCommunityModule]);
selector: 'ag-grid-column-state-example',
imports: [AgGridModule, KbqAgGridThemeModule, KbqButtonModule],
template: `
- Reset state
+ Reset column state
+ Download CSV
+ Download XLSX
+ Download PDF
+
+
+
+ `,
+ styles: `
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--kbq-size-m);
+ }
+
+ .ag-grid-export-example-actions {
+ display: flex;
+ gap: var(--kbq-size-m);
+ }
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AgGridExportExample {
+ private readonly api = signal(null);
+ private readonly filename = 'example-export';
+ protected readonly defaultColDef: ColDef = {
+ sortable: true,
+ resizable: true,
+ filter: true,
+ floatingFilter: true
+ };
+ protected readonly columnDefs: ColDef[] = [
+ { field: 'column0', headerName: 'Project name', width: 130 },
+ { field: 'column1', headerName: 'Column 1', width: 130 },
+ { field: 'column2', headerName: 'Column 2', width: 130 },
+ { field: 'column3', headerName: 'Column 3', width: 130 },
+ { field: 'column4', headerName: 'Column 4', width: 130 }
+ ];
+ protected readonly rowData = Array.from({ length: 20 }, (_, index) => ({
+ column0: 'Project name ' + index,
+ column1: 'Text ' + index,
+ column2: 'Text ' + index,
+ column3: 'Text ' + index,
+ column4: 'Text ' + index
+ }));
+
+ /** Stores the grid API once the grid finishes initializing. */
+ protected onGridReady({ api }: GridReadyEvent): void {
+ this.api.set(api);
+ }
+
+ /** Downloads the grid data as a .csv file. */
+ protected downloadCsv(): void {
+ this.api()?.exportDataAsCsv({ fileName: `${this.filename}.csv` });
+ }
+
+ /** Downloads the grid data as an .xlsx file. */
+ protected downloadXlsx(): void {
+ const table = this.getExportTable();
+
+ if (!table) return;
+
+ const worksheet = utils.aoa_to_sheet([table.headers, ...table.rows]);
+ const workbook = utils.book_new();
+
+ utils.book_append_sheet(workbook, worksheet, 'Export');
+ writeFile(workbook, `${this.filename}.xlsx`);
+ }
+
+ /** Downloads the grid data as a .pdf file. */
+ protected downloadPdf(): void {
+ const table = this.getExportTable();
+
+ if (!table) return;
+
+ const pdf = new jsPDF({ orientation: 'landscape' });
+
+ autoTable(pdf, { head: [table.headers], body: table.rows, theme: 'plain' });
+ pdf.save(`${this.filename}.pdf`);
+ }
+
+ /** Reads the currently displayed columns and rows (respecting filter, sort and formatters). */
+ private getExportTable(): ExportTable | null {
+ const api = this.api();
+
+ if (!api) return null;
+
+ const columns = api.getAllDisplayedColumns();
+ const headers = columns.map((column) => column.getColDef().headerName ?? column.getColId());
+ const rows: string[][] = [];
+
+ api.forEachNodeAfterFilterAndSort((node) => {
+ if (!node.data) return;
+
+ rows.push(
+ columns.map((column) => api.getCellValue({ rowNode: node, colKey: column, useFormatter: true }) ?? '')
+ );
+ });
+
+ return { headers, rows };
+ }
+}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-external-filter-state/ag-grid-external-filter-state-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-external-filter-state/ag-grid-external-filter-state-example.ts
index d09c703e7..72ab9534f 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-external-filter-state/ag-grid-external-filter-state-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-external-filter-state/ag-grid-external-filter-state-example.ts
@@ -31,7 +31,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
Reset state
+ Reset filter state
({
column5: 'Text ' + index
}));
+/**
+ * Shape actually worth sending to a backend. `KbqAgGridInfiniteSelectionState.excludedIds` is only
+ * meaningful while `selectAll` is `true` — outside select-all mode, the directive leaves individual
+ * row selection entirely to AG Grid's own API, so `includedIds` has to be read from there instead.
+ * Both fields are always present so the inapplicable one reads as an explicit `null`, not a missing key.
+ */
+type SelectionDto = {
+ selectAll: boolean;
+ includedIds: readonly string[] | null;
+ excludedIds: readonly string[] | null;
+};
+
/**
* @title AG Grid with infinite selection
*/
@@ -37,7 +52,6 @@ const ROW_DATA = Array.from({ length: 1000 }, (_, index) => ({
imports: [AgGridModule, KbqAgGridThemeModule, JsonPipe],
template: `
({
[columnDefs]="columnDefs"
[defaultColDef]="defaultColDef"
[rowSelection]="rowSelection"
+ [selectionColumnDef]="selectionColumnDef"
[kbqAgGridInfiniteSelectionDatasource]="datasource"
[getRowId]="getRowId"
[cacheBlockSize]="10"
(kbqAgGridInfiniteSelectionStateChange)="onSelectAllChange($event)"
+ (selectionChanged)="onSelectionChanged($event)"
/>
- {{ selection.state() | json }}
+
+
DTO sent to the backend:
+
{{ selectionDto() | json }}
+
`,
styles: `
:host {
@@ -67,25 +86,31 @@ const ROW_DATA = Array.from({ length: 1000 }, (_, index) => ({
height: 300px;
}
+ .ag-grid-infinite-selection-example-dto {
+ display: flex;
+ flex-direction: column;
+ gap: var(--kbq-size-s);
+ width: 180px;
+ font-size: var(--kbq-typography-text-compact-font-size);
+ color: var(--kbq-foreground-contrast-secondary);
+ }
+
pre {
margin: 0;
- width: 180px;
max-height: 300px;
overflow: scroll;
- font-size: var(--kbq-typography-text-compact-font-size);
- color: var(--kbq-foreground-contrast-secondary);
}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AgGridInfiniteSelectionExample {
protected readonly columnDefs: ColDef[] = [
- { field: 'column0', headerName: 'Project name' },
- { field: 'column1', headerName: 'Text' },
- { field: 'column2', headerName: 'Text' },
- { field: 'column3', headerName: 'Text' },
- { field: 'column4', headerName: 'Text' },
- { field: 'column5', headerName: 'Text' }
+ { field: 'column0', headerName: 'Project name', pinned: 'left', width: 130 },
+ { field: 'column1', headerName: 'Text', width: 130 },
+ { field: 'column2', headerName: 'Text', width: 130 },
+ { field: 'column3', headerName: 'Text', width: 130 },
+ { field: 'column4', headerName: 'Text', width: 130 },
+ { field: 'column5', headerName: 'Text', width: 130 }
];
protected readonly datasource: IDatasource = {
rowCount: ROW_DATA.length,
@@ -102,8 +127,39 @@ export class AgGridInfiniteSelectionExample {
mode: 'multiRow',
isRowSelectable: ({ data }) => data !== undefined
};
+ protected readonly selectionColumnDef: SelectionColumnDef = {
+ pinned: 'left'
+ };
+ private readonly infiniteSelection = viewChild.required(KbqAgGridInfiniteSelection);
+ private readonly includedIds = signal([]);
+
+ /**
+ * The DTO this example would send to the backend for the current selection — combines the
+ * directive's own `selectAll`/`excludedIds` state with `includedIds` tracked separately via
+ * AG Grid's native selection, since the directive only maintains `excludedIds` while
+ * `selectAll` is `true` (see `SelectionDto`).
+ */
+ protected readonly selectionDto = computed(() => {
+ const state = this.infiniteSelection().state();
+
+ return {
+ selectAll: state.selectAll,
+ includedIds: state.selectAll ? null : this.includedIds(),
+ excludedIds: state.selectAll ? state.excludedIds : null
+ };
+ });
protected onSelectAllChange(state: KbqAgGridInfiniteSelectionState): void {
console.debug('onSelectAllChange: ', state);
}
+
+ /** Tracks individually selected row ids — only meaningful while `selectAll` is `false`. */
+ protected onSelectionChanged({ api }: SelectionChangedEvent): void {
+ this.includedIds.set(
+ api
+ .getSelectedNodes()
+ .map((node) => node.id)
+ .filter((id) => id !== undefined)
+ );
+ }
}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-loading-overlay/ag-grid-loading-overlay-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-loading-overlay/ag-grid-loading-overlay-example.ts
index afd837a6b..19de76839 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-loading-overlay/ag-grid-loading-overlay-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-loading-overlay/ag-grid-loading-overlay-example.ts
@@ -42,7 +42,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
width: 100%;
}
`,
- providers: [kbqAgGridLoadingOverlayConfigProvider({ rows: 6, cols: 4 })],
+ providers: [kbqAgGridLoadingOverlayConfigProvider({ rows: 6, cols: 3 })],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AgGridLoadingOverlayExample {
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-overview/ag-grid-overview-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-overview/ag-grid-overview-example.ts
index 10884b6e2..80c859dfd 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-overview/ag-grid-overview-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-overview/ag-grid-overview-example.ts
@@ -148,7 +148,5 @@ export class AgGridOverviewExample {
node.setSelected(true);
}
});
-
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
}
}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-quick-filter-state/ag-grid-quick-filter-state-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-quick-filter-state/ag-grid-quick-filter-state-example.ts
index 6ec425637..7be3bd789 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-quick-filter-state/ag-grid-quick-filter-state-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-quick-filter-state/ag-grid-quick-filter-state-example.ts
@@ -28,7 +28,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
#quickFilterState="kbqAgGridQuickFilterState"
kbqAgGridTheme
kbqAgGridThemeDisableCellFocusStyles
- kbqAgGridQuickFilterState="dev-ag-grid-quick-filter-state"
+ kbqAgGridQuickFilterState="example-ag-grid-quick-filter-state"
[alwaysMultiSort]="true"
[rowData]="rowData"
[columnDefs]="columnDefs"
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-row-actions/ag-grid-row-actions-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-row-actions/ag-grid-row-actions-example.ts
index 1f12bd8f8..b51f465c7 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-row-actions/ag-grid-row-actions-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-row-actions/ag-grid-row-actions-example.ts
@@ -155,7 +155,5 @@ export class AgGridRowActionsExample {
node.setSelected(true);
}
});
-
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
}
}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-row-dragging/ag-grid-row-dragging-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-row-dragging/ag-grid-row-dragging-example.ts
index 668b2f9e4..08f3ff8d9 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-row-dragging/ag-grid-row-dragging-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-row-dragging/ag-grid-row-dragging-example.ts
@@ -117,7 +117,5 @@ export class AgGridRowDraggingExample {
node.setSelected(true);
}
});
-
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
}
}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-row-focus-state/ag-grid-row-focus-state-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-row-focus-state/ag-grid-row-focus-state-example.ts
new file mode 100644
index 000000000..15fefdcfd
--- /dev/null
+++ b/packages/docs-examples/components/ag-grid/ag-grid-row-focus-state/ag-grid-row-focus-state-example.ts
@@ -0,0 +1,63 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import {
+ KbqAgGridRowFocusStateLocalStorageStore,
+ kbqAgGridRowFocusStateStoreProvider,
+ KbqAgGridThemeModule
+} from '@koobiq/ag-grid-angular-theme';
+import { KbqButtonModule } from '@koobiq/components/button';
+import { AgGridModule } from 'ag-grid-angular';
+import { AllCommunityModule, ColDef, GetRowIdParams, ModuleRegistry } from 'ag-grid-community';
+
+ModuleRegistry.registerModules([AllCommunityModule]);
+
+/**
+ * @title AG Grid with `KbqAgGridRowFocusState` directive
+ */
+@Component({
+ selector: 'ag-grid-row-focus-state-example',
+ imports: [AgGridModule, KbqAgGridThemeModule, KbqButtonModule],
+ template: `
+ Reset focus state
+
+
+ `,
+ styles: `
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--kbq-size-m);
+ }
+ `,
+ providers: [
+ kbqAgGridRowFocusStateStoreProvider(KbqAgGridRowFocusStateLocalStorageStore)
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AgGridRowFocusStateExample {
+ protected readonly getRowId = (params: GetRowIdParams): string => params.data.column0;
+ protected readonly columnDefs: ColDef[] = [
+ { field: 'column0', headerName: 'Column 0', width: 130 },
+ { field: 'column1', headerName: 'Column 1', width: 130 },
+ { field: 'column2', headerName: 'Column 2', width: 130 },
+ { field: 'column3', headerName: 'Column 3', width: 130 },
+ { field: 'column4', headerName: 'Column 4', width: 130 }
+ ];
+ protected readonly rowData = Array.from({ length: 100 }, (_, index) => ({
+ column0: 'Text ' + index,
+ column1: 'Text ' + index,
+ column2: 'Text ' + index,
+ column3: 'Text ' + index,
+ column4: 'Text ' + index
+ }));
+}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-row-group/ag-grid-row-group-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-row-group/ag-grid-row-group-example.ts
new file mode 100644
index 000000000..b02a388d2
--- /dev/null
+++ b/packages/docs-examples/components/ag-grid/ag-grid-row-group/ag-grid-row-group-example.ts
@@ -0,0 +1,109 @@
+import { ChangeDetectionStrategy, Component, model } from '@angular/core';
+import {
+ KbqAgGridRowGroup,
+ KbqAgGridRowGroupCollapsedStateLocalStorageStore,
+ kbqAgGridRowGroupCollapsedStateStoreProvider,
+ kbqAgGridRowGroupColOptionsProvider,
+ KbqAgGridRowGroupSelectionStateLocalStorageStore,
+ kbqAgGridRowGroupSelectionStateStoreProvider,
+ KbqAgGridThemeModule
+} from '@koobiq/ag-grid-angular-theme';
+import { KbqButtonModule } from '@koobiq/components/button';
+import { AgGridModule } from 'ag-grid-angular';
+import { AllCommunityModule, ColDef, ModuleRegistry, RowSelectionOptions } from 'ag-grid-community';
+
+ModuleRegistry.registerModules([AllCommunityModule]);
+
+const CATEGORIES = ['BruteForce', 'Complex Attack', 'DDoS', 'HIPS alert', 'IDS/IPS Alert', 'XSS'];
+const SEVERITIES = ['Low', 'Medium', 'High', 'Critical'];
+
+/**
+ * @title AG Grid with `KbqAgGridRowGroup` directive
+ */
+@Component({
+ selector: 'ag-grid-row-group-example',
+ imports: [AgGridModule, KbqAgGridThemeModule, KbqButtonModule],
+ template: `
+
+ Clear collapsed state
+ Clear selection state
+
+
+
+ `,
+ styles: `
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--kbq-size-m);
+ }
+
+ .ag-grid-row-group-example-actions {
+ display: flex;
+ gap: var(--kbq-size-m);
+ }
+ `,
+ providers: [
+ kbqAgGridRowGroupCollapsedStateStoreProvider(KbqAgGridRowGroupCollapsedStateLocalStorageStore),
+ kbqAgGridRowGroupSelectionStateStoreProvider(KbqAgGridRowGroupSelectionStateLocalStorageStore),
+ kbqAgGridRowGroupColOptionsProvider({ headerName: 'Group' })
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AgGridRowGroupExample {
+ protected readonly groupCols = model(['category', 'severity']);
+ protected readonly rowId = (row: Record): string => row.id as string;
+ protected readonly defaultColDef: ColDef = {
+ sortable: true,
+ resizable: true,
+ width: 140
+ };
+ protected readonly rowSelection: RowSelectionOptions = {
+ mode: 'multiRow',
+ headerCheckbox: true,
+ checkboxes: true
+ };
+ protected readonly columnDefs: ColDef[] = [
+ { field: 'column0', headerName: 'Column 0', width: 130 },
+ { field: 'category', headerName: 'Category', width: 130 },
+ { field: 'severity', headerName: 'Severity', width: 130 },
+ { field: 'column3', headerName: 'Column 3', width: 130 },
+ { field: 'column4', headerName: 'Column 4', width: 130 },
+ { field: 'column5', headerName: 'Column 5', width: 130 },
+ { field: 'column6', headerName: 'Column 6', width: 130 }
+ ];
+
+ protected readonly rowData = Array.from({ length: 24 }, (_, index) => ({
+ id: String(index),
+ column0: 'Text ' + index,
+ category: CATEGORIES[index % CATEGORIES.length],
+ severity: SEVERITIES[index % SEVERITIES.length],
+ column3: 'Text ' + index,
+ column4: 'Text ' + index,
+ column5: 'Text ' + index,
+ column6: 'Text ' + index
+ }));
+
+ /** Deselects every data row, including rows hidden inside a collapsed group. */
+ protected clearSelectionState(rowGroup: KbqAgGridRowGroup): void {
+ for (const row of this.rowData) {
+ rowGroup.setRowSelected(row.id, false);
+ }
+ }
+}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-row-selection-state/ag-grid-row-selection-state-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-row-selection-state/ag-grid-row-selection-state-example.ts
new file mode 100644
index 000000000..6d4667a96
--- /dev/null
+++ b/packages/docs-examples/components/ag-grid/ag-grid-row-selection-state/ag-grid-row-selection-state-example.ts
@@ -0,0 +1,74 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import {
+ KbqAgGridRowSelectionStateLocalStorageStore,
+ kbqAgGridRowSelectionStateStoreProvider,
+ KbqAgGridThemeModule
+} from '@koobiq/ag-grid-angular-theme';
+import { KbqButtonModule } from '@koobiq/components/button';
+import { AgGridModule } from 'ag-grid-angular';
+import { AllCommunityModule, ColDef, GetRowIdParams, ModuleRegistry, RowSelectionOptions } from 'ag-grid-community';
+
+ModuleRegistry.registerModules([AllCommunityModule]);
+
+/**
+ * @title AG Grid with `KbqAgGridRowSelectionState` directive
+ */
+@Component({
+ selector: 'ag-grid-row-selection-state-example',
+ imports: [AgGridModule, KbqAgGridThemeModule, KbqButtonModule],
+ template: `
+ Reset selection state
+
+
+ `,
+ styles: `
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--kbq-size-m);
+ }
+ `,
+ providers: [
+ kbqAgGridRowSelectionStateStoreProvider(KbqAgGridRowSelectionStateLocalStorageStore)
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AgGridRowSelectionStateExample {
+ protected readonly getRowId = (params: GetRowIdParams): string => params.data.column0;
+ protected readonly defaultColDef: ColDef = {
+ sortable: true,
+ resizable: true
+ };
+ protected readonly rowSelection: RowSelectionOptions = {
+ mode: 'multiRow',
+ headerCheckbox: true,
+ checkboxes: true
+ };
+ protected readonly columnDefs: ColDef[] = [
+ { field: 'column0', headerName: 'Column 0', width: 130 },
+ { field: 'column1', headerName: 'Column 1', width: 130 },
+ { field: 'column2', headerName: 'Column 2', width: 130 },
+ { field: 'column3', headerName: 'Column 3', width: 130 },
+ { field: 'column4', headerName: 'Column 4', width: 130 }
+ ];
+ protected readonly rowData = Array.from({ length: 100 }, (_, index) => ({
+ column0: 'Text ' + index,
+ column1: 'Text ' + index,
+ column2: 'Text ' + index,
+ column3: 'Text ' + index,
+ column4: 'Text ' + index
+ }));
+}
diff --git a/packages/docs-examples/components/ag-grid/ag-grid-status-bar/ag-grid-status-bar-example.ts b/packages/docs-examples/components/ag-grid/ag-grid-status-bar/ag-grid-status-bar-example.ts
index 1afc9ae75..e599f1bd5 100644
--- a/packages/docs-examples/components/ag-grid/ag-grid-status-bar/ag-grid-status-bar-example.ts
+++ b/packages/docs-examples/components/ag-grid/ag-grid-status-bar/ag-grid-status-bar-example.ts
@@ -161,7 +161,5 @@ export class AgGridStatusBarExample {
node.setSelected(true);
}
});
-
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
}
}
diff --git a/packages/docs-examples/components/ag-grid/index.ts b/packages/docs-examples/components/ag-grid/index.ts
index 87b6f3706..016874aaf 100644
--- a/packages/docs-examples/components/ag-grid/index.ts
+++ b/packages/docs-examples/components/ag-grid/index.ts
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
import { AgGridColumnMenuExample } from './ag-grid-column-menu/ag-grid-column-menu-example';
import { AgGridColumnStateExample } from './ag-grid-column-state/ag-grid-column-state-example';
import { AgGridCopySelectedExample } from './ag-grid-copy-selected/ag-grid-copy-selected-example';
+import { AgGridExportExample } from './ag-grid-export/ag-grid-export-example';
import { AgGridExternalFilterStateExample } from './ag-grid-external-filter-state/ag-grid-external-filter-state-example';
import { AgGridFilterStateExample } from './ag-grid-filter-state/ag-grid-filter-state-example';
import { AgGridInfiniteSelectionExample } from './ag-grid-infinite-selection/ag-grid-infinite-selection-example';
@@ -10,6 +11,9 @@ import { AgGridOverviewExample } from './ag-grid-overview/ag-grid-overview-examp
import { AgGridQuickFilterStateExample } from './ag-grid-quick-filter-state/ag-grid-quick-filter-state-example';
import { AgGridRowActionsExample } from './ag-grid-row-actions/ag-grid-row-actions-example';
import { AgGridRowDraggingExample } from './ag-grid-row-dragging/ag-grid-row-dragging-example';
+import { AgGridRowFocusStateExample } from './ag-grid-row-focus-state/ag-grid-row-focus-state-example';
+import { AgGridRowGroupExample } from './ag-grid-row-group/ag-grid-row-group-example';
+import { AgGridRowSelectionStateExample } from './ag-grid-row-selection-state/ag-grid-row-selection-state-example';
import { AgGridSkeletonCellRendererExample } from './ag-grid-skeleton-cell-renderer/ag-grid-skeleton-cell-renderer-example';
import { AgGridStatusBarExample } from './ag-grid-status-bar/ag-grid-status-bar-example';
@@ -17,6 +21,7 @@ export {
AgGridColumnMenuExample,
AgGridColumnStateExample,
AgGridCopySelectedExample,
+ AgGridExportExample,
AgGridExternalFilterStateExample,
AgGridFilterStateExample,
AgGridInfiniteSelectionExample,
@@ -25,6 +30,9 @@ export {
AgGridQuickFilterStateExample,
AgGridRowActionsExample,
AgGridRowDraggingExample,
+ AgGridRowFocusStateExample,
+ AgGridRowGroupExample,
+ AgGridRowSelectionStateExample,
AgGridSkeletonCellRendererExample,
AgGridStatusBarExample
};
@@ -33,13 +41,17 @@ const EXAMPLES = [
AgGridColumnMenuExample,
AgGridOverviewExample,
AgGridRowDraggingExample,
+ AgGridRowGroupExample,
AgGridCopySelectedExample,
+ AgGridExportExample,
AgGridStatusBarExample,
AgGridRowActionsExample,
AgGridColumnStateExample,
AgGridFilterStateExample,
AgGridQuickFilterStateExample,
AgGridExternalFilterStateExample,
+ AgGridRowSelectionStateExample,
+ AgGridRowFocusStateExample,
AgGridLoadingOverlayExample,
AgGridSkeletonCellRendererExample,
AgGridInfiniteSelectionExample
diff --git a/packages/docs-examples/components/content-panel/content-panel-with-grid/content-panel-with-grid-example.ts b/packages/docs-examples/components/content-panel/content-panel-with-grid/content-panel-with-grid-example.ts
index 3470c438d..9bc8c20c4 100644
--- a/packages/docs-examples/components/content-panel/content-panel-with-grid/content-panel-with-grid-example.ts
+++ b/packages/docs-examples/components/content-panel/content-panel-with-grid/content-panel-with-grid-example.ts
@@ -89,8 +89,6 @@ export class ExampleGrid {
node.setSelected(true);
}
});
-
- api.setColumnWidths([{ key: 'ag-Grid-SelectionColumn', newWidth: 36 }]);
}
}
diff --git a/tools/cspell-locales/en.json b/tools/cspell-locales/en.json
index b3a5393a1..d2be387a7 100644
--- a/tools/cspell-locales/en.json
+++ b/tools/cspell-locales/en.json
@@ -7,6 +7,7 @@
"words": [
"actionbar",
"autoselect",
+ "autotable",
"behaviour",
"bento",
"codeowners",
diff --git a/tools/validate-licenses/validate-licenses.ts b/tools/validate-licenses/validate-licenses.ts
index 922488ec4..12e7c58e1 100644
--- a/tools/validate-licenses/validate-licenses.ts
+++ b/tools/validate-licenses/validate-licenses.ts
@@ -19,6 +19,10 @@ const licensesWhitelist: License[] = [
'BSD-3-Clause',
'BSD-4-Clause',
+ // OSI-approved, permissive (same tier as MIT/BSD). Reaches the tree via
+ // jspdf -> fast-png -> pako, a transitive dependency of jspdf (used by the ag-grid PDF export docs example).
+ 'Zlib',
+
// All CC-BY licenses have a full copyright grant and attribution section.
'CC-BY-3.0',
'CC-BY-4.0',
diff --git a/yarn.lock b/yarn.lock
index c324047f5..9c62715fb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2946,6 +2946,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.28.6":
+ version: 7.29.7
+ resolution: "@babel/runtime@npm:7.29.7"
+ checksum: 10c0/ca11572f7146b21e0bde6a9ed4bb6a89eafbee5f0944c7eb54d0d8a2dac962c33638a1d611e14faa71dfbb92b4b5f9236232208568a6b7d5c6f3f39ddb91771e
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/template@npm:7.24.7"
@@ -6039,9 +6046,9 @@ __metadata:
languageName: node
linkType: hard
-"@koobiq/ag-grid-angular-theme@npm:^34.4.0":
- version: 34.4.0
- resolution: "@koobiq/ag-grid-angular-theme@npm:34.4.0"
+"@koobiq/ag-grid-angular-theme@npm:^34.5.1":
+ version: 34.5.1
+ resolution: "@koobiq/ag-grid-angular-theme@npm:34.5.1"
dependencies:
tslib: "npm:^2.3.0"
peerDependencies:
@@ -6051,7 +6058,7 @@ __metadata:
"@koobiq/icons": ">=9.0.0"
ag-grid-angular: ^34.0.0
ag-grid-community: ^34.0.0
- checksum: 10c0/788e3f9505345e759163d5643666d389d68e6c5715cea272cad8b1d7cda348906b8fbf6e32f600bd7d512fa7afe663e02f7a0b87894acc748ecb798c23c0a390
+ checksum: 10c0/0531fc2b2409e09a6d17f2d467ca7ebba8d70a0465587de81a42522c76843a3fadf88e8a91f09a4237d74fe0f11f1281828c7a8ff7bbde8298336dd02ffefd3e
languageName: node
linkType: hard
@@ -8998,6 +9005,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/pako@npm:^2.0.3":
+ version: 2.0.4
+ resolution: "@types/pako@npm:2.0.4"
+ checksum: 10c0/5765bf8bc7e77ee141c454118f03e544b8f6cb51eb257d82dc5830feeab8cd00818af3a1eabefdfbe8dd3ae9916ed5403937bf1031a0ee51deea27fdf4dccdfb
+ languageName: node
+ linkType: hard
+
"@types/qs@npm:*":
version: 6.9.13
resolution: "@types/qs@npm:6.9.13"
@@ -9005,6 +9019,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/raf@npm:^3.4.0":
+ version: 3.4.3
+ resolution: "@types/raf@npm:3.4.3"
+ checksum: 10c0/dea835f0daa399c51db9137f5337dc08a2b4a5f61f645658966ecabaebbbd0fd59551f384a1141e14e22a1cc5a591da7d4d88c60a525ad1399108b6dd2641d75
+ languageName: node
+ linkType: hard
+
"@types/range-parser@npm:*":
version: 1.2.7
resolution: "@types/range-parser@npm:1.2.7"
@@ -9134,6 +9155,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/trusted-types@npm:^2.0.7":
+ version: 2.0.7
+ resolution: "@types/trusted-types@npm:2.0.7"
+ checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c
+ languageName: node
+ linkType: hard
+
"@types/ws@npm:<8.18.2":
version: 8.18.1
resolution: "@types/ws@npm:8.18.1"
@@ -9877,6 +9905,13 @@ __metadata:
languageName: node
linkType: hard
+"adler-32@npm:~1.3.0":
+ version: 1.3.1
+ resolution: "adler-32@npm:1.3.1"
+ checksum: 10c0/c1b7185526ee1bbe0eac8ed414d5226af4cd02a0540449a72ec1a75f198c5e93352ba4d7b9327231eea31fd83c2d080d13baf16d8ed5710fb183677beb85f612
+ languageName: node
+ linkType: hard
+
"ag-charts-types@npm:12.3.1":
version: 12.3.1
resolution: "ag-charts-types@npm:12.3.1"
@@ -10607,6 +10642,13 @@ __metadata:
languageName: node
linkType: hard
+"base64-arraybuffer@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "base64-arraybuffer@npm:1.0.2"
+ checksum: 10c0/3acac95c70f9406e87a41073558ba85b6be9dbffb013a3d2a710e3f2d534d506c911847d5d9be4de458af6362c676de0a5c4c2d7bdf4def502d00b313368e72f
+ languageName: node
+ linkType: hard
+
"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
@@ -11225,6 +11267,22 @@ __metadata:
languageName: node
linkType: hard
+"canvg@npm:^3.0.11":
+ version: 3.0.11
+ resolution: "canvg@npm:3.0.11"
+ dependencies:
+ "@babel/runtime": "npm:^7.12.5"
+ "@types/raf": "npm:^3.4.0"
+ core-js: "npm:^3.8.3"
+ raf: "npm:^3.4.1"
+ regenerator-runtime: "npm:^0.13.7"
+ rgbcolor: "npm:^1.0.1"
+ stackblur-canvas: "npm:^2.0.0"
+ svg-pathdata: "npm:^6.0.3"
+ checksum: 10c0/03ea5b69e97a4a476ef5fc8455d0da2718bd68cd8ace3e42718176bf4b7dfd80eb1d0eba47dcd04b34ed9a0c5c8ed849ead0f364dad0e35369254a45d5e098c4
+ languageName: node
+ linkType: hard
+
"capital-case@npm:^1.0.4":
version: 1.0.4
resolution: "capital-case@npm:1.0.4"
@@ -11236,6 +11294,16 @@ __metadata:
languageName: node
linkType: hard
+"cfb@npm:~1.2.1":
+ version: 1.2.2
+ resolution: "cfb@npm:1.2.2"
+ dependencies:
+ adler-32: "npm:~1.3.0"
+ crc-32: "npm:~1.2.0"
+ checksum: 10c0/87f6d9c3878268896ed6ca29dfe32a2aa078b12d0f21d8405c95911b74ab6296823d7312bbf5e18326d00b16cc697f587e07a17018c5edf7a1ba31dd5bc6da36
+ languageName: node
+ linkType: hard
+
"chalk-template@npm:^1.1.0":
version: 1.1.0
resolution: "chalk-template@npm:1.1.0"
@@ -11576,6 +11644,13 @@ __metadata:
languageName: node
linkType: hard
+"codepage@npm:~1.15.0":
+ version: 1.15.0
+ resolution: "codepage@npm:1.15.0"
+ checksum: 10c0/2455b482302cb784b46dea60a8ee83f0c23e794bdd979556bdb107abe681bba722af62a37f5c955ff4efd68fdb9688c3986e719b4fd536c0e06bb25bc82abea3
+ languageName: node
+ linkType: hard
+
"collect-v8-coverage@npm:^1.0.2":
version: 1.0.3
resolution: "collect-v8-coverage@npm:1.0.3"
@@ -12196,6 +12271,13 @@ __metadata:
languageName: node
linkType: hard
+"core-js@npm:^3.6.0, core-js@npm:^3.8.3":
+ version: 3.49.0
+ resolution: "core-js@npm:3.49.0"
+ checksum: 10c0/2e42edb47eda38fd5368380131623c8aa5d4a6b42164125b17744bdc08fa5ebbbdd06b4b4aa6ca3663470a560b0f2fba48e18f142dfe264b0039df85bc625694
+ languageName: node
+ linkType: hard
+
"core-util-is@npm:^1.0.3, core-util-is@npm:~1.0.0":
version: 1.0.3
resolution: "core-util-is@npm:1.0.3"
@@ -12250,7 +12332,7 @@ __metadata:
languageName: node
linkType: hard
-"crc-32@npm:^1.2.0":
+"crc-32@npm:^1.2.0, crc-32@npm:~1.2.0, crc-32@npm:~1.2.1":
version: 1.2.2
resolution: "crc-32@npm:1.2.2"
bin:
@@ -12463,6 +12545,15 @@ __metadata:
languageName: node
linkType: hard
+"css-line-break@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "css-line-break@npm:2.1.0"
+ dependencies:
+ utrie: "npm:^1.0.2"
+ checksum: 10c0/b2222d99d5daf7861ecddc050244fdce296fad74b000dcff6bdfb1eb16dc2ef0b9ffe2c1c965e3239bd05ebe9eadb6d5438a91592fa8648d27a338e827cf9048
+ languageName: node
+ linkType: hard
+
"css-loader@npm:7.1.2":
version: 7.1.2
resolution: "css-loader@npm:7.1.2"
@@ -13030,6 +13121,18 @@ __metadata:
languageName: node
linkType: hard
+"dompurify@npm:^3.3.1":
+ version: 3.4.12
+ resolution: "dompurify@npm:3.4.12"
+ dependencies:
+ "@types/trusted-types": "npm:^2.0.7"
+ dependenciesMeta:
+ "@types/trusted-types":
+ optional: true
+ checksum: 10c0/127a13817353d4e20e75a991a9022a04c3af12af7479f68e2b8bee6dbc7330a96edfb8f4ebff96f4f0f24cd43e8dbba46214131f510c3aa87a843bd8b610d0ab
+ languageName: node
+ linkType: hard
+
"domutils@npm:^3.2.1, domutils@npm:^3.2.2":
version: 3.2.2
resolution: "domutils@npm:3.2.2"
@@ -14545,6 +14648,17 @@ __metadata:
languageName: node
linkType: hard
+"fast-png@npm:^6.2.0":
+ version: 6.4.0
+ resolution: "fast-png@npm:6.4.0"
+ dependencies:
+ "@types/pako": "npm:^2.0.3"
+ iobuffer: "npm:^5.3.2"
+ pako: "npm:^2.1.0"
+ checksum: 10c0/bca27a09d56a5ead536b11c1ddccf4fe44c7c0af88a8faefab6a397527d9c71b00c09b2055d0108807c438c50719dd2acbd7217ef88785b500888db26fa0358a
+ languageName: node
+ linkType: hard
+
"fast-uri@npm:^3.0.1":
version: 3.0.1
resolution: "fast-uri@npm:3.0.1"
@@ -14627,6 +14741,13 @@ __metadata:
languageName: node
linkType: hard
+"fflate@npm:^0.8.1":
+ version: 0.8.3
+ resolution: "fflate@npm:0.8.3"
+ checksum: 10c0/eab181ca37f5348ae76d4b6f840e0026e30220e33153289ac942222d8b9638237d486507dbcc09878d724095bd354993a2ee48bbee99c8f2c6440d4448719aa7
+ languageName: node
+ linkType: hard
+
"figures@npm:^3.0.0":
version: 3.2.0
resolution: "figures@npm:3.2.0"
@@ -15010,6 +15131,13 @@ __metadata:
languageName: node
linkType: hard
+"frac@npm:~1.1.2":
+ version: 1.1.2
+ resolution: "frac@npm:1.1.2"
+ checksum: 10c0/640740eb58b590eb38c78c676955bee91cd22d854f5876241a15c49d4495fa53a84898779dcf7eca30aabfe1c1a4a705752b5f224934257c5dda55c545413ba7
+ languageName: node
+ linkType: hard
+
"fraction.js@npm:^4.3.7":
version: 4.3.7
resolution: "fraction.js@npm:4.3.7"
@@ -15979,6 +16107,16 @@ __metadata:
languageName: node
linkType: hard
+"html2canvas@npm:^1.0.0-rc.5":
+ version: 1.4.1
+ resolution: "html2canvas@npm:1.4.1"
+ dependencies:
+ css-line-break: "npm:^2.1.0"
+ text-segmentation: "npm:^1.0.3"
+ checksum: 10c0/6de86f75762b00948edf2ea559f16da0a1ec3facc4a8a7d3f35fcec59bb0c5970463478988ae3d9082152e0173690d46ebf4082e7ac803dd4817bae1d355c0db
+ languageName: node
+ linkType: hard
+
"htmlparser2@npm:^10.0.0":
version: 10.0.0
resolution: "htmlparser2@npm:10.0.0"
@@ -16445,6 +16583,13 @@ __metadata:
languageName: node
linkType: hard
+"iobuffer@npm:^5.3.2":
+ version: 5.4.0
+ resolution: "iobuffer@npm:5.4.0"
+ checksum: 10c0/1b3f9a5ea158bc63f038b374b42832acdb9db13ea9cfa4ed78723f30894986442f6c033dff4ae2fdf34724bf0fe432e3b86c11ca82049568c58b8d7fb47a6ac2
+ languageName: node
+ linkType: hard
+
"ip-address@npm:^10.0.1":
version: 10.1.0
resolution: "ip-address@npm:10.1.0"
@@ -18126,6 +18271,39 @@ __metadata:
languageName: node
linkType: hard
+"jspdf-autotable@npm:^5.0.8":
+ version: 5.0.8
+ resolution: "jspdf-autotable@npm:5.0.8"
+ peerDependencies:
+ jspdf: ^2 || ^3 || ^4
+ checksum: 10c0/c5e695d6d31692b9d2c11d284948ad508fc3e616d0b555119451dfd307176bdd80c880459cef6fee9e7db5140272b6fa281ee0ffaeeffddca6bf2497b577b40e
+ languageName: node
+ linkType: hard
+
+"jspdf@npm:^4.2.1":
+ version: 4.2.1
+ resolution: "jspdf@npm:4.2.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.28.6"
+ canvg: "npm:^3.0.11"
+ core-js: "npm:^3.6.0"
+ dompurify: "npm:^3.3.1"
+ fast-png: "npm:^6.2.0"
+ fflate: "npm:^0.8.1"
+ html2canvas: "npm:^1.0.0-rc.5"
+ dependenciesMeta:
+ canvg:
+ optional: true
+ core-js:
+ optional: true
+ dompurify:
+ optional: true
+ html2canvas:
+ optional: true
+ checksum: 10c0/d905809b374de1060ab39ba4b1603935fcced314bef8f63f7fd272d3f96eff0b50a96e48d3c2063ac8e51b84a1442464ff2b037af13f54b082e456416da470b7
+ languageName: node
+ linkType: hard
+
"jwa@npm:^2.0.1":
version: 2.0.1
resolution: "jwa@npm:2.0.1"
@@ -18230,7 +18408,7 @@ __metadata:
"@eslint/js": "npm:^9.0.0"
"@fontsource/inter": "npm:^5.2.8"
"@fontsource/jetbrains-mono": "npm:^5.2.6"
- "@koobiq/ag-grid-angular-theme": "npm:^34.4.0"
+ "@koobiq/ag-grid-angular-theme": "npm:^34.5.1"
"@koobiq/date-adapter": "npm:^3.5.1"
"@koobiq/date-formatter": "npm:^3.5.1"
"@koobiq/design-tokens": "npm:^3.17.2"
@@ -18300,6 +18478,8 @@ __metadata:
jest-environment-jsdom: "npm:^30.4.1"
jest-fail-on-console: "npm:^3.3.4"
jest-preset-angular: "npm:^16.2.0"
+ jspdf: "npm:^4.2.1"
+ jspdf-autotable: "npm:^5.0.8"
license-checker: "npm:^25.0.1"
lint-staged: "npm:^15.5.2"
luxon: "npm:^3.7.2"
@@ -18333,6 +18513,7 @@ __metadata:
tslib: "npm:^2.8.1"
typescript: "npm:5.8.3"
typescript-eslint: "npm:^8.60.1"
+ xlsx: "npm:^0.18.5"
zone.js: "npm:~0.16.2"
languageName: unknown
linkType: soft
@@ -20815,6 +20996,13 @@ __metadata:
languageName: node
linkType: hard
+"pako@npm:^2.1.0":
+ version: 2.2.0
+ resolution: "pako@npm:2.2.0"
+ checksum: 10c0/e5d31de1940fdd13cc4014296b0026112483d0834bce4856ca29c8af8438d030c6416986a0f6df7d5372cae18d6dd6c57f48b24a49d6c207c0a4cc66af15c07d
+ languageName: node
+ linkType: hard
+
"param-case@npm:^3.0.4":
version: 3.0.4
resolution: "param-case@npm:3.0.4"
@@ -21111,6 +21299,13 @@ __metadata:
languageName: node
linkType: hard
+"performance-now@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "performance-now@npm:2.1.0"
+ checksum: 10c0/22c54de06f269e29f640e0e075207af57de5052a3d15e360c09b9a8663f393f6f45902006c1e71aa8a5a1cdfb1a47fe268826f8496d6425c362f00f5bc3e85d9
+ languageName: node
+ linkType: hard
+
"pg-cloudflare@npm:^1.2.5":
version: 1.2.5
resolution: "pg-cloudflare@npm:1.2.5"
@@ -21994,6 +22189,15 @@ __metadata:
languageName: node
linkType: hard
+"raf@npm:^3.4.1":
+ version: 3.4.1
+ resolution: "raf@npm:3.4.1"
+ dependencies:
+ performance-now: "npm:^2.1.0"
+ checksum: 10c0/337f0853c9e6a77647b0f499beedafea5d6facfb9f2d488a624f88b03df2be72b8a0e7f9118a3ff811377d534912039a3311815700d2b6d2313f82f736f9eb6e
+ languageName: node
+ linkType: hard
+
"railroad-diagrams@npm:^1.0.0":
version: 1.0.0
resolution: "railroad-diagrams@npm:1.0.0"
@@ -22317,6 +22521,13 @@ __metadata:
languageName: node
linkType: hard
+"regenerator-runtime@npm:^0.13.7":
+ version: 0.13.11
+ resolution: "regenerator-runtime@npm:0.13.11"
+ checksum: 10c0/12b069dc774001fbb0014f6a28f11c09ebfe3c0d984d88c9bced77fdb6fedbacbca434d24da9ae9371bfbf23f754869307fb51a4c98a8b8b18e5ef748677ca24
+ languageName: node
+ linkType: hard
+
"regex-parser@npm:^2.2.11":
version: 2.3.0
resolution: "regex-parser@npm:2.3.0"
@@ -22640,6 +22851,13 @@ __metadata:
languageName: node
linkType: hard
+"rgbcolor@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "rgbcolor@npm:1.0.1"
+ checksum: 10c0/13af06c523351bac2854b85a22d1dfafd9310efd898e9bd96c8706f9aa09a3ddc8392ab00ae03d12950782164a97677f21834ffd84ffebf76ae106add319f956
+ languageName: node
+ linkType: hard
+
"rimraf@npm:^5.0.1, rimraf@npm:^5.0.10":
version: 5.0.10
resolution: "rimraf@npm:5.0.10"
@@ -24106,6 +24324,15 @@ __metadata:
languageName: node
linkType: hard
+"ssf@npm:~0.11.2":
+ version: 0.11.2
+ resolution: "ssf@npm:0.11.2"
+ dependencies:
+ frac: "npm:~1.1.2"
+ checksum: 10c0/c3fd24a90dc37a9dc5c4154cb4121e27507c33ebfeee3532aaf03625756b2c006cf79c0a23db0ba16c4a6e88e1349455327867e03453fc9d54b32c546bc18ca6
+ languageName: node
+ linkType: hard
+
"ssri@npm:^10.0.0":
version: 10.0.5
resolution: "ssri@npm:10.0.5"
@@ -24140,6 +24367,13 @@ __metadata:
languageName: node
linkType: hard
+"stackblur-canvas@npm:^2.0.0":
+ version: 2.7.0
+ resolution: "stackblur-canvas@npm:2.7.0"
+ checksum: 10c0/df290d0629056d5bb43d37548d0b24cb8593c79d742650e68489abf61013db578c9980724c2508bb738d107204f2e2494ab94c3cf69d6b725caa9c63b8c7e272
+ languageName: node
+ linkType: hard
+
"statuses@npm:2.0.1":
version: 2.0.1
resolution: "statuses@npm:2.0.1"
@@ -24557,6 +24791,13 @@ __metadata:
languageName: node
linkType: hard
+"svg-pathdata@npm:^6.0.3":
+ version: 6.0.3
+ resolution: "svg-pathdata@npm:6.0.3"
+ checksum: 10c0/1ba4ad2fa81e86df37d6e78d3be9e664bbedf97773b725a863a85db384285be32dc37d9c0d61e477d89594ee95b967d2c53d6bee2d76420aab670ab4124a38b9
+ languageName: node
+ linkType: hard
+
"svg-tags@npm:^1.0.0":
version: 1.0.0
resolution: "svg-tags@npm:1.0.0"
@@ -24801,6 +25042,15 @@ __metadata:
languageName: node
linkType: hard
+"text-segmentation@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "text-segmentation@npm:1.0.3"
+ dependencies:
+ utrie: "npm:^1.0.2"
+ checksum: 10c0/8b9ae8524e3a332371060d0ca62f10ad49a13e954719ea689a6c3a8b8c15c8a56365ede2bb91c322fb0d44b6533785f0da603e066b7554d052999967fb72d600
+ languageName: node
+ linkType: hard
+
"thenify-all@npm:^1.0.0":
version: 1.6.0
resolution: "thenify-all@npm:1.6.0"
@@ -25890,6 +26140,15 @@ __metadata:
languageName: node
linkType: hard
+"utrie@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "utrie@npm:1.0.2"
+ dependencies:
+ base64-arraybuffer: "npm:^1.0.2"
+ checksum: 10c0/eaffe645bd81a39e4bc3abb23df5895e9961dbdd49748ef3b173529e8b06ce9dd1163e9705d5309a1c61ee41ffcb825e2043bc0fd1659845ffbdf4b1515dfdb4
+ languageName: node
+ linkType: hard
+
"uuid@npm:^8.0.0, uuid@npm:^8.3.2":
version: 8.3.2
resolution: "uuid@npm:8.3.2"
@@ -26459,6 +26718,20 @@ __metadata:
languageName: node
linkType: hard
+"wmf@npm:~1.0.1":
+ version: 1.0.2
+ resolution: "wmf@npm:1.0.2"
+ checksum: 10c0/3fa5806f382632cadfe65d4ef24f7a583b0c0720171edb00e645af5248ad0bb6784e8fcee1ccd9f475a1a12a7523e2512e9c063731fbbdae14dc469e1c033d93
+ languageName: node
+ linkType: hard
+
+"word@npm:~0.3.0":
+ version: 0.3.0
+ resolution: "word@npm:0.3.0"
+ checksum: 10c0/c6da2a9f7a0d81a32fa6768a638d21b153da2be04f94f3964889c7cc1365d74b6ecb43b42256c3f926cd59512d8258206991c78c21000c3da96d42ff1238b840
+ languageName: node
+ linkType: hard
+
"wordwrap@npm:^1.0.0":
version: 1.0.0
resolution: "wordwrap@npm:1.0.0"
@@ -26614,6 +26887,23 @@ __metadata:
languageName: node
linkType: hard
+"xlsx@npm:^0.18.5":
+ version: 0.18.5
+ resolution: "xlsx@npm:0.18.5"
+ dependencies:
+ adler-32: "npm:~1.3.0"
+ cfb: "npm:~1.2.1"
+ codepage: "npm:~1.15.0"
+ crc-32: "npm:~1.2.1"
+ ssf: "npm:~0.11.2"
+ wmf: "npm:~1.0.1"
+ word: "npm:~0.3.0"
+ bin:
+ xlsx: bin/xlsx.njs
+ checksum: 10c0/787cfa77034a3e86fdcde21572f1011c8976f87823a5e0ee5057f13b2f6e48f17a1710732a91b8ae15d7794945c7cba8a3ca904ea7150e028260b0ab8e1158c8
+ languageName: node
+ linkType: hard
+
"xml-name-validator@npm:^4.0.0":
version: 4.0.0
resolution: "xml-name-validator@npm:4.0.0"