onekijs-ui 0.19.20 → 0.19.21

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.
@@ -1,6 +1,6 @@
1
1
  import { AnonymousObject, CollectionService } from 'onekijs-framework';
2
2
  import React from 'react';
3
- import { TableColumn, TableColumnWidth, TableConfig, TableController, TableItem, TableState } from './typings';
3
+ import { TableColumn, TableColumnWidth, TableConfig, TableController, TableItem, TableSerializerFormat, TableState } from './typings';
4
4
  export declare const parseColumnWidth: (width?: string | number) => TableColumnWidth;
5
5
  declare class TableService<T = any, I extends TableItem<T> = TableItem<T>, S extends TableState<T, I> = TableState<T, I>> extends CollectionService<T, I, S> implements TableController<T, I> {
6
6
  protected cells: AnonymousObject<AnonymousObject<React.RefObject<HTMLDivElement>>>;
@@ -13,6 +13,7 @@ declare class TableService<T = any, I extends TableItem<T> = TableItem<T>, S ext
13
13
  initCell(rowNumber: number | 'header-title' | 'header-filter' | 'footer', colId: string, ref: React.RefObject<HTMLDivElement>): void;
14
14
  removeColumn(id: string): void;
15
15
  resetWidth(): void;
16
+ serialize(data: T[], format: TableSerializerFormat): string;
16
17
  toggle(item: I): void;
17
18
  protected _setCellWidth(fit: boolean): void;
18
19
  }
@@ -0,0 +1,3 @@
1
+ import { TableCellSerializer } from '../typings';
2
+ declare const defaultCellSerializer: TableCellSerializer<any, any>;
3
+ export default defaultCellSerializer;
@@ -92,6 +92,7 @@ export type TableBodyRowProps<T = any, I extends TableItem<T> = TableItem<T>> =
92
92
  onCollapsing?: (item: I | undefined, index: number) => void;
93
93
  onCollapsed?: (item: I | undefined, index: number) => void;
94
94
  };
95
+ export type TableSerializerFormat = 'csv' | 'json';
95
96
  export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
96
97
  autoRefresh?: number;
97
98
  bodyClassName?: string;
@@ -127,6 +128,7 @@ export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
127
128
  preload?: number;
128
129
  rowClassName?: string | ((item: I | undefined, rowIndex: number, columns: TableColumn<T, I>[]) => string);
129
130
  RowComponent?: React.FC<TableBodyRowProps<T, I>>;
131
+ serializer?: (data: T[], format: TableSerializerFormat) => string;
130
132
  sortable?: boolean;
131
133
  stripRows?: boolean;
132
134
  tail?: boolean;
@@ -147,6 +149,7 @@ export type TableController<T = any, I extends TableItem<T> = TableItem<T>, S ex
147
149
  initCell(rowIndex: number | 'header-title' | 'header-filter' | 'footer', colId: string, ref: React.RefObject<HTMLDivElement>): void;
148
150
  removeColumn(id: string): void;
149
151
  removeSelected<B extends keyof CollectionBy<T, I>>(by: B, target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][]): I[];
152
+ serialize: (data: T[], format: TableSerializerFormat) => string;
150
153
  setSelected<B extends keyof CollectionBy<T, I>>(by: B, target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][]): I[];
151
154
  startAutoRefresh: (interval: number) => void;
152
155
  stopAutoRefresh: () => void;
@@ -167,6 +170,7 @@ export type TableCellDisplayerProps<T, I extends TableItem<T> = TableItem<T>> =
167
170
  value: T;
168
171
  format: FormDisplayerProps['format'];
169
172
  };
173
+ export type TableCellSerializer<T, I extends TableItem<T> = TableItem<T>> = (data: T, column: TableColumn<T, I>, format: TableSerializerFormat) => any;
170
174
  export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
171
175
  className?: string | ((item: I, column: TableColumn<T, I>, rowIndex: number) => string);
172
176
  CellComponent?: Cell<T, I>;
@@ -177,15 +181,16 @@ export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
177
181
  filterable?: boolean;
178
182
  FilterComponent?: React.FC<TableHeaderCellProps<T, I>>;
179
183
  headerClassName?: string | ((column: TableColumn<T, I>) => string);
184
+ help?: ReactNode;
180
185
  id: string;
181
186
  maxWidth?: string;
182
187
  minWidth?: string;
188
+ serializer?: TableCellSerializer<T, I>;
183
189
  sortable?: boolean;
184
190
  title?: string;
185
191
  TitleComponent?: React.FC<TableHeaderCellProps<T, I>>;
186
192
  weight?: number;
187
193
  width?: string;
188
- help?: ReactNode;
189
194
  };
190
195
  export type TableColumnWidth = {
191
196
  auto?: boolean;
package/dist/index.d.ts CHANGED
@@ -160,7 +160,7 @@ export { default as useTextColumn } from './components/table/hooks/useTextColumn
160
160
  export { default as useTextareaColumn } from './components/table/hooks/useTextareaColumn';
161
161
  export { default as FormCardDisplayer } from './components/card/FormCardDisplayer';
162
162
  export { filterListStyle, tableStyle } from './components/table/style';
163
- export { ArrayTableProps, Cell, CheckboxColumn, CheckboxColumnOptions, ControllerTableProps, EnumColumnOptions, FormCellDisplayerProps, FormTableContext, FormTableItemDisplayerProps, FormTableProps, TableValueDisplayerProps, InputColumn, InputColumnOptions, LinkColumnOptions, SelectCell, SelectColumn, SelectColumnOptions, TableBodyCellProps, TableBodyProps, TableBodyRowProps, TableCellDisplayerProps, TableColumn, TableColumnComputedWidth, TableColumnOptions, TableColumnSpec, TableColumnWidth, TableColumnsState, TableConfig, TableController, TableExpandedProps, TableFilterOperator, TableFilterOperatorProps, TableFooterCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableItem, TableItemAdaptee, TableItemAdapter, TableItems, TableNotFoundProps, TableProps, TableRowHandler, TableSortProps, TableState, TextareaColumn, TextareaColumnOptions, UseTableController, UseTableOptions, } from './components/table/typings';
163
+ export { ArrayTableProps, Cell, CheckboxColumn, CheckboxColumnOptions, ControllerTableProps, EnumColumnOptions, FormCellDisplayerProps, FormTableContext, FormTableItemDisplayerProps, FormTableProps, TableValueDisplayerProps, InputColumn, InputColumnOptions, LinkColumnOptions, SelectCell, SelectColumn, SelectColumnOptions, TableBodyCellProps, TableBodyProps, TableBodyRowProps, TableCellDisplayerProps, TableColumn, TableColumnComputedWidth, TableColumnOptions, TableColumnSpec, TableColumnWidth, TableColumnsState, TableConfig, TableController, TableExpandedProps, TableFilterOperator, TableFilterOperatorProps, TableFooterCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableItem, TableItemAdaptee, TableItemAdapter, TableItems, TableNotFoundProps, TableProps, TableRowHandler, TableSortProps, TableState, TextareaColumn, TextareaColumnOptions, UseTableController, UseTableOptions, TableCellSerializer, TableSerializerFormat } from './components/table/typings';
164
164
  export { default as Tag } from './components/tag';
165
165
  export { default as TagComponent } from './components/tag/components/TagComponent';
166
166
  export { tagStyle } from './components/tag/style';
@@ -182,6 +182,7 @@ export { default as ArrayTreeComponent } from './components/tree/components/Arra
182
182
  export { default as ControllerTreeComponent } from './components/tree/components/ControllerTreeComponent';
183
183
  export { default as TreeBodyComponent } from './components/tree/components/TreeBodyComponent';
184
184
  export { default as TreeComponent } from './components/tree/components/TreeComponent';
185
+ export { default as defaultCellSerializer } from './components/table/seralizers/defaultCellSerializer';
185
186
  export { default as TreeItemComponent, TreeItemContent, TreeItemToggler, } from './components/tree/components/TreeItemComponent';
186
187
  export { default as TreeListComponent } from './components/tree/components/TreeListComponent';
187
188
  export { default as VirtualTreeBodyComponent } from './components/tree/components/VirtualTreeBodyComponent';
package/dist/index.js CHANGED
@@ -405,6 +405,24 @@ const enumFormatter = (values) => {
405
405
  return String(value);
406
406
  };
407
407
  };
408
+ const escapeCsvValue = (value, separator = ',') => {
409
+ const escape = (value) => {
410
+ if (Array.isArray(value)) {
411
+ return value.map((v) => escape(v)).join(',');
412
+ }
413
+ if (value === null || value === undefined)
414
+ return '';
415
+ return `${value}`;
416
+ };
417
+ const result = escape(value);
418
+ if (result.startsWith('"') && result.endsWith('"'))
419
+ return result; // the string is already escaped
420
+ // escape only if the string contains the separator
421
+ if (result.includes(separator)) {
422
+ return `"${result.replace(/"/g, '""')}"`;
423
+ }
424
+ return result;
425
+ };
408
426
  const pxFormatter = (value) => {
409
427
  if (typeof value === 'string') {
410
428
  return value;
@@ -9182,6 +9200,36 @@ let TableService = class TableService extends onekijsFramework.CollectionService
9182
9200
  column.computedWidth = undefined;
9183
9201
  });
9184
9202
  }
9203
+ serialize(data, format) {
9204
+ const serializer = this.config?.serializer;
9205
+ if (serializer) {
9206
+ return serializer(data, format);
9207
+ }
9208
+ const serializableColumns = (this.state.columns || []).filter((c) => c.serializer !== undefined);
9209
+ switch (format) {
9210
+ case 'csv':
9211
+ let result = 'sep=,';
9212
+ const header = serializableColumns.map((c) => escapeCsvValue(onekijsFramework.get(c, 'title', onekijsFramework.get(c, 'id')))).join(',');
9213
+ result = `${result}\n${header}`;
9214
+ const csvRows = data.map((row) => {
9215
+ const columns = serializableColumns
9216
+ .map((c) => c.serializer(row, c, format))
9217
+ .map((s) => {
9218
+ return escapeCsvValue(s, ',');
9219
+ });
9220
+ return columns.join(',');
9221
+ });
9222
+ return `${result}\n${csvRows.join('\n')}`;
9223
+ case 'json':
9224
+ const rows = data.map((row) => {
9225
+ return serializableColumns.reduce((accumulator, c) => {
9226
+ accumulator[c.title ?? c.id] = c.serializer(row, c, format);
9227
+ return accumulator;
9228
+ }, {});
9229
+ });
9230
+ return JSON.stringify(rows);
9231
+ }
9232
+ }
9185
9233
  toggle(item) {
9186
9234
  this.setMeta('item', item, 'expanded', !item.expanded);
9187
9235
  }
@@ -10482,6 +10530,10 @@ const DefaultFormCellDisplayer = (props) => {
10482
10530
  return null;
10483
10531
  };
10484
10532
 
10533
+ const defaultCellSerializer = (data, column) => {
10534
+ return onekijsFramework.get(data, column.id, null);
10535
+ };
10536
+
10485
10537
  const checkboxColumn = (id, options) => {
10486
10538
  const Component = options.CellComponent || CheckboxCellComponent;
10487
10539
  return Object.assign({
@@ -10489,6 +10541,7 @@ const checkboxColumn = (id, options) => {
10489
10541
  sortable: false,
10490
10542
  className: 'o-checkbox-cell',
10491
10543
  Displayer: DefaultFormCellDisplayer,
10544
+ serializer: defaultCellSerializer,
10492
10545
  }, options, {
10493
10546
  id,
10494
10547
  CellComponent: Component(options),
@@ -10541,12 +10594,28 @@ const TableSelectFilterComponent = ({ column, dataSource, }) => {
10541
10594
  TableSelectFilterComponent.displayName = 'TableInputFilterComponent';
10542
10595
 
10543
10596
  const enumColumn = (id, options) => {
10597
+ const serializer = (data, column, format) => {
10598
+ const value = onekijsFramework.get(data, column.id, null);
10599
+ const entry = options.filterDataSource.find((item) => {
10600
+ if (Array.isArray(item)) {
10601
+ if (item[0] === value) {
10602
+ return true;
10603
+ }
10604
+ }
10605
+ return false;
10606
+ });
10607
+ if (entry) {
10608
+ return entry[1];
10609
+ }
10610
+ return defaultCellSerializer(data, column);
10611
+ };
10544
10612
  return Object.assign({
10545
10613
  CellComponent: DefaultCellComponent,
10546
10614
  filterable: true,
10547
10615
  FilterComponent: (props) => (React.createElement(TableSelectFilterComponent, { ...props, dataSource: options.filterDataSource })),
10548
10616
  sortable: true,
10549
10617
  Displayer: DefaultFormCellDisplayer,
10618
+ serializer,
10550
10619
  }, options, {
10551
10620
  id,
10552
10621
  });
@@ -10570,6 +10639,7 @@ const inputColumn = (id, options) => {
10570
10639
  filterable: false,
10571
10640
  sortable: false,
10572
10641
  Displayer: DefaultFormCellDisplayer,
10642
+ serializer: defaultCellSerializer,
10573
10643
  }, options, {
10574
10644
  id,
10575
10645
  CellComponent: Component(options),
@@ -10593,6 +10663,7 @@ const textColumn = (id, options) => {
10593
10663
  FilterComponent: TableTextFilterComponent,
10594
10664
  sortable: true,
10595
10665
  Displayer: DefaultFormCellDisplayer,
10666
+ serializer: defaultCellSerializer,
10596
10667
  }, options, {
10597
10668
  id,
10598
10669
  });
@@ -10624,6 +10695,7 @@ const numberColumn = (id, options) => {
10624
10695
  FilterComponent: TableNumberFilterComponent,
10625
10696
  sortable: true,
10626
10697
  Displayer: DefaultFormCellDisplayer,
10698
+ serializer: defaultCellSerializer,
10627
10699
  }, options, {
10628
10700
  id,
10629
10701
  });
@@ -10663,12 +10735,30 @@ const selectColumn = (id, options) => {
10663
10735
  };
10664
10736
  opts.adapter = adapter;
10665
10737
  }
10738
+ const serializer = (data, column, format) => {
10739
+ const value = onekijsFramework.get(data, column.id, null);
10740
+ if (Array.isArray(opts.dataSource)) {
10741
+ const entry = opts.dataSource.find((item) => {
10742
+ if (Array.isArray(item)) {
10743
+ if (item[0] === value) {
10744
+ return true;
10745
+ }
10746
+ }
10747
+ return false;
10748
+ });
10749
+ if (entry && Array.isArray(entry)) {
10750
+ return entry[1];
10751
+ }
10752
+ }
10753
+ return defaultCellSerializer(data, column);
10754
+ };
10666
10755
  const broker = new DefaultSelectBroker(dataSource, opts);
10667
10756
  const Component = opts.CellComponent || SelectCellComponent;
10668
10757
  return Object.assign({
10669
10758
  filterable: false,
10670
10759
  sortable: false,
10671
10760
  Displayer: DefaultFormCellDisplayer,
10761
+ serializer,
10672
10762
  }, opts, {
10673
10763
  id,
10674
10764
  CellComponent: Component(opts, broker),
@@ -10820,6 +10910,7 @@ const textareaColumn = (id, options) => {
10820
10910
  filterable: false,
10821
10911
  sortable: false,
10822
10912
  Displayer: DefaultFormCellDisplayer,
10913
+ serializer: defaultCellSerializer,
10823
10914
  }, options, {
10824
10915
  id,
10825
10916
  CellComponent: Component(options),
@@ -12611,6 +12702,7 @@ exports.cssProperty = cssProperty;
12611
12702
  exports.cursor = cursor;
12612
12703
  exports.darken = darken;
12613
12704
  exports.dashboardOverlayStyle = dashboardOverlayStyle;
12705
+ exports.defaultCellSerializer = defaultCellSerializer;
12614
12706
  exports.defaultTreeQueryEngine = defaultTreeQueryEngine;
12615
12707
  exports.deriveColor = deriveColor;
12616
12708
  exports.display = display;
@@ -12619,6 +12711,7 @@ exports.dropdownStyle = dropdownStyle;
12619
12711
  exports.emptyCells = emptyCells;
12620
12712
  exports.enumColumn = enumColumn;
12621
12713
  exports.enumFormatter = enumFormatter;
12714
+ exports.escapeCsvValue = escapeCsvValue;
12622
12715
  exports.fieldDescriptionStyle = fieldDescriptionStyle;
12623
12716
  exports.fieldDisplayerStyle = fieldDisplayerStyle;
12624
12717
  exports.fieldHelpStyle = fieldHelpStyle;