@monolith-forensics/monolith-ui 1.3.116-dev.1 → 1.3.116-dev.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.
@@ -20,13 +20,13 @@ export type Operator = {
20
20
  label: string;
21
21
  value: string;
22
22
  };
23
- export type EditorType = "text" | "select" | "checkbox" | "radio" | "multiselect" | "date" | "time" | null;
23
+ export type InputType = "text" | "number" | "date" | "datetime" | "multiselect";
24
24
  export interface FilterDefinition {
25
25
  dataField: string;
26
26
  label: string;
27
27
  pluralLabel?: string;
28
28
  operators?: Operator[];
29
- inputType?: HTMLInputElement["type"];
29
+ inputType?: InputType;
30
30
  resolution?: "day" | "second" | "millisecond";
31
31
  isoString?: boolean;
32
32
  placeholder?: string;
@@ -34,7 +34,6 @@ export interface FilterDefinition {
34
34
  dropDownOptions?: {
35
35
  style?: React.CSSProperties;
36
36
  };
37
- editorType?: EditorType;
38
37
  query?: DropDownMenuProps["query"];
39
38
  }
40
39
  export interface Rule {
@@ -30,7 +30,7 @@ const FlexedRow = styled.div `
30
30
  `;
31
31
  const TableMenu = () => {
32
32
  var _a, _b, _c, _d, _e;
33
- const { data, columnState, searchState, toggleColumnVisibility, tableMenuOptions, runSearch, enableSelection, compactState, toggleCompact, totalRecords, getCalculatedSelectionTotal, filterState, handleFilterChange, clearSearch, } = useTable();
33
+ const { data, columnState, searchState, toggleColumnVisibility, tableMenuOptions, runSearch, enableSelection, compactState, toggleCompact, totalRecords, getCalculatedSelectionTotal, handleTableExport, filterState, handleFilterChange, clearSearch, } = useTable();
34
34
  const inputRef = useRef(null);
35
35
  if ((tableMenuOptions === null || tableMenuOptions === void 0 ? void 0 : tableMenuOptions.enabled) !== true)
36
36
  return null;
@@ -111,10 +111,7 @@ const TableMenu = () => {
111
111
  title: "Export List to XLSX",
112
112
  size: "xxs",
113
113
  style: { padding: "0px 4px" },
114
- }, onItemSelect: (item) => {
115
- var _a, _b;
116
- return (_b = (_a = tableMenuOptions === null || tableMenuOptions === void 0 ? void 0 : tableMenuOptions.exportOptions) === null || _a === void 0 ? void 0 : _a.onExport) === null || _b === void 0 ? void 0 : _b.call(_a, item.value);
117
- }, dropDownProps: {
114
+ }, onItemSelect: (item) => void handleTableExport(item.value), dropDownProps: {
118
115
  style: { width: 175, maxWidth: 400 },
119
116
  }, children: _jsx(DownloadIcon, { size: 14 }) })), (compactOptions === null || compactOptions === void 0 ? void 0 : compactOptions.enabled) === true && (_jsx(Button, { variant: "outlined", title: "Toggle Compact", size: "xxs", style: { padding: "0px 4px" }, onClick: () => toggleCompact(), children: compactState ? _jsx(Rows4Icon, { size: 14 }) : _jsx(Rows3Icon, { size: 14 }) })), (columnSelectorOptions === null || columnSelectorOptions === void 0 ? void 0 : columnSelectorOptions.enabled) === true && (_jsx(DropDownMenu, { variant: "outlined", size: "xs", data: columnState.map((col) => ({
120
117
  label: (col === null || col === void 0 ? void 0 : col.caption) || col.dataField,
@@ -1,3 +1,12 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  var __rest = (this && this.__rest) || function (s, e) {
2
11
  var t = {};
3
12
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -18,6 +27,7 @@ import shortUUID from "short-uuid";
18
27
  import { SelectionStatus } from "./enums";
19
28
  import moment from "moment";
20
29
  import { useControlled } from "../Utilities";
30
+ import { exportTableToExcel } from "./Utils";
21
31
  const calculateSelectionTotal = (selectionState, totalRecords, dataLength = 0) => {
22
32
  if (!selectionState) {
23
33
  return 0;
@@ -37,7 +47,7 @@ const calculateSelectionTotal = (selectionState, totalRecords, dataLength = 0) =
37
47
  };
38
48
  export const TableContext = createContext(null);
39
49
  const TableProvider = (_a) => {
40
- var { children, columns, data, keyField, tableInstanceRef, stateStorage, tableMenuOptions, manualSorting, manualFiltering, manualSearch, height, maxHeight, minHeight, focusedRowId, enableColumnResize, enableSorting, compact, totalRecords, onColumnStateChange, onColumnReorder, onColumnHeaderClick, onSort, onRowUpdated, tableElement, headerRowElm, tableDimensions, targetElm, listElm, defaultSelectionState, selectionState, onSelectionChange, defaultFilterState, filterState, onFilterChange } = _a, props = __rest(_a, ["children", "columns", "data", "keyField", "tableInstanceRef", "stateStorage", "tableMenuOptions", "manualSorting", "manualFiltering", "manualSearch", "height", "maxHeight", "minHeight", "focusedRowId", "enableColumnResize", "enableSorting", "compact", "totalRecords", "onColumnStateChange", "onColumnReorder", "onColumnHeaderClick", "onSort", "onRowUpdated", "tableElement", "headerRowElm", "tableDimensions", "targetElm", "listElm", "defaultSelectionState", "selectionState", "onSelectionChange", "defaultFilterState", "filterState", "onFilterChange"]);
50
+ var { children, columns, data, keyField, tableInstanceRef, stateStorage, tableMenuOptions, manualSorting, manualFiltering, manualSearch, manualExport, height, maxHeight, minHeight, focusedRowId, enableColumnResize, enableSorting, compact, totalRecords, onColumnStateChange, onColumnReorder, onColumnHeaderClick, onSort, onRowUpdated, tableElement, headerRowElm, tableDimensions, targetElm, listElm, defaultSelectionState, selectionState, onSelectionChange, defaultFilterState, filterState, onFilterChange } = _a, props = __rest(_a, ["children", "columns", "data", "keyField", "tableInstanceRef", "stateStorage", "tableMenuOptions", "manualSorting", "manualFiltering", "manualSearch", "manualExport", "height", "maxHeight", "minHeight", "focusedRowId", "enableColumnResize", "enableSorting", "compact", "totalRecords", "onColumnStateChange", "onColumnReorder", "onColumnHeaderClick", "onSort", "onRowUpdated", "tableElement", "headerRowElm", "tableDimensions", "targetElm", "listElm", "defaultSelectionState", "selectionState", "onSelectionChange", "defaultFilterState", "filterState", "onFilterChange"]);
41
51
  const _columns = useMemo(() => columns
42
52
  .map((child, index) => {
43
53
  if (child.dataField === "__key") {
@@ -192,6 +202,18 @@ const TableProvider = (_a) => {
192
202
  const clearSearch = () => {
193
203
  updateSearchState("");
194
204
  };
205
+ const handleTableExport = (exportType) => __awaiter(void 0, void 0, void 0, function* () {
206
+ var _a, _b;
207
+ if (manualExport === true) {
208
+ (_b = (_a = tableMenuOptions === null || tableMenuOptions === void 0 ? void 0 : tableMenuOptions.exportOptions) === null || _a === void 0 ? void 0 : _a.onExport) === null || _b === void 0 ? void 0 : _b.call(_a, exportType);
209
+ return;
210
+ }
211
+ yield exportTableToExcel({
212
+ columns: columnState,
213
+ data: _data,
214
+ exportMode: exportType,
215
+ });
216
+ });
195
217
  const updateSortState = (sortState) => {
196
218
  var _a;
197
219
  setSortState(sortState);
@@ -209,20 +231,36 @@ const TableProvider = (_a) => {
209
231
  // sort data
210
232
  return data.sort((a, b) => {
211
233
  if (sortState) {
234
+ const aValue = a[sortState.dataField];
235
+ const bValue = b[sortState.dataField];
236
+ const aIsEmpty = aValue === null || aValue === undefined;
237
+ const bIsEmpty = bValue === null || bValue === undefined;
238
+ // Treat empty values as the smallest values.
239
+ if (aIsEmpty && bIsEmpty) {
240
+ return 0;
241
+ }
242
+ if (aIsEmpty || bIsEmpty) {
243
+ if (sortState.dir === "asc") {
244
+ return aIsEmpty ? -1 : 1;
245
+ }
246
+ if (sortState.dir === "desc") {
247
+ return aIsEmpty ? 1 : -1;
248
+ }
249
+ }
212
250
  if (sortState.dir === "asc") {
213
- if (a[sortState.dataField] < b[sortState.dataField]) {
251
+ if (aValue < bValue) {
214
252
  return -1;
215
253
  }
216
- if (a[sortState.dataField] > b[sortState.dataField]) {
254
+ if (aValue > bValue) {
217
255
  return 1;
218
256
  }
219
257
  return 0;
220
258
  }
221
259
  else if (sortState.dir === "desc") {
222
- if (a[sortState.dataField] > b[sortState.dataField]) {
260
+ if (aValue > bValue) {
223
261
  return -1;
224
262
  }
225
- if (a[sortState.dataField] < b[sortState.dataField]) {
263
+ if (aValue < bValue) {
226
264
  return 1;
227
265
  }
228
266
  return 0;
@@ -583,6 +621,7 @@ const TableProvider = (_a) => {
583
621
  toggleColumnVisibility,
584
622
  runSearch,
585
623
  clearSearch,
624
+ handleTableExport,
586
625
  handleFilterChange, filterState: _filterState, compactState,
587
626
  toggleCompact,
588
627
  getCalculatedSelectionTotal,
@@ -1,3 +1,4 @@
1
1
  export { default as resolveColumnResize } from "./resolveColumnResize";
2
2
  export { default as syncColumnState } from "./syncColumnState";
3
3
  export { default as resizeHandler } from "./resizeHandler";
4
+ export { exportTableToExcel } from "./tableExport";
@@ -1,3 +1,4 @@
1
1
  export { default as resolveColumnResize } from "./resolveColumnResize";
2
2
  export { default as syncColumnState } from "./syncColumnState";
3
3
  export { default as resizeHandler } from "./resizeHandler";
4
+ export { exportTableToExcel } from "./tableExport";
@@ -0,0 +1,9 @@
1
+ import { TableExportOptions } from "../enums";
2
+ import { ColumnState } from "../types";
3
+ type TableExportParams = {
4
+ columns: ColumnState[];
5
+ data: any[];
6
+ exportMode: TableExportOptions;
7
+ };
8
+ export declare const exportTableToExcel: ({ columns, data, exportMode, }: TableExportParams) => Promise<void>;
9
+ export {};
@@ -0,0 +1,102 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { isValidElement } from "react";
11
+ import { TableExportOptions } from "../enums";
12
+ const getColumnHeader = (column) => {
13
+ return column.caption || column.dataField;
14
+ };
15
+ const toExportablePrimitive = (value) => {
16
+ if (value === undefined || value === null)
17
+ return null;
18
+ if (typeof value === "string" ||
19
+ typeof value === "number" ||
20
+ typeof value === "boolean" ||
21
+ value instanceof Date) {
22
+ return value;
23
+ }
24
+ if (value instanceof RegExp) {
25
+ return value.toString();
26
+ }
27
+ if (Array.isArray(value)) {
28
+ return value.map((item) => toExportablePrimitive(item)).join(", ");
29
+ }
30
+ if (typeof value === "object") {
31
+ try {
32
+ return JSON.stringify(value);
33
+ }
34
+ catch (_a) {
35
+ return String(value);
36
+ }
37
+ }
38
+ return String(value);
39
+ };
40
+ const extractTextFromNode = (node) => {
41
+ if (node === null || node === undefined || typeof node === "boolean") {
42
+ return "";
43
+ }
44
+ if (typeof node === "string" || typeof node === "number") {
45
+ return String(node);
46
+ }
47
+ if (Array.isArray(node)) {
48
+ return node.map((child) => extractTextFromNode(child)).join("");
49
+ }
50
+ if (isValidElement(node)) {
51
+ return extractTextFromNode(node.props.children);
52
+ }
53
+ return "";
54
+ };
55
+ const getExportCellValue = (row, column) => {
56
+ const rawValue = row[column.dataField];
57
+ if (!column.render) {
58
+ return toExportablePrimitive(rawValue);
59
+ }
60
+ const renderedText = extractTextFromNode(column.render({ rowData: row }));
61
+ if (renderedText.trim().length > 0) {
62
+ return renderedText;
63
+ }
64
+ return toExportablePrimitive(rawValue);
65
+ };
66
+ const getColumnsForExport = (columns, exportMode) => {
67
+ return columns
68
+ .filter((column) => {
69
+ if (exportMode === TableExportOptions.ExportVisible) {
70
+ return column.visible !== false;
71
+ }
72
+ return true;
73
+ })
74
+ .sort((a, b) => a.orderValue - b.orderValue);
75
+ };
76
+ const getFileName = () => {
77
+ const timestamp = new Date().toISOString().replaceAll(":", "-");
78
+ return `table-export-${timestamp}.xlsx`;
79
+ };
80
+ const downloadBuffer = (buffer) => {
81
+ const blob = new Blob([buffer], {
82
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
83
+ });
84
+ const url = window.URL.createObjectURL(blob);
85
+ const anchor = document.createElement("a");
86
+ anchor.href = url;
87
+ anchor.download = getFileName();
88
+ anchor.click();
89
+ window.URL.revokeObjectURL(url);
90
+ };
91
+ export const exportTableToExcel = (_a) => __awaiter(void 0, [_a], void 0, function* ({ columns, data, exportMode, }) {
92
+ const { default: ExcelJS } = yield import("exceljs");
93
+ const exportColumns = getColumnsForExport(columns, exportMode);
94
+ const workbook = new ExcelJS.Workbook();
95
+ const worksheet = workbook.addWorksheet("Table Export");
96
+ worksheet.addRow(exportColumns.map((column) => getColumnHeader(column)));
97
+ data.forEach((row) => {
98
+ worksheet.addRow(exportColumns.map((column) => getExportCellValue(row, column)));
99
+ });
100
+ const buffer = yield workbook.xlsx.writeBuffer();
101
+ downloadBuffer(buffer);
102
+ });
@@ -134,6 +134,7 @@ export type TableContextType = {
134
134
  toggleColumnVisibility: (dataField: string) => void;
135
135
  runSearch: (query: string) => void;
136
136
  clearSearch: () => void;
137
+ handleTableExport: (e: TableExportOptions) => Promise<void> | void;
137
138
  handleFilterChange: (query: Query) => void;
138
139
  selectAllRows: () => void;
139
140
  clearSelections: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.3.116-dev.1",
3
+ "version": "1.3.116-dev.2",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",
@@ -59,6 +59,7 @@
59
59
  "@uiw/codemirror-theme-vscode": "^4.23.6",
60
60
  "@uiw/react-codemirror": "^4.23.6",
61
61
  "deepmerge": "^4.3.1",
62
+ "exceljs": "^4.4.0",
62
63
  "lucide-react": "^0.469.0",
63
64
  "moment": "^2.29.1",
64
65
  "overlayscrollbars": "^2.6.0",