@vuu-ui/vuu-table-extras 4.0.0-alpha.20 → 4.0.0-alpha.22

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 (132) hide show
  1. package/package.json +16 -17
  2. package/src/cell-renderers/pct-progress-cell/PctProgressCell.css.js +2 -2
  3. package/src/cell-renderers/progress-cell/ProgressCell.css.js +2 -2
  4. package/src/column-expression-input/ColumnExpressionInput.css.js +5 -5
  5. package/src/column-expression-input/theme.js +1 -1
  6. package/src/column-settings-panel/ColumnNameLabel.css.js +1 -1
  7. package/src/csv-export/export-utils.js +13 -4
  8. package/src/csv-upload/CsvUpload.css.js +7 -7
  9. package/src/csv-upload/parse/csv-upload-utils.js +47 -2
  10. package/src/csv-upload/session/index.js +2 -0
  11. package/src/csv-upload/session/useImportSchema.js +44 -0
  12. package/src/csv-upload/session/useImportSession.js +204 -0
  13. package/src/csv-upload/useCsvUpload.js +45 -188
  14. package/src/freeze-control/FreezeControl.css.js +4 -4
  15. package/src/freeze-control/FrozenBanner.css.js +2 -2
  16. package/types/calculated-column/CalculatedColumnPanel.d.ts +1 -1
  17. package/types/cell-renderers/background-cell/BackgroundCell.d.ts +1 -1
  18. package/types/cell-renderers/background-cell/BackgroundCellConfigurationEditor.d.ts +1 -1
  19. package/types/cell-renderers/button-cell/IconButtonCell.d.ts +1 -1
  20. package/types/cell-renderers/dropdown-cell/DropdownCell.d.ts +1 -1
  21. package/types/cell-renderers/lookup-cell/LookupCell.d.ts +1 -1
  22. package/types/cell-renderers/pct-progress-cell/PctProgressCell.d.ts +1 -1
  23. package/types/column-expression-input/ColumnExpressionInput.d.ts +1 -1
  24. package/types/column-expression-input/column-language-parser/test.d.mts +1 -1
  25. package/types/column-formatting-settings/BaseNumericFormattingSettings.d.ts +1 -1
  26. package/types/column-formatting-settings/ColumnFormattingPanel.d.ts +1 -1
  27. package/types/column-formatting-settings/LongTypeFormattingSettings.d.ts +1 -2
  28. package/types/column-menu/ColumnMenu.d.ts +1 -1
  29. package/types/column-picker/ColumnPickerAction.d.ts +1 -1
  30. package/types/column-settings-panel/ColumnNameLabel.d.ts +1 -1
  31. package/types/column-settings-panel/ColumnSettingsPanel.d.ts +1 -1
  32. package/types/csv-upload/CsvUpload.d.ts +1 -1
  33. package/types/csv-upload/data-upload-preview/DataUploadPreview.d.ts +1 -1
  34. package/types/csv-upload/parse/csv-upload-utils.d.ts +9 -0
  35. package/types/csv-upload/session/index.d.ts +2 -0
  36. package/types/csv-upload/session/useImportSchema.d.ts +13 -0
  37. package/types/csv-upload/session/useImportSession.d.ts +26 -0
  38. package/types/csv-upload/useCsvUpload.d.ts +1 -1
  39. package/types/datasource-stats/DatasourceStats.d.ts +1 -1
  40. package/types/freeze-control/FreezeControl.d.ts +1 -1
  41. package/types/freeze-control/FrozenBanner.d.ts +1 -1
  42. package/types/inline-add-row/InlineAddRow.d.ts +1 -1
  43. package/types/tabbed-table-config-panel/TabbedTableConfigPanel.d.ts +1 -1
  44. package/types/tabbed-table-config-panel/TabbedTableSettingsAction.d.ts +1 -1
  45. package/types/table-footer/TableFooter.d.ts +2 -2
  46. package/types/table-provider/TableProvider.d.ts +1 -1
  47. package/types/table-settings-panel/TableSettingsPanel.d.ts +1 -1
  48. package/types/src/calculated-column/CalculatedColumnPanel.d.ts +0 -12
  49. package/types/src/calculated-column/useCalculatedColumnPanel.d.ts +0 -10
  50. package/types/src/calculated-column/useEditCalculatedColumn.d.ts +0 -13
  51. package/types/src/cell-edit-validators/CaseValidator.d.ts +0 -2
  52. package/types/src/cell-edit-validators/PatternValidator.d.ts +0 -2
  53. package/types/src/cell-edit-validators/index.d.ts +0 -2
  54. package/types/src/cell-renderers/background-cell/BackgroundCell.d.ts +0 -2
  55. package/types/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.d.ts +0 -2
  56. package/types/src/cell-renderers/background-cell/index.d.ts +0 -2
  57. package/types/src/cell-renderers/background-cell/useDirection.d.ts +0 -3
  58. package/types/src/cell-renderers/button-cell/IconButtonCell.d.ts +0 -6
  59. package/types/src/cell-renderers/dropdown-cell/DropdownCell.d.ts +0 -2
  60. package/types/src/cell-renderers/dropdown-cell/index.d.ts +0 -1
  61. package/types/src/cell-renderers/index.d.ts +0 -6
  62. package/types/src/cell-renderers/lookup-cell/LookupCell.d.ts +0 -2
  63. package/types/src/cell-renderers/lookup-cell/index.d.ts +0 -1
  64. package/types/src/cell-renderers/pct-progress-cell/PctProgressCell.d.ts +0 -2
  65. package/types/src/cell-renderers/pct-progress-cell/index.d.ts +0 -1
  66. package/types/src/cell-renderers/progress-cell/ProgressCell.d.ts +0 -1
  67. package/types/src/cell-renderers/progress-cell/index.d.ts +0 -1
  68. package/types/src/column-expression-input/ColumnExpressionInput.d.ts +0 -10
  69. package/types/src/column-expression-input/column-function-descriptors.d.ts +0 -15
  70. package/types/src/column-expression-input/column-language-parser/ColumnExpressionLanguage.d.ts +0 -2
  71. package/types/src/column-expression-input/column-language-parser/ColumnExpressionTreeWalker.d.ts +0 -57
  72. package/types/src/column-expression-input/column-language-parser/column-expression-parse-utils.d.ts +0 -5
  73. package/types/src/column-expression-input/column-language-parser/generated/column-parser.d.ts +0 -2
  74. package/types/src/column-expression-input/column-language-parser/generated/column-parser.terms.d.ts +0 -1
  75. package/types/src/column-expression-input/column-language-parser/index.d.ts +0 -3
  76. package/types/src/column-expression-input/column-language-parser/test.d.mts +0 -1
  77. package/types/src/column-expression-input/functionDocInfo.d.ts +0 -2
  78. package/types/src/column-expression-input/highlighting.d.ts +0 -1
  79. package/types/src/column-expression-input/index.d.ts +0 -4
  80. package/types/src/column-expression-input/theme.d.ts +0 -1
  81. package/types/src/column-expression-input/useColumnAutoComplete.d.ts +0 -6
  82. package/types/src/column-expression-input/useColumnExpressionEditor.d.ts +0 -25
  83. package/types/src/column-expression-input/useColumnExpressionSuggestionProvider.d.ts +0 -8
  84. package/types/src/column-formatting-settings/BaseNumericFormattingSettings.d.ts +0 -2
  85. package/types/src/column-formatting-settings/ColumnFormattingPanel.d.ts +0 -9
  86. package/types/src/column-formatting-settings/DateTimeFormattingSettings.d.ts +0 -3
  87. package/types/src/column-formatting-settings/LongTypeFormattingSettings.d.ts +0 -3
  88. package/types/src/column-formatting-settings/index.d.ts +0 -3
  89. package/types/src/column-menu/ColumnMenu.d.ts +0 -10
  90. package/types/src/column-menu/column-action-types.d.ts +0 -11
  91. package/types/src/column-menu/column-menu-utils.d.ts +0 -19
  92. package/types/src/column-menu/useColumnActions.d.ts +0 -16
  93. package/types/src/column-picker/ColumnModel.d.ts +0 -81
  94. package/types/src/column-picker/ColumnPicker.d.ts +0 -10
  95. package/types/src/column-picker/ColumnPickerAction.d.ts +0 -5
  96. package/types/src/column-picker/useColumnPicker.d.ts +0 -16
  97. package/types/src/column-picker/useTableColumnPicker.d.ts +0 -7
  98. package/types/src/column-picker/useTableColumnPickerDeprecated.d.ts +0 -14
  99. package/types/src/column-settings-panel/ColumnNameLabel.d.ts +0 -7
  100. package/types/src/column-settings-panel/ColumnSettingsPanel.d.ts +0 -5
  101. package/types/src/column-settings-panel/useColumnSettings.d.ts +0 -30
  102. package/types/src/csv-export/export-utils.d.ts +0 -42
  103. package/types/src/csv-export/index.d.ts +0 -2
  104. package/types/src/csv-export/useCsvExport.d.ts +0 -14
  105. package/types/src/csv-upload/CsvUpload.d.ts +0 -69
  106. package/types/src/csv-upload/data-upload-preview/DataUploadPreview.d.ts +0 -10
  107. package/types/src/csv-upload/data-upload-preview/useDataUploadPreview.d.ts +0 -17
  108. package/types/src/csv-upload/index.d.ts +0 -7
  109. package/types/src/csv-upload/parse/csv-constants.d.ts +0 -3
  110. package/types/src/csv-upload/parse/csv-errors.d.ts +0 -47
  111. package/types/src/csv-upload/parse/csv-parse.d.ts +0 -11
  112. package/types/src/csv-upload/parse/csv-schema-validation.d.ts +0 -18
  113. package/types/src/csv-upload/parse/csv-upload-utils.d.ts +0 -21
  114. package/types/src/csv-upload/parse/index.d.ts +0 -5
  115. package/types/src/csv-upload/useCsvUpload.d.ts +0 -43
  116. package/types/src/datasource-stats/DatasourceStats.d.ts +0 -17
  117. package/types/src/datasource-stats/useDatasourceStats.d.ts +0 -15
  118. package/types/src/freeze-control/FreezeControl.d.ts +0 -15
  119. package/types/src/freeze-control/FrozenBanner.d.ts +0 -6
  120. package/types/src/freeze-control/freezeControlBadge.d.ts +0 -11
  121. package/types/src/freeze-control/useFreezeControl.d.ts +0 -10
  122. package/types/src/index.d.ts +0 -26
  123. package/types/src/inline-add-row/InlineAddRow.d.ts +0 -3
  124. package/types/src/inline-add-row/index.d.ts +0 -2
  125. package/types/src/inline-add-row/useInlineAddRow.d.ts +0 -59
  126. package/types/src/tabbed-table-config-panel/TabbedTableConfigPanel.d.ts +0 -17
  127. package/types/src/tabbed-table-config-panel/TabbedTableSettingsAction.d.ts +0 -7
  128. package/types/src/tabbed-table-config-panel/useTabbedTableConfigPanel.d.ts +0 -13
  129. package/types/src/table-footer/TableFooter.d.ts +0 -10
  130. package/types/src/table-provider/TableProvider.d.ts +0 -18
  131. package/types/src/table-settings-panel/TableSettingsPanel.d.ts +0 -22
  132. package/types/src/table-settings-panel/useTableSettings.d.ts +0 -14
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-alpha.20",
2
+ "version": "4.0.0-alpha.22",
3
3
  "author": "heswell",
4
4
  "main": "./src/index.js",
5
5
  "license": "Apache-2.0",
@@ -12,25 +12,24 @@
12
12
  "lezer-generate:column": "lezer-generator --output ./src/column-expression-input/column-language-parser/generated/column-parser.ts ./src/column-expression-input/column-language-parser/grammar/column.grammar"
13
13
  },
14
14
  "devDependencies": {
15
- "@vuu-ui/vuu-filter-types": "4.0.0-alpha.20",
16
- "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.20"
15
+ "@vuu-ui/vuu-filter-types": "4.0.0-alpha.22",
16
+ "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.22"
17
17
  },
18
18
  "dependencies": {
19
- "@vuu-ui/core": "4.0.0-alpha.20",
20
- "@vuu-ui/vuu-codemirror": "4.0.0-alpha.20",
21
- "@vuu-ui/vuu-data-editing": "4.0.0-alpha.20",
22
- "@vuu-ui/vuu-data-react": "4.0.0-alpha.20",
23
- "@vuu-ui/vuu-data-types": "4.0.0-alpha.20",
24
- "@vuu-ui/vuu-table-types": "4.0.0-alpha.20",
25
- "@vuu-ui/vuu-popups": "4.0.0-alpha.20",
26
- "@vuu-ui/vuu-table": "4.0.0-alpha.20",
27
- "@vuu-ui/vuu-utils": "4.0.0-alpha.20",
28
- "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.20",
19
+ "@vuu-ui/core": "4.0.0-alpha.22",
20
+ "@vuu-ui/vuu-codemirror": "4.0.0-alpha.22",
21
+ "@vuu-ui/vuu-data-editing": "4.0.0-alpha.22",
22
+ "@vuu-ui/vuu-data-react": "4.0.0-alpha.22",
23
+ "@vuu-ui/vuu-data-types": "4.0.0-alpha.22",
24
+ "@vuu-ui/vuu-table-types": "4.0.0-alpha.22",
25
+ "@vuu-ui/vuu-popups": "4.0.0-alpha.22",
26
+ "@vuu-ui/vuu-table": "4.0.0-alpha.22",
27
+ "@vuu-ui/vuu-utils": "4.0.0-alpha.22",
28
+ "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.22",
29
29
  "@lezer/lr": "1.4.2",
30
- "@salt-ds/core": "1.67.0",
31
- "@salt-ds/lab": "1.0.0-alpha.99",
32
- "@salt-ds/styles": "0.2.1",
33
- "@salt-ds/window": "0.1.1",
30
+ "@salt-ds/core": "1.72.0",
31
+ "@salt-ds/styles": "0.4.1",
32
+ "@salt-ds/window": "0.1.2",
34
33
  "csv-parse": "^7.0.0"
35
34
  },
36
35
  "peerDependencies": {
@@ -9,8 +9,8 @@ const css = `
9
9
  }
10
10
 
11
11
  .vuuPctProgressCell-progressBar {
12
- background-color: var(--vuu-color-green-60-fade-30);
13
- border-right: solid var(--progress-bar-width) var(--vuu-color-green-60);
12
+ background-color: var(--salt-color-green-600-40a);
13
+ border-right: solid var(--progress-bar-width) var(--salt-color-green-600);
14
14
  height: 20px;
15
15
  width: var(--progress-bar-pct, 0);
16
16
  display: inline-block;
@@ -13,7 +13,7 @@ const css = `
13
13
  }
14
14
 
15
15
  .vuuProgressCell-bg {
16
- background-color: var(--salt-measured-background);
16
+ background-color: var(--salt-sentiment-neutral-track);
17
17
  width: 100%;
18
18
  height: 2px;
19
19
  display: inline-block;
@@ -23,7 +23,7 @@ const css = `
23
23
  }
24
24
 
25
25
  .vuuProgressCell-bar {
26
- background-color: var(--salt-measured-fill);
26
+ background-color: var(--salt-sentiment-accent-background);
27
27
  height: 100%;
28
28
  transform: translateX(var(--progress-bar-pct, -100%));
29
29
  width: 100%;
@@ -5,15 +5,15 @@ const css = `
5
5
  --vuuFilterEditor-fontFamily: var(--salt-typography-fontFamily);
6
6
  --vuuFilterEditor-fontSize: var(--salt-text-fontSize);
7
7
  --vuuFilterEditor-cursorColor: var(--salt-content-secondary-foreground);
8
- --vuuFilterEditor-selectionBackground: var(--salt-text-background-selected);
8
+ --vuuFilterEditor-selectionBackground: var(--salt-selectable-background-selected);
9
9
  --vuuFilterEditor-tooltipBackground: var(--salt-container-primary-background);
10
- --vuuFilterEditor-tooltipBorder: solid 1px var(--vuu-color-purple-10);
10
+ --vuuFilterEditor-tooltipBorder: solid 1px var(--vuu-color-purple);
11
11
  --vuuFilterEditor-tooltipElevation: var(--salt-overlayable-shadow-popout);
12
12
  --vuuFilterEditor-suggestion-selectedBackground: var(--vuu-color-gray-10);
13
13
  --vuuFilterEditor-suggestion-selectedColor: var(--salt-content-primary-foreground);
14
14
  --vuuFilterEditor-suggestion-detailColor: var(--salt-content-secondary-foreground-disabled);
15
15
  --vuuFilterEditor-suggestion-height: 24px;
16
- --vuuFilterEditor-variableColor: var(--vuu-color-purple-10);
16
+ --vuuFilterEditor-variableColor: var(--vuu-color-purple);
17
17
  box-sizing: border-box;
18
18
  align-items: center;
19
19
  height: 30px;
@@ -72,13 +72,13 @@ const css = `
72
72
  }
73
73
 
74
74
  .vuuFunctionDoc .example-container {
75
- background-color: var(--vuu-color-gray-03);
75
+ background-color: var(--salt-color-gray-100);
76
76
  margin: 6px 0;
77
77
  padding: 3px;
78
78
  }
79
79
 
80
80
  .vuuFunctionDoc .example-expression {
81
- color: var(--vuu-color-gray-80);
81
+ color: var(--salt-color-gray-800);
82
82
  font-family: var(--salt-typography-fontFamily-code);
83
83
  padding: 8px;
84
84
  font-weight: 500;
@@ -24,7 +24,7 @@ const vuuTheme = EditorView.theme({
24
24
  color: "var(--vuu-color-gray-50)"
25
25
  },
26
26
  ".cm-completionMatchedText": {
27
- color: "var(--vuu-color-gray-80)",
27
+ color: "var(--salt-color-gray-800)",
28
28
  fontWeight: 700,
29
29
  textDecoration: "none"
30
30
  },
@@ -10,7 +10,7 @@ const css = `
10
10
  }
11
11
 
12
12
  .vuuColumnNameLabel-placeholder {
13
- color: var(--vuu-color-gray-35);
13
+ color: var(--salt-color-gray-400);
14
14
  }
15
15
 
16
16
 
@@ -51,8 +51,9 @@ const isExportableColumn = (descriptor)=>{
51
51
  const exportCsvTemplate = async (dataSource, options = {})=>{
52
52
  const { filename = "template.csv", excludeColumns = [], columns, overrides, timeout = DEFAULT_TEMPLATE_TIMEOUT, onError, onSuccess } = options;
53
53
  const targetColumnNames = columns ? columns.filter((col)=>"string" == typeof col ? true : isExportableColumn(col) && "client" !== col.source).map((col)=>"string" == typeof col ? col : col.name) : void 0;
54
- const sessionOverrides = overrides ?? (targetColumnNames ? {
55
- columns: targetColumnNames
54
+ const targetColumns = targetColumnNames ?? overrides?.columns;
55
+ const sessionOverrides = overrides ?? (targetColumns ? {
56
+ columns: targetColumns
56
57
  } : void 0);
57
58
  if (!isSessionTable(dataSource.table) && dataSource.createSessionDataSource && "initialising" !== dataSource.status && "unsubscribed" !== dataSource.status) try {
58
59
  const sessionDataSource = await dataSource.createSessionDataSource("Empty", "export", sessionOverrides);
@@ -80,7 +81,16 @@ const exportCsvTemplate = async (dataSource, options = {})=>{
80
81
  }, (message)=>{
81
82
  if ("subscribed" === message.type) {
82
83
  const { columns: subColumns } = message;
83
- const exportCols = subColumns.filter((name)=>!excluded.has(name));
84
+ const exportCols = targetColumns ? targetColumns.filter((name)=>!excluded.has(name)) : subColumns.filter((name)=>!excluded.has(name));
85
+ if (0 === exportCols.length) {
86
+ cleanup();
87
+ const error = new Error("exportCsvTemplate: no columns available for export");
88
+ if (onError) {
89
+ onError(error);
90
+ resolve();
91
+ } else reject(error);
92
+ return;
93
+ }
84
94
  const header = exportCols.map(csvCell).join(",");
85
95
  triggerCsvDownload(`${header}\r\n`, filename);
86
96
  cleanup();
@@ -93,7 +103,6 @@ const exportCsvTemplate = async (dataSource, options = {})=>{
93
103
  console.warn("[exportCsvTemplate] createSessionDataSource failed, falling back to tableSchema", error);
94
104
  }
95
105
  const schema = dataSource.tableSchema;
96
- const targetColumns = targetColumnNames ?? overrides?.columns;
97
106
  if (void 0 !== targetColumns) {
98
107
  if (schema) {
99
108
  const schemaColumnNames = new Set(schema.columns.map((col)=>col.name));
@@ -20,8 +20,8 @@ const css = `
20
20
  max-width: 480px;
21
21
  max-height: 120px;
22
22
  padding: var(--salt-spacing-100) var(--salt-spacing-200);
23
- background-color: rgba(var(--salt-palette-interact-error-background), .05);
24
- border-radius: var(--salt-size-borderRadius);
23
+ background-color: var(--salt-status-error-background);
24
+ border-radius: var(--salt-palette-corner);
25
25
  text-align: left;
26
26
  overflow-y: auto;
27
27
  }
@@ -33,9 +33,9 @@ const css = `
33
33
  }
34
34
 
35
35
  .vuuCsvUpload-errorItem {
36
- font-size: var(--salt-text-fontSize-small);
37
- color: var(--salt-status-error-foreground);
38
- line-height: var(--salt-text-lineHeight-small);
36
+ font-size: var(--salt-text-label-fontSize);
37
+ color: var(--salt-status-error-foreground-informative);
38
+ line-height: var(--salt-text-label-lineHeight);
39
39
  word-break: break-word;
40
40
  margin-bottom: var(--salt-spacing-50);
41
41
  }
@@ -50,8 +50,8 @@ const css = `
50
50
 
51
51
  .vuuCsvUpload-errors {
52
52
  border: solid 1px var(--salt-status-error-borderColor);
53
- border-radius: var(--salt-size-borderRadius);
54
- color: var(--salt-status-error-foreground);
53
+ border-radius: var(--salt-palette-corner);
54
+ color: var(--salt-status-error-foreground-informative);
55
55
  gap: var(--salt-spacing-100);
56
56
  padding: var(--salt-spacing-200);
57
57
  display: grid;
@@ -1,4 +1,4 @@
1
- import { isRpcError } from "@vuu-ui/vuu-utils";
1
+ import { isRpcError, metadataKeys } from "@vuu-ui/vuu-utils";
2
2
  import { CSV_FIRST_DATA_ROW_NUMBER } from "./csv-constants.js";
3
3
  const isRecord = (value)=>"object" == typeof value && null !== value;
4
4
  const toErrorMessage = (error)=>error instanceof Error ? error.message : String(error);
@@ -56,4 +56,49 @@ const executeBatchRpcCalls = async (items, executor, errorFormatter)=>{
56
56
  results
57
57
  };
58
58
  };
59
- export { buildRowErrorMessage, createUploadError, executeBatchRpcCalls, hasFileParseErrors, isCsvParseError, mergeValidationWithParseErrors, normalizeTableData, toErrorMessage, toValidationErrorsFromParseRowErrors };
59
+ const getInlineRowErrorMessage = (result)=>{
60
+ if (isRecord(result) && "data" in result && isRecord(result.data)) {
61
+ const data = result.data;
62
+ const msg = data.vuuMsg ?? data.msg;
63
+ if ("string" == typeof msg && "" !== msg.trim()) return msg.trim();
64
+ }
65
+ };
66
+ const getRowVuuMsgError = (row, vuuMsgDataIndex, vuuRowNumDataIndex)=>{
67
+ if (-1 === vuuMsgDataIndex) return;
68
+ const msg = Array.isArray(row) ? row[vuuMsgDataIndex] : row?.vuuMsg;
69
+ if ("string" == typeof msg && "" !== msg.trim()) {
70
+ const rowNum = -1 !== vuuRowNumDataIndex && void 0 !== row[vuuRowNumDataIndex] ? Number(row[vuuRowNumDataIndex]) : Number(row[metadataKeys.IDX]) + CSV_FIRST_DATA_ROW_NUMBER;
71
+ return {
72
+ rowNum,
73
+ message: msg.trim()
74
+ };
75
+ }
76
+ };
77
+ const waitForSessionErrors = (isRemote, sessionErrors, receivedRowKeys, expectedRowCount, listeners, timeoutMs = 500)=>{
78
+ if (sessionErrors.size > 0 || !isRemote) return Promise.resolve([
79
+ ...sessionErrors.values()
80
+ ]);
81
+ return new Promise((resolve)=>{
82
+ let timeoutId;
83
+ const onUpdate = ()=>{
84
+ if (sessionErrors.size > 0 || receivedRowKeys.size >= expectedRowCount) {
85
+ cleanup();
86
+ resolve([
87
+ ...sessionErrors.values()
88
+ ]);
89
+ }
90
+ };
91
+ const cleanup = ()=>{
92
+ clearTimeout(timeoutId);
93
+ listeners.delete(onUpdate);
94
+ };
95
+ listeners.add(onUpdate);
96
+ timeoutId = setTimeout(()=>{
97
+ cleanup();
98
+ resolve([
99
+ ...sessionErrors.values()
100
+ ]);
101
+ }, timeoutMs);
102
+ });
103
+ };
104
+ export { buildRowErrorMessage, createUploadError, executeBatchRpcCalls, getInlineRowErrorMessage, getRowVuuMsgError, hasFileParseErrors, isCsvParseError, mergeValidationWithParseErrors, normalizeTableData, toErrorMessage, toValidationErrorsFromParseRowErrors, waitForSessionErrors };
@@ -0,0 +1,2 @@
1
+ export * from "./useImportSchema.js";
2
+ export * from "./useImportSession.js";
@@ -0,0 +1,44 @@
1
+ import { useData } from "@vuu-ui/vuu-utils";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ const useImportSchema = ({ dataSource, importSchema, importTable })=>{
4
+ const { getServerAPI } = useData();
5
+ const [fetchedImportSchema, setFetchedImportSchema] = useState();
6
+ useEffect(()=>{
7
+ if (importSchema || void 0 === importTable) return void setFetchedImportSchema(void 0);
8
+ let cancelled = false;
9
+ (async ()=>{
10
+ try {
11
+ const server = await getServerAPI();
12
+ const tableSchema = await server.getTableSchema(importTable);
13
+ if (!cancelled) setFetchedImportSchema(tableSchema);
14
+ } catch (error) {
15
+ console.error("[useImportSchema] failed to fetch import table schema", error);
16
+ }
17
+ })();
18
+ return ()=>{
19
+ cancelled = true;
20
+ };
21
+ }, [
22
+ getServerAPI,
23
+ importSchema,
24
+ importTable
25
+ ]);
26
+ const resolvedImportSchema = importSchema ?? fetchedImportSchema;
27
+ const sessionOverrides = useMemo(()=>{
28
+ const columns = resolvedImportSchema?.columns.map(({ name })=>name);
29
+ return columns || importTable ? {
30
+ columns,
31
+ table: importTable
32
+ } : void 0;
33
+ }, [
34
+ resolvedImportSchema,
35
+ importTable
36
+ ]);
37
+ const schema = importTable ? resolvedImportSchema : resolvedImportSchema ?? dataSource.tableSchema;
38
+ return {
39
+ resolvedImportSchema,
40
+ schema,
41
+ sessionOverrides
42
+ };
43
+ };
44
+ export { useImportSchema };
@@ -0,0 +1,204 @@
1
+ import { EditSession } from "@vuu-ui/vuu-data-editing";
2
+ import { Range, buildColumnMap, isRpcError, isSessionTable, metadataKeys } from "@vuu-ui/vuu-utils";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import { buildRowErrorMessage, getInlineRowErrorMessage, getRowVuuMsgError, toErrorMessage, waitForSessionErrors } from "../parse/csv-upload-utils.js";
5
+ import { CSV_FIRST_DATA_ROW_NUMBER } from "../parse/csv-constants.js";
6
+ const useImportSession = ({ dataSource, sessionOverrides, rowDefaults, processingPromiseRef, onImportSessionEnded })=>{
7
+ const sessionErrorsRef = useRef(new Map());
8
+ const receivedRowKeysRef = useRef(new Set());
9
+ const sessionRowUpdateListenersRef = useRef(new Set());
10
+ const importDataSource = useMemo(()=>({
11
+ tableSchema: dataSource.tableSchema,
12
+ createSessionDataSource: async (copyOption, sessionType)=>{
13
+ if (!dataSource.createSessionDataSource) throw Error("[useCsvUpload] dataSource does not support createSessionDataSource");
14
+ const sessionDs = await dataSource.createSessionDataSource(copyOption, sessionType, sessionOverrides);
15
+ if (!sessionDs) throw Error("[useCsvUpload] Failed to create session datasource");
16
+ if (!sessionDs.columns.includes("vuuMsg")) sessionDs.columns = sessionDs.columns.concat("vuuMsg");
17
+ const columnMap = buildColumnMap(sessionDs.columns);
18
+ const vuuMsgDataIndex = columnMap.vuuMsg ?? -1;
19
+ const vuuRowNumDataIndex = columnMap.vuuRowNum ?? -1;
20
+ const handleSessionMessage = (message)=>{
21
+ if ("viewport-update" === message.type && message.rows) {
22
+ for (const row of message.rows){
23
+ const rowKey = row[metadataKeys.KEY] ?? row[metadataKeys.IDX];
24
+ receivedRowKeysRef.current.add(rowKey);
25
+ const error = getRowVuuMsgError(row, vuuMsgDataIndex, vuuRowNumDataIndex);
26
+ if (error) sessionErrorsRef.current.set(rowKey, error);
27
+ }
28
+ for (const listener of sessionRowUpdateListenersRef.current)listener();
29
+ } else if ("viewport-clear" === message.type) {
30
+ sessionErrorsRef.current.clear();
31
+ receivedRowKeysRef.current.clear();
32
+ }
33
+ };
34
+ if (sessionDs.isRemote) return new Promise((resolve, reject)=>{
35
+ const handleSubscribed = ()=>{
36
+ sessionDs.removeListener("subscribed", handleSubscribed);
37
+ resolve(sessionDs);
38
+ };
39
+ sessionDs.on("subscribed", handleSubscribed);
40
+ try {
41
+ sessionDs.subscribe({
42
+ range: Range(0, 0)
43
+ }, handleSessionMessage);
44
+ } catch (err) {
45
+ sessionDs.removeListener("subscribed", handleSubscribed);
46
+ reject(err);
47
+ }
48
+ });
49
+ if ("function" == typeof sessionDs.subscribe && "initialising" === sessionDs.status) try {
50
+ sessionDs.subscribe({
51
+ range: Range(0, 0)
52
+ }, handleSessionMessage);
53
+ } catch {}
54
+ return sessionDs;
55
+ }
56
+ }), [
57
+ dataSource,
58
+ sessionOverrides
59
+ ]);
60
+ const editSession = useMemo(()=>new EditSession({
61
+ dataSource: importDataSource,
62
+ editSessionApi: "createSessionDataSource",
63
+ rowDefaults
64
+ }), [
65
+ importDataSource,
66
+ rowDefaults
67
+ ]);
68
+ const ownsEditSessionRef = useRef(true);
69
+ const sessionDataSourceRef = useRef(void 0);
70
+ const [sessionTable, setSessionTable] = useState();
71
+ useEffect(()=>()=>{
72
+ const processingPromise = processingPromiseRef?.current;
73
+ (async ()=>{
74
+ try {
75
+ await processingPromise;
76
+ } finally{
77
+ if (ownsEditSessionRef.current) try {
78
+ const sessionDs = sessionDataSourceRef.current ?? editSession.sessionDataSource;
79
+ if (sessionDs?.status !== "unsubscribed") await editSession.end(false);
80
+ } catch (error) {
81
+ console.error("[useCsvUpload] failed to discard edit session during cleanup", error);
82
+ }
83
+ }
84
+ })();
85
+ }, [
86
+ editSession,
87
+ processingPromiseRef
88
+ ]);
89
+ const setActiveSessionDataSource = useCallback((sessionDataSource)=>{
90
+ sessionDataSourceRef.current = sessionDataSource;
91
+ const table = sessionDataSource?.table;
92
+ setSessionTable(table && isSessionTable(table) ? table : void 0);
93
+ }, []);
94
+ const endEditSessionAndNotify = useCallback(async (save, reason)=>{
95
+ ownsEditSessionRef.current = false;
96
+ const sessionDataSource = sessionDataSourceRef.current;
97
+ if (!sessionDataSource) throw Error("CsvUpload has no active edit session.");
98
+ if (!sessionDataSource.endEditSession) throw Error("CsvUpload requires the session datasource to support endEditSession.");
99
+ const currentSessionTable = sessionDataSource.table;
100
+ try {
101
+ await editSession.end(save);
102
+ } finally{
103
+ if ("unsubscribed" !== sessionDataSource.status && "function" == typeof sessionDataSource.unsubscribe) sessionDataSource.unsubscribe();
104
+ setActiveSessionDataSource(void 0);
105
+ }
106
+ onImportSessionEnded?.({
107
+ reason,
108
+ sessionTable: currentSessionTable && isSessionTable(currentSessionTable) ? currentSessionTable : void 0
109
+ });
110
+ }, [
111
+ editSession,
112
+ onImportSessionEnded,
113
+ setActiveSessionDataSource
114
+ ]);
115
+ const beginEditSession = useCallback(async ()=>{
116
+ sessionErrorsRef.current.clear();
117
+ receivedRowKeysRef.current.clear();
118
+ ownsEditSessionRef.current = true;
119
+ const sessionDataSource = await editSession.begin("Empty", "import");
120
+ const sessionVuuTable = sessionDataSource?.table;
121
+ if (void 0 === sessionDataSource || void 0 === sessionVuuTable || !isSessionTable(sessionVuuTable)) throw Error("CsvUpload createSessionDataSource returned no session datasource.");
122
+ setActiveSessionDataSource(sessionDataSource);
123
+ return sessionDataSource;
124
+ }, [
125
+ editSession,
126
+ setActiveSessionDataSource
127
+ ]);
128
+ const closePendingEditSession = useCallback(async (save)=>{
129
+ if (void 0 === sessionDataSourceRef.current) return;
130
+ await endEditSessionAndNotify(save, save ? "saved" : "discarded");
131
+ }, [
132
+ endEditSessionAndNotify
133
+ ]);
134
+ const releaseEditSessionOwnership = useCallback(()=>{
135
+ ownsEditSessionRef.current = false;
136
+ }, []);
137
+ const addAllRows = useCallback(async (mergedValidation, isCancelled)=>{
138
+ const vuuMsgByRow = new Map();
139
+ for (const { rowNum, column, message } of mergedValidation.errors){
140
+ if (rowNum < CSV_FIRST_DATA_ROW_NUMBER) continue;
141
+ const existing = vuuMsgByRow.get(rowNum);
142
+ const columnError = `${column}: ${message}`;
143
+ vuuMsgByRow.set(rowNum, existing ? `${existing}; ${columnError}` : columnError);
144
+ }
145
+ const parsedRowCount = mergedValidation.rows.length;
146
+ const unparsedErrorRows = [
147
+ ...vuuMsgByRow.keys()
148
+ ].filter((rowNum)=>rowNum - CSV_FIRST_DATA_ROW_NUMBER >= parsedRowCount).map((rowNum)=>({
149
+ rowNum,
150
+ rowData: {},
151
+ vuuMsg: vuuMsgByRow.get(rowNum) ?? ""
152
+ }));
153
+ const allRows = [
154
+ ...mergedValidation.rows.map((rowData, idx)=>({
155
+ rowNum: idx + CSV_FIRST_DATA_ROW_NUMBER,
156
+ rowData: rowData ?? {},
157
+ vuuMsg: vuuMsgByRow.get(idx + CSV_FIRST_DATA_ROW_NUMBER) ?? ""
158
+ })),
159
+ ...unparsedErrorRows
160
+ ];
161
+ const rpcErrors = [];
162
+ for (const { rowNum, rowData, vuuMsg } of allRows){
163
+ if (isCancelled()) return false;
164
+ try {
165
+ const payload = vuuMsg ? {
166
+ vuuRowNum: rowNum,
167
+ vuuMsg
168
+ } : {
169
+ ...rowData,
170
+ vuuRowNum: rowNum,
171
+ vuuMsg
172
+ };
173
+ const result = await editSession.addRow(payload);
174
+ if (isRpcError(result)) throw Error(result.errorMessage);
175
+ if ("string" == typeof result) throw Error(result);
176
+ const inlineMsg = getInlineRowErrorMessage(result);
177
+ if (inlineMsg) sessionErrorsRef.current.set(rowNum, {
178
+ rowNum,
179
+ message: inlineMsg
180
+ });
181
+ } catch (error) {
182
+ rpcErrors.push(`${0 === rowNum ? "Header" : `Row ${rowNum}`}: ${toErrorMessage(error)}`);
183
+ }
184
+ }
185
+ if (rpcErrors.length > 0) throw Error(buildRowErrorMessage("Import failed", rpcErrors));
186
+ return allRows.length;
187
+ }, [
188
+ editSession
189
+ ]);
190
+ const checkSessionTableErrors = useCallback(async (sessionDs, expectedRowCount)=>waitForSessionErrors(sessionDs.isRemote ?? false, sessionErrorsRef.current, receivedRowKeysRef.current, expectedRowCount, sessionRowUpdateListenersRef.current), []);
191
+ return {
192
+ addAllRows,
193
+ beginEditSession,
194
+ checkSessionTableErrors,
195
+ closePendingEditSession,
196
+ editSession,
197
+ endEditSessionAndNotify,
198
+ releaseEditSessionOwnership,
199
+ sessionDataSourceRef,
200
+ sessionTable,
201
+ setActiveSessionDataSource
202
+ };
203
+ };
204
+ export { useImportSession };