@platforma-sdk/ui-vue 1.78.2 → 1.78.4

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
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.78.2 build /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.78.4 build /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder build --target browser-lib
5
5
 
6
6
  Building browser-lib project...
@@ -16,7 +16,7 @@ Building browser-lib project...
16
16
  rendering chunks...
17
17
 
18
18
  [vite:dts] Start generate declaration files...
19
- [vite:dts] Declaration files built in 5089ms.
19
+ [vite:dts] Declaration files built in 5727ms.
20
20
 
21
21
  computing gzip size...
22
22
  dist/components/PlAnnotations/components/PlAnnotations.vue?vue&type=style&index=0&lang.css 0.04 kB │ gzip: 0.06 kB
@@ -83,7 +83,7 @@ dist/components/PlAgRowNumHeader.js
83
83
  dist/components/PlAgCellFile/PlAgCellFile.js 0.21 kB │ gzip: 0.16 kB │ map: 2.49 kB
84
84
  dist/components/PlAgDataTable/PlAgRowCount.js 0.21 kB │ gzip: 0.17 kB │ map: 1.72 kB
85
85
  dist/plugins/Monetization/EndOfPeriod.vue_vue_type_style_index_0_lang.module.js 0.22 kB │ gzip: 0.18 kB │ map: 0.42 kB
86
- dist/components/PlAgCsvExporter/PlAgCsvExporter.js 0.22 kB │ gzip: 0.16 kB │ map: 1.51 kB
86
+ dist/components/PlAgCsvExporter/PlAgCsvExporter.js 0.22 kB │ gzip: 0.16 kB │ map: 1.49 kB
87
87
  dist/components/PlAnnotations/components/PlAnnotations.vue_vue_type_style_index_0_lang.module.js 0.22 kB │ gzip: 0.18 kB │ map: 0.42 kB
88
88
  dist/components/PlAgCellProgress/PlAgCellProgress.js 0.23 kB │ gzip: 0.16 kB │ map: 0.55 kB
89
89
  dist/components/PlAgColumnHeader/PlAgColumnHeader.js 0.23 kB │ gzip: 0.17 kB │ map: 3.22 kB
@@ -176,9 +176,9 @@ dist/lib/util/helpers/dist/objects.js
176
176
  dist/components/PlAgDataTable/sources/value-rendering.js 1.21 kB │ gzip: 0.59 kB │ map: 3.54 kB
177
177
  dist/createModel.js 1.22 kB │ gzip: 0.61 kB │ map: 3.11 kB
178
178
  dist/utils.js 1.26 kB │ gzip: 0.62 kB │ map: 3.40 kB
179
+ dist/components/PlAgCsvExporter/PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js 1.28 kB │ gzip: 0.72 kB │ map: 2.05 kB
179
180
  dist/lib/util/helpers/dist/prettyBytes.js 1.29 kB │ gzip: 0.67 kB │ map: 3.79 kB
180
181
  dist/AgGridVue/AgGridTheme.js 1.30 kB │ gzip: 0.59 kB │ map: 2.07 kB
181
- dist/components/PlAgCsvExporter/PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js 1.31 kB │ gzip: 0.74 kB │ map: 2.08 kB
182
182
  dist/components/PlBtnExportArchive/Summary.vue_vue_type_script_setup_true_lang.js 1.31 kB │ gzip: 0.65 kB │ map: 2.35 kB
183
183
  dist/components/PlAgDataTable/PlAgRowCount.vue_vue_type_script_setup_true_lang.js 1.32 kB │ gzip: 0.62 kB │ map: 2.50 kB
184
184
  dist/internal/UpdateSerializer.js 1.33 kB │ gzip: 0.61 kB │ map: 4.28 kB
@@ -188,7 +188,6 @@ dist/components/PlBtnExportArchive/Item.vue_vue_type_script_setup_true_lang.js
188
188
  dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue_vue_type_script_setup_true_lang.js 1.46 kB │ gzip: 0.77 kB │ map: 3.56 kB
189
189
  dist/internal/createAppModel.js 1.48 kB │ gzip: 0.75 kB │ map: 3.89 kB
190
190
  dist/plugins/Monetization/useInfo.js 1.51 kB │ gzip: 0.77 kB │ map: 3.85 kB
191
- dist/components/PlAgCsvExporter/export-csv.js 1.66 kB │ gzip: 0.87 kB │ map: 5.19 kB
192
191
  dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue_vue_type_script_setup_true_lang.js 1.67 kB │ gzip: 0.84 kB │ map: 2.62 kB
193
192
  dist/components/PlAnnotations/components/PlAnnotationsModal.vue_vue_type_script_setup_true_lang.js 1.75 kB │ gzip: 0.75 kB │ map: 1.78 kB
194
193
  dist/AgGridVue/createAgGridColDef.js 1.76 kB │ gzip: 0.75 kB │ map: 9.21 kB
@@ -202,6 +201,7 @@ dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue_vue_
202
201
  dist/components/PlAgDataTable/PlAgDataTableSheets.vue_vue_type_script_setup_true_lang.js 2.45 kB │ gzip: 1.17 kB │ map: 5.01 kB
203
202
  dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_script_setup_true_lang.js 2.58 kB │ gzip: 1.07 kB │ map: 6.02 kB
204
203
  dist/components/PlAnnotations/components/PlAnnotations.vue_vue_type_script_setup_true_lang.js 2.69 kB │ gzip: 1.12 kB │ map: 4.16 kB
204
+ dist/components/PlAgCsvExporter/export-csv.js 2.69 kB │ gzip: 1.20 kB │ map: 8.79 kB
205
205
  dist/lib.js 2.73 kB │ gzip: 0.57 kB │ map: 3.98 kB
206
206
  dist/components/PlAgDataTable/compositions/useGrid.js 2.91 kB │ gzip: 1.29 kB │ map: 6.51 kB
207
207
  dist/components/PlAgColumnHeader/PlAgColumnHeader.vue_vue_type_script_setup_true_lang.js 2.93 kB │ gzip: 1.26 kB │ map: 7.97 kB
@@ -227,12 +227,12 @@ dist/components/PlAdvancedFilter/FilterEditor.vue_vue_type_script_setup_true_lan
227
227
  dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.31 kB │ gzip: 3.90 kB │ map: 29.22 kB
228
228
 
229
229
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
230
- - sourcemaps (32%)
230
+ - sourcemaps (38%)
231
231
  - vite:dts (23%)
232
- - vite:css-post (11%)
233
- - vite:vue (9%)
234
- - vite:build-import-analysis (7%)
232
+ - vite:vue (10%)
233
+ - vite:worker (8%)
234
+ - vite:css-post (7%)
235
235
  See https://rolldown.rs/options/checks#plugintimings for more details.
236
236
  
237
- ✓ built in 5.99s
237
+ ✓ built in 6.58s
238
238
  Build completed successfully
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.78.2 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.78.4 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder formatter --check
5
5
 
6
6
  Checking formatting...
@@ -8,5 +8,5 @@ Checking formatting...
8
8
  Checking formatting...
9
9
 
10
10
  All matched files use the correct format.
11
- Finished in 3513ms on 137 files using 8 threads.
11
+ Finished in 4312ms on 137 files using 8 threads.
12
12
  Format check completed successfully
@@ -1,10 +1,10 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.78.2 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.78.4 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder linter --check
5
5
 
6
6
  Linting project...
7
7
  ↳ oxlint --config /home/runner/_work/platforma/platforma/sdk/ui-vue/.oxlintrc.json --deny-warnings
8
8
  Found 0 warnings and 0 errors.
9
- Finished in 30ms on 120 files with 108 rules using 8 threads.
9
+ Finished in 33ms on 120 files with 108 rules using 8 threads.
10
10
  Linting completed successfully
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.78.2 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.78.4 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder type-check --target browser-lib
5
5
 
6
6
  ↳ vue-tsc.js --noEmit --project ./tsconfig.json --customConditions ,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @platforma-sdk/ui-vue
2
2
 
3
+ ## 1.78.4
4
+
5
+ ### Patch Changes
6
+
7
+ - b0c2b5f: Add `PFrameDriver.exportPTable(handle, { path, columnIndices })` — exports the table to a file natively via `PTableV10.export`, selecting the format from the `path` extension (`csv`/`tsv`/`parquet`/`xlsx`). `columnIndices` selects the columns to export; column headers are derived on the driver side from each field's label annotation (falling back to its spec name), the same way `writePTableToFs` builds CSV/TSV headers. For `xlsx`, the driver checks the table shape and rejects exports whose data rows exceed the 1,000,000-row per-sheet limit (below Excel's hard cap of 1,048,576). The driver currently voids `columnIndices` and exports the full table — it will be honoured once the `PTableV11` native update lands.
8
+
9
+ Add the next PFrames addon interface version — `PFrameFactoryV7` / `PFrameV16` / `PFrameReadAPIV14` / `PTableV11` — where `PTableV11.export` takes `headers` as a `Record<number, string>` (unified column index → header name) that both selects the columns to export (its keys) and names them (its values), instead of a positional `string[]`. The current `V6`/`V15`/`V13`/`V10` surface is unchanged and still used by the driver; the new version is defined ahead of its PFrames implementation, after which the monorepo will migrate and drop the old one.
10
+
11
+ `PlAgCsvExporter` no longer hardcodes the output format — it offers the available formats as save-dialog file-type filters and derives the format from the chosen path. When the runtime advertises `exportPTable` it exports the visible table handle directly (`csv`/`tsv`/`parquet`/`xlsx`, no gzip); otherwise it falls back to `writePTableToFs` (`csv`/`tsv`, plain or gzip-compressed depending on the chosen `.gz` extension).
12
+
13
+ - Updated dependencies [b0c2b5f]
14
+ - @milaboratories/pl-model-common@1.45.0
15
+ - @milaboratories/pf-spec-driver@1.4.3
16
+ - @platforma-sdk/model@1.78.4
17
+ - @milaboratories/uikit@2.14.22
18
+
3
19
  ## 1.78.2
4
20
 
5
21
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCsvExporter.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle, format: \"csv\" }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"PlAgCsvExporter.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":""}
@@ -11,10 +11,7 @@ var _ = /* @__PURE__ */ s({
11
11
  },
12
12
  setup(s) {
13
13
  let _ = s, { api: v } = u(_), y = t(), b = l(!1), x = () => {
14
- let t = m(_.tableHandle) ? void 0 : {
15
- tableHandle: _.tableHandle,
16
- format: "csv"
17
- };
14
+ let t = m(_.tableHandle) ? void 0 : { tableHandle: _.tableHandle };
18
15
  m(t) || (b.value = !0, e(v.value, t).finally(() => b.value = !1));
19
16
  }, S = g("PlAgCsvExporter");
20
17
  return (e, t) => d(S) && d(y) ? (c(), r(n, {
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle, format: \"csv\" }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;EASA,IAAM,IAAQ,GAIR,EAAE,KAAK,MAAY,EAAO,EAAM,EAChC,IAAqB,GAAsB,EAE3C,IAAY,EAAW,GAAM,EAC7B,UAAuB;GAC3B,IAAM,IAA4C,EAAM,EAAM,YAAW,GAErE,KAAA,IADA;IAAE,aAAa,EAAM;IAAa,QAAQ;IAAM;AAGhD,KAAM,EAAc,KAIxB,EAAU,QAAQ,IAClB,EAAU,EAAQ,OAAO,EAAc,CAAC,cAAe,EAAU,QAAQ,GAAO;KAG5E,IAAiB,EAAkC,kBAAkB;mBAIzD,EAAA,EAAc,IAAI,EAAA,EAAkB,IAAA,GAAA,EAApD,EAIW,GAAA;;GAJ4C,IAAI,EAAA,EAAc;MACvE,EAEa,EAAA,EAAA,EAAA;GAFA,SAAS,EAAA;GAAW,MAAK;GAAU,SAAK,EAAO,GAAc,CAAA,OAAA,CAAA;;oBAE1E,CAAA,GAAA,AAAA,EAAA,OAAA,CAAA,EAF4E,YAE5E,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;EASA,IAAM,IAAQ,GAIR,EAAE,KAAK,MAAY,EAAO,EAAM,EAChC,IAAqB,GAAsB,EAE3C,IAAY,EAAW,GAAM,EAC7B,UAAuB;GAC3B,IAAM,IAA4C,EAAM,EAAM,YAAW,GAErE,KAAA,IADA,EAAE,aAAa,EAAM,aAAY;AAGjC,KAAM,EAAc,KAIxB,EAAU,QAAQ,IAClB,EAAU,EAAQ,OAAO,EAAc,CAAC,cAAe,EAAU,QAAQ,GAAO;KAG5E,IAAiB,EAAkC,kBAAkB;mBAIzD,EAAA,EAAc,IAAI,EAAA,EAAkB,IAAA,GAAA,EAApD,EAIW,GAAA;;GAJ4C,IAAI,EAAA,EAAc;MACvE,EAEa,EAAA,EAAA,EAAA;GAFA,SAAS,EAAA;GAAW,MAAK;GAAU,SAAK,EAAO,GAAc,CAAA,OAAA,CAAA;;oBAE1E,CAAA,GAAA,AAAA,EAAA,OAAA,CAAA,EAF4E,YAE5E,GAAA,CAAA,CAAA,CAAA"}
@@ -1,16 +1,24 @@
1
1
  import { GridApi } from 'ag-grid-enterprise';
2
- import { PTableHandle, PTableDownloadFormat, PTableColumnSpec, PFrameSpecDriver, WritePTableToFsResult } from '@platforma-sdk/model';
2
+ import { PTableHandle, PTableColumnSpec, PFrameSpecDriver, WritePTableToFsResult } from '@platforma-sdk/model';
3
3
  import { Nil } from '@milaboratories/helpers';
4
- /** Options for the native CSV export path. */
4
+ /** Options for the native table export. */
5
5
  export interface ExportOptions {
6
6
  tableHandle: PTableHandle;
7
- format: PTableDownloadFormat;
8
7
  defaultFileName?: string;
9
8
  }
10
9
  /**
11
- * CSV export via the platforma desktop runtime. Prompts for a save
12
- * destination via the `Dialog` service, then streams the PTable to the
13
- * chosen path via `PFrame.writePTableToFs`.
10
+ * Table export via the platforma desktop runtime. Prompts for a save
11
+ * destination via the `Dialog` service offering the available output formats
12
+ * as file-type filters so the user picks the format — then writes the PTable to
13
+ * the chosen path.
14
+ *
15
+ * Prefers the native `PFrame.exportPTable` when the runtime advertises it: the
16
+ * table handle is the *visible* one, so exporting the whole handle reproduces
17
+ * exactly the visible columns/rows, and the format (`csv`/`tsv`/`parquet`/
18
+ * `xlsx`) is taken from the chosen file extension. Falls back to streaming the
19
+ * visible columns via `PFrame.writePTableToFs` (`csv`/`tsv`, optionally
20
+ * gzip-compressed when the chosen path ends in `.gz`) on runtimes that do not
21
+ * advertise `exportPTable`.
14
22
  */
15
23
  export declare function exportCsv(gridApi: GridApi, nativeOptions: ExportOptions): Promise<undefined | WritePTableToFsResult>;
16
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"export-csv.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAI9C,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,YAAY,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,SAAS,GAAG,qBAAqB,CAAC,CAiC5C;AAUD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,EAAE,EACzB,UAAU,EAAE,gBAAgB,GAC3B,GAAG,GAAG,MAAM,EAAE,CAkBhB"}
1
+ {"version":3,"file":"export-csv.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAEV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAI9C,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,YAAY,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAkCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,SAAS,GAAG,qBAAqB,CAAC,CAoD5C;AAUD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,EAAE,EACzB,UAAU,EAAE,gBAAgB,GAC3B,GAAG,GAAG,MAAM,EAAE,CAkBhB"}
@@ -4,26 +4,86 @@ import "../PlAgDataTable/index.js";
4
4
  import { getPTableColumnId as t } from "@platforma-sdk/model";
5
5
  import { isNil as n } from "es-toolkit";
6
6
  //#region src/components/PlAgCsvExporter/export-csv.ts
7
- async function r(t, r) {
8
- let { dialog: a, pframe: s, pframeSpec: c } = e();
9
- if (n(a)) throw Error("dialog service is not available in the current environment");
10
- if (n(s)) throw Error("pframe service is not available");
11
- if (n(c)) throw Error("pframeSpec service is not available");
12
- let l = o(t, await s.getSpec(r.tableHandle), c);
13
- if (n(l)) return;
14
- let { canceled: u, path: d } = await a.showSaveDialog({ defaultFileName: (r.defaultFileName ?? `table_${i(/* @__PURE__ */ new Date())}`) + `.${r.format}.gz` });
15
- if (!(u || n(d))) return s.writePTableToFs(r.tableHandle, {
16
- path: d,
17
- format: r.format,
18
- columnIndices: l,
19
- compression: { type: "gzip" }
7
+ var r = [
8
+ {
9
+ name: "CSV",
10
+ extensions: ["csv"]
11
+ },
12
+ {
13
+ name: "TSV",
14
+ extensions: ["tsv"]
15
+ },
16
+ {
17
+ name: "Parquet",
18
+ extensions: ["parquet"]
19
+ },
20
+ {
21
+ name: "Excel",
22
+ extensions: ["xlsx"]
23
+ }
24
+ ], i = [
25
+ {
26
+ name: "CSV (gzip)",
27
+ extensions: ["csv.gz"]
28
+ },
29
+ {
30
+ name: "CSV",
31
+ extensions: ["csv"]
32
+ },
33
+ {
34
+ name: "TSV (gzip)",
35
+ extensions: ["tsv.gz"]
36
+ },
37
+ {
38
+ name: "TSV",
39
+ extensions: ["tsv"]
40
+ }
41
+ ];
42
+ function a(e) {
43
+ let t = e.toLowerCase(), n = t.endsWith(".gz") ? t.slice(0, -3) : t;
44
+ return n.slice(n.lastIndexOf(".") + 1);
45
+ }
46
+ function o(e, t) {
47
+ return t.some(({ extensions: t }) => t.some((t) => e.endsWith("." + t)));
48
+ }
49
+ async function s(t, s) {
50
+ let { dialog: l, pframe: d, pframeSpec: f } = e();
51
+ if (n(l)) throw Error("dialog service is not available in the current environment");
52
+ if (n(d)) throw Error("pframe service is not available");
53
+ if (n(f)) throw Error("pframeSpec service is not available");
54
+ let p = u(t, await d.getSpec(s.tableHandle), f);
55
+ if (n(p)) return;
56
+ let m = s.defaultFileName ?? `table_${c(/* @__PURE__ */ new Date())}`;
57
+ if (typeof d.exportPTable == "function") {
58
+ let { canceled: e, path: t } = await l.showSaveDialog({
59
+ defaultFileName: `${m}.csv`,
60
+ filters: r
61
+ });
62
+ if (e || n(t) || !o(t, r)) return;
63
+ await d.exportPTable(s.tableHandle, {
64
+ path: t,
65
+ columnIndices: p
66
+ });
67
+ return;
68
+ }
69
+ let { canceled: h, path: g } = await l.showSaveDialog({
70
+ defaultFileName: `${m}.csv.gz`,
71
+ filters: i
72
+ });
73
+ if (h || n(g) || !o(g, i)) return;
74
+ let _ = a(g);
75
+ if (!(_ !== "csv" && _ !== "tsv")) return d.writePTableToFs(s.tableHandle, {
76
+ path: g,
77
+ format: _,
78
+ columnIndices: p,
79
+ ...g.toLowerCase().endsWith(".gz") && { compression: { type: "gzip" } }
20
80
  });
21
81
  }
22
- function i(e) {
82
+ function c(e) {
23
83
  let t = (e) => String(e).padStart(2, "0");
24
84
  return `${t(e.getDate())}-${t(e.getMonth() + 1)}-${e.getFullYear()}_${t(e.getHours())}-${t(e.getMinutes())}-${t(e.getSeconds())}`;
25
85
  }
26
- function a() {
86
+ function l() {
27
87
  try {
28
88
  let t = e();
29
89
  return !n(t?.dialog) && !n(t?.pframe);
@@ -31,11 +91,11 @@ function a() {
31
91
  return !1;
32
92
  }
33
93
  }
34
- function o(e, r, i) {
94
+ function u(e, r, i) {
35
95
  let a = e.getColumnDefs();
36
96
  return n(a) ? void 0 : [...new Set(a.flatMap((e) => "children" in e || e.hide === !0 || n(e.colId) || e.colId === "\"##RowNumberColumnId##\"" ? [] : [e.context]).map((e) => i.findTableColumn(r, t(e))))].filter((e) => e !== -1);
37
97
  }
38
98
  //#endregion
39
- export { r as exportCsv, a as isCsvExportAvailable };
99
+ export { s as exportCsv, l as isCsvExportAvailable };
40
100
 
41
101
  //# sourceMappingURL=export-csv.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"export-csv.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"sourcesContent":["import { type ColDef, type ColGroupDef, type GridApi } from \"ag-grid-enterprise\";\nimport type {\n PTableHandle,\n PTableDownloadFormat,\n PTableColumnSpec,\n PFrameSpecDriver,\n WritePTableToFsResult,\n} from \"@platforma-sdk/model\";\nimport { getPTableColumnId } from \"@platforma-sdk/model\";\nimport { isNil } from \"es-toolkit\";\nimport { Nil } from \"@milaboratories/helpers\";\nimport { getServices } from \"../../internal/getServices\";\nimport { PlAgDataTableRowNumberColId } from \"../PlAgDataTable\";\n\n/** Options for the native CSV export path. */\nexport interface ExportOptions {\n tableHandle: PTableHandle;\n format: PTableDownloadFormat;\n defaultFileName?: string;\n}\n\n/**\n * CSV export via the platforma desktop runtime. Prompts for a save\n * destination via the `Dialog` service, then streams the PTable to the\n * chosen path via `PFrame.writePTableToFs`.\n */\nexport async function exportCsv(\n gridApi: GridApi,\n nativeOptions: ExportOptions,\n): Promise<undefined | WritePTableToFsResult> {\n const { dialog, pframe, pframeSpec } = getServices();\n if (isNil(dialog)) {\n throw new Error(\"dialog service is not available in the current environment\");\n }\n if (isNil(pframe)) {\n throw new Error(\"pframe service is not available\");\n }\n if (isNil(pframeSpec)) {\n throw new Error(\"pframeSpec service is not available\");\n }\n\n const specs = await pframe.getSpec(nativeOptions.tableHandle);\n const columnIndices = collectVisibleColumnIndices(gridApi, specs, pframeSpec);\n if (isNil(columnIndices)) {\n return undefined;\n }\n\n const { canceled, path } = await dialog.showSaveDialog({\n defaultFileName:\n (nativeOptions.defaultFileName ?? `table_${formatTimestamp(new Date())}`) +\n `.${nativeOptions.format}.gz`,\n });\n if (canceled || isNil(path)) {\n return undefined;\n }\n\n return pframe.writePTableToFs(nativeOptions.tableHandle, {\n path,\n format: nativeOptions.format,\n columnIndices,\n compression: { type: \"gzip\" },\n });\n}\n\nfunction formatTimestamp(d: Date): string {\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()}` +\n `_${pad(d.getHours())}-${pad(d.getMinutes())}-${pad(d.getSeconds())}`\n );\n}\n\n/**\n * Checks whether the native CSV export capability is available in the\n * current platforma runtime environment. Both `Dialog` and `PFrame`\n * services must be present — desktop-app wires them, web/preview do not.\n */\nexport function isCsvExportAvailable(): boolean {\n try {\n const services = getServices();\n return !isNil(services?.dialog) && !isNil(services?.pframe);\n } catch {\n return false;\n }\n}\n\n/**\n * Collect unified column indices for visible (non-hidden) columns from the\n * ag-grid column defs, remapped onto the provided PTable spec array so the\n * indices match the current table handle (ColDef.field indices may be stale\n * or diverge from the spec order).\n */\nexport function collectVisibleColumnIndices(\n gridApi: GridApi,\n specs: PTableColumnSpec[],\n pframeSpec: PFrameSpecDriver,\n): Nil | number[] {\n const columnDefs = gridApi.getColumnDefs();\n if (isNil(columnDefs)) {\n return;\n }\n\n const findIndex = (spec: PTableColumnSpec) =>\n pframeSpec.findTableColumn(specs, getPTableColumnId(spec));\n\n const specsForDef = (def: ColDef | ColGroupDef): PTableColumnSpec[] => {\n if (\"children\" in def) return [];\n if (def.hide === true) return [];\n if (isNil(def.colId)) return [];\n if (def.colId === PlAgDataTableRowNumberColId) return [];\n return [def.context as PTableColumnSpec];\n };\n\n return [...new Set(columnDefs.flatMap(specsForDef).map(findIndex))].filter((idx) => idx !== -1);\n}\n"],"mappings":";;;;;;AA0BA,eAAsB,EACpB,GACA,GAC4C;CAC5C,IAAM,EAAE,WAAQ,WAAQ,kBAAe,GAAa;AACpD,KAAI,EAAM,EAAO,CACf,OAAU,MAAM,6DAA6D;AAE/E,KAAI,EAAM,EAAO,CACf,OAAU,MAAM,kCAAkC;AAEpD,KAAI,EAAM,EAAW,CACnB,OAAU,MAAM,sCAAsC;CAIxD,IAAM,IAAgB,EAA4B,GADpC,MAAM,EAAO,QAAQ,EAAc,YAAY,EACK,EAAW;AAC7E,KAAI,EAAM,EAAc,CACtB;CAGF,IAAM,EAAE,aAAU,YAAS,MAAM,EAAO,eAAe,EACrD,kBACG,EAAc,mBAAmB,SAAS,kBAAgB,IAAI,MAAM,CAAC,MACtE,IAAI,EAAc,OAAO,MAC5B,CAAC;AACE,YAAY,EAAM,EAAK,EAI3B,QAAO,EAAO,gBAAgB,EAAc,aAAa;EACvD;EACA,QAAQ,EAAc;EACtB;EACA,aAAa,EAAE,MAAM,QAAQ;EAC9B,CAAC;;AAGJ,SAAS,EAAgB,GAAiB;CACxC,IAAM,KAAO,MAAc,OAAO,EAAE,CAAC,SAAS,GAAG,IAAI;AACrD,QACE,GAAG,EAAI,EAAE,SAAS,CAAC,CAAC,GAAG,EAAI,EAAE,UAAU,GAAG,EAAE,CAAC,GAAG,EAAE,aAAa,CAAA,GAC3D,EAAI,EAAE,UAAU,CAAC,CAAC,GAAG,EAAI,EAAE,YAAY,CAAC,CAAC,GAAG,EAAI,EAAE,YAAY,CAAC;;AASvE,SAAgB,IAAgC;AAC9C,KAAI;EACF,IAAM,IAAW,GAAa;AAC9B,SAAO,CAAC,EAAM,GAAU,OAAO,IAAI,CAAC,EAAM,GAAU,OAAO;SACrD;AACN,SAAO;;;AAUX,SAAgB,EACd,GACA,GACA,GACgB;CAChB,IAAM,IAAa,EAAQ,eAAe;AAgB1C,QAfI,EAAM,EAAW,GACnB,SAcK,CAAC,GAAG,IAAI,IAAI,EAAW,SART,MACf,cAAc,KACd,EAAI,SAAS,MACb,EAAM,EAAI,MAAM,IAChB,EAAI,UAAA,8BAA8C,EAAE,GACjD,CAAC,EAAI,QAA4B,CAGQ,CAAC,KAXhC,MACjB,EAAW,gBAAgB,GAAO,EAAkB,EAAK,CAAC,CAUK,CAAC,CAAC,CAAC,QAAQ,MAAQ,MAAQ,GAAG"}
1
+ {"version":3,"file":"export-csv.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"sourcesContent":["import { type ColDef, type ColGroupDef, type GridApi } from \"ag-grid-enterprise\";\nimport type {\n FileFilter,\n PTableHandle,\n PTableColumnSpec,\n PFrameSpecDriver,\n WritePTableToFsResult,\n} from \"@platforma-sdk/model\";\nimport { getPTableColumnId } from \"@platforma-sdk/model\";\nimport { isNil } from \"es-toolkit\";\nimport { Nil } from \"@milaboratories/helpers\";\nimport { getServices } from \"../../internal/getServices\";\nimport { PlAgDataTableRowNumberColId } from \"../PlAgDataTable\";\n\n/** Options for the native table export. */\nexport interface ExportOptions {\n tableHandle: PTableHandle;\n defaultFileName?: string;\n}\n\n/** Save-dialog file-type filters for the native `exportPTable` path. */\nconst NATIVE_EXPORT_FILTERS: FileFilter[] = [\n { name: \"CSV\", extensions: [\"csv\"] },\n { name: \"TSV\", extensions: [\"tsv\"] },\n { name: \"Parquet\", extensions: [\"parquet\"] },\n { name: \"Excel\", extensions: [\"xlsx\"] },\n];\n\n/**\n * Save-dialog file-type filters for the `writePTableToFs` fallback. csv/tsv\n * only, offered both plain and gzip-compressed — a trailing `.gz` in the\n * chosen path selects gzip compression.\n */\nconst FALLBACK_EXPORT_FILTERS: FileFilter[] = [\n { name: \"CSV (gzip)\", extensions: [\"csv.gz\"] },\n { name: \"CSV\", extensions: [\"csv\"] },\n { name: \"TSV (gzip)\", extensions: [\"tsv.gz\"] },\n { name: \"TSV\", extensions: [\"tsv\"] },\n];\n\n/** Table format from a save path, ignoring a trailing `.gz`. e.g. `\"t.csv.gz\"` → `\"csv\"`. */\nfunction tableFormatFromPath(path: string): string {\n const lower = path.toLowerCase();\n const base = lower.endsWith(\".gz\") ? lower.slice(0, -3) : lower;\n return base.slice(base.lastIndexOf(\".\") + 1);\n}\n\n/** True when `path` ends with one of the filters' extensions (e.g. `\".csv\"`). */\nfunction matchesFilterExtension(path: string, filters: FileFilter[]): boolean {\n return filters.some(({ extensions }) => extensions.some((ext) => path.endsWith(\".\" + ext)));\n}\n\n/**\n * Table export via the platforma desktop runtime. Prompts for a save\n * destination via the `Dialog` service — offering the available output formats\n * as file-type filters so the user picks the format — then writes the PTable to\n * the chosen path.\n *\n * Prefers the native `PFrame.exportPTable` when the runtime advertises it: the\n * table handle is the *visible* one, so exporting the whole handle reproduces\n * exactly the visible columns/rows, and the format (`csv`/`tsv`/`parquet`/\n * `xlsx`) is taken from the chosen file extension. Falls back to streaming the\n * visible columns via `PFrame.writePTableToFs` (`csv`/`tsv`, optionally\n * gzip-compressed when the chosen path ends in `.gz`) on runtimes that do not\n * advertise `exportPTable`.\n */\nexport async function exportCsv(\n gridApi: GridApi,\n nativeOptions: ExportOptions,\n): Promise<undefined | WritePTableToFsResult> {\n const { dialog, pframe, pframeSpec } = getServices();\n if (isNil(dialog)) {\n throw new Error(\"dialog service is not available in the current environment\");\n }\n if (isNil(pframe)) {\n throw new Error(\"pframe service is not available\");\n }\n if (isNil(pframeSpec)) {\n throw new Error(\"pframeSpec service is not available\");\n }\n\n const specs = await pframe.getSpec(nativeOptions.tableHandle);\n const columnIndices = collectVisibleColumnIndices(gridApi, specs, pframeSpec);\n if (isNil(columnIndices)) {\n return undefined;\n }\n\n const baseFileName = nativeOptions.defaultFileName ?? `table_${formatTimestamp(new Date())}`;\n\n if (typeof pframe.exportPTable === \"function\") {\n const { canceled, path } = await dialog.showSaveDialog({\n defaultFileName: `${baseFileName}.csv`,\n filters: NATIVE_EXPORT_FILTERS,\n });\n if (canceled || isNil(path) || !matchesFilterExtension(path, NATIVE_EXPORT_FILTERS)) {\n return undefined;\n }\n\n await pframe.exportPTable(nativeOptions.tableHandle, { path, columnIndices });\n return undefined;\n }\n\n const { canceled, path } = await dialog.showSaveDialog({\n defaultFileName: `${baseFileName}.csv.gz`,\n filters: FALLBACK_EXPORT_FILTERS,\n });\n if (canceled || isNil(path) || !matchesFilterExtension(path, FALLBACK_EXPORT_FILTERS)) {\n return undefined;\n }\n\n const format = tableFormatFromPath(path);\n if (format !== \"csv\" && format !== \"tsv\") {\n return undefined;\n }\n\n return pframe.writePTableToFs(nativeOptions.tableHandle, {\n path,\n format,\n columnIndices,\n ...(path.toLowerCase().endsWith(\".gz\") && { compression: { type: \"gzip\" } }),\n });\n}\n\nfunction formatTimestamp(d: Date): string {\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()}` +\n `_${pad(d.getHours())}-${pad(d.getMinutes())}-${pad(d.getSeconds())}`\n );\n}\n\n/**\n * Checks whether the native CSV export capability is available in the\n * current platforma runtime environment. Both `Dialog` and `PFrame`\n * services must be present — desktop-app wires them, web/preview do not.\n */\nexport function isCsvExportAvailable(): boolean {\n try {\n const services = getServices();\n return !isNil(services?.dialog) && !isNil(services?.pframe);\n } catch {\n return false;\n }\n}\n\n/**\n * Collect unified column indices for visible (non-hidden) columns from the\n * ag-grid column defs, remapped onto the provided PTable spec array so the\n * indices match the current table handle (ColDef.field indices may be stale\n * or diverge from the spec order).\n */\nexport function collectVisibleColumnIndices(\n gridApi: GridApi,\n specs: PTableColumnSpec[],\n pframeSpec: PFrameSpecDriver,\n): Nil | number[] {\n const columnDefs = gridApi.getColumnDefs();\n if (isNil(columnDefs)) {\n return;\n }\n\n const findIndex = (spec: PTableColumnSpec) =>\n pframeSpec.findTableColumn(specs, getPTableColumnId(spec));\n\n const specsForDef = (def: ColDef | ColGroupDef): PTableColumnSpec[] => {\n if (\"children\" in def) return [];\n if (def.hide === true) return [];\n if (isNil(def.colId)) return [];\n if (def.colId === PlAgDataTableRowNumberColId) return [];\n return [def.context as PTableColumnSpec];\n };\n\n return [...new Set(columnDefs.flatMap(specsForDef).map(findIndex))].filter((idx) => idx !== -1);\n}\n"],"mappings":";;;;;;AAqBA,IAAM,IAAsC;CAC1C;EAAE,MAAM;EAAO,YAAY,CAAC,MAAM;EAAE;CACpC;EAAE,MAAM;EAAO,YAAY,CAAC,MAAM;EAAE;CACpC;EAAE,MAAM;EAAW,YAAY,CAAC,UAAU;EAAE;CAC5C;EAAE,MAAM;EAAS,YAAY,CAAC,OAAO;EAAE;CACxC,EAOK,IAAwC;CAC5C;EAAE,MAAM;EAAc,YAAY,CAAC,SAAS;EAAE;CAC9C;EAAE,MAAM;EAAO,YAAY,CAAC,MAAM;EAAE;CACpC;EAAE,MAAM;EAAc,YAAY,CAAC,SAAS;EAAE;CAC9C;EAAE,MAAM;EAAO,YAAY,CAAC,MAAM;EAAE;CACrC;AAGD,SAAS,EAAoB,GAAsB;CACjD,IAAM,IAAQ,EAAK,aAAa,EAC1B,IAAO,EAAM,SAAS,MAAM,GAAG,EAAM,MAAM,GAAG,GAAG,GAAG;AAC1D,QAAO,EAAK,MAAM,EAAK,YAAY,IAAI,GAAG,EAAE;;AAI9C,SAAS,EAAuB,GAAc,GAAgC;AAC5E,QAAO,EAAQ,MAAM,EAAE,oBAAiB,EAAW,MAAM,MAAQ,EAAK,SAAS,MAAM,EAAI,CAAC,CAAC;;AAiB7F,eAAsB,EACpB,GACA,GAC4C;CAC5C,IAAM,EAAE,WAAQ,WAAQ,kBAAe,GAAa;AACpD,KAAI,EAAM,EAAO,CACf,OAAU,MAAM,6DAA6D;AAE/E,KAAI,EAAM,EAAO,CACf,OAAU,MAAM,kCAAkC;AAEpD,KAAI,EAAM,EAAW,CACnB,OAAU,MAAM,sCAAsC;CAIxD,IAAM,IAAgB,EAA4B,GADpC,MAAM,EAAO,QAAQ,EAAc,YAAY,EACK,EAAW;AAC7E,KAAI,EAAM,EAAc,CACtB;CAGF,IAAM,IAAe,EAAc,mBAAmB,SAAS,kBAAgB,IAAI,MAAM,CAAC;AAE1F,KAAI,OAAO,EAAO,gBAAiB,YAAY;EAC7C,IAAM,EAAE,aAAU,YAAS,MAAM,EAAO,eAAe;GACrD,iBAAiB,GAAG,EAAa;GACjC,SAAS;GACV,CAAC;AACF,MAAI,KAAY,EAAM,EAAK,IAAI,CAAC,EAAuB,GAAM,EAAsB,CACjF;AAGF,QAAM,EAAO,aAAa,EAAc,aAAa;GAAE;GAAM;GAAe,CAAC;AAC7E;;CAGF,IAAM,EAAE,aAAU,YAAS,MAAM,EAAO,eAAe;EACrD,iBAAiB,GAAG,EAAa;EACjC,SAAS;EACV,CAAC;AACF,KAAI,KAAY,EAAM,EAAK,IAAI,CAAC,EAAuB,GAAM,EAAwB,CACnF;CAGF,IAAM,IAAS,EAAoB,EAAK;AACpC,aAAW,SAAS,MAAW,OAInC,QAAO,EAAO,gBAAgB,EAAc,aAAa;EACvD;EACA;EACA;EACA,GAAI,EAAK,aAAa,CAAC,SAAS,MAAM,IAAI,EAAE,aAAa,EAAE,MAAM,QAAQ,EAAE;EAC5E,CAAC;;AAGJ,SAAS,EAAgB,GAAiB;CACxC,IAAM,KAAO,MAAc,OAAO,EAAE,CAAC,SAAS,GAAG,IAAI;AACrD,QACE,GAAG,EAAI,EAAE,SAAS,CAAC,CAAC,GAAG,EAAI,EAAE,UAAU,GAAG,EAAE,CAAC,GAAG,EAAE,aAAa,CAAA,GAC3D,EAAI,EAAE,UAAU,CAAC,CAAC,GAAG,EAAI,EAAE,YAAY,CAAC,CAAC,GAAG,EAAI,EAAE,YAAY,CAAC;;AASvE,SAAgB,IAAgC;AAC9C,KAAI;EACF,IAAM,IAAW,GAAa;AAC9B,SAAO,CAAC,EAAM,GAAU,OAAO,IAAI,CAAC,EAAM,GAAU,OAAO;SACrD;AACN,SAAO;;;AAUX,SAAgB,EACd,GACA,GACA,GACgB;CAChB,IAAM,IAAa,EAAQ,eAAe;AAgB1C,QAfI,EAAM,EAAW,GACnB,SAcK,CAAC,GAAG,IAAI,IAAI,EAAW,SART,MACf,cAAc,KACd,EAAI,SAAS,MACb,EAAM,EAAI,MAAM,IAChB,EAAI,UAAA,8BAA8C,EAAE,GACjD,CAAC,EAAI,QAA4B,CAGQ,CAAC,KAXhC,MACjB,EAAW,gBAAgB,GAAO,EAAkB,EAAK,CAAC,CAUK,CAAC,CAAC,CAAC,QAAQ,MAAQ,MAAQ,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAUb,CARM,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
1
+ {"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAiBZ,CAfK,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.78.2",
3
+ "version": "1.78.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -26,10 +26,10 @@
26
26
  "lru-cache": "^11.2.2",
27
27
  "vue": "3.5.24",
28
28
  "zod": "~3.25.76",
29
- "@milaboratories/pf-spec-driver": "1.4.2",
30
- "@milaboratories/pl-model-common": "1.44.0",
31
- "@milaboratories/uikit": "2.14.21",
32
- "@platforma-sdk/model": "1.78.2"
29
+ "@milaboratories/uikit": "2.14.22",
30
+ "@milaboratories/pf-spec-driver": "1.4.3",
31
+ "@platforma-sdk/model": "1.78.4",
32
+ "@milaboratories/pl-model-common": "1.45.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@faker-js/faker": "^9.2.0",
@@ -45,10 +45,10 @@
45
45
  "typescript": "~5.9.3",
46
46
  "vite": "^8.0.6",
47
47
  "vitest": "^4.1.3",
48
- "@milaboratories/build-configs": "2.0.0",
49
48
  "@milaboratories/helpers": "1.14.2",
50
- "@milaboratories/ts-builder": "1.5.0",
51
- "@milaboratories/ts-configs": "1.2.3"
49
+ "@milaboratories/build-configs": "2.0.0",
50
+ "@milaboratories/ts-configs": "1.2.3",
51
+ "@milaboratories/ts-builder": "1.5.0"
52
52
  },
53
53
  "scripts": {
54
54
  "dev": "ts-builder serve --target browser-lib",
@@ -17,7 +17,7 @@ const csvExportAvailable = isCsvExportAvailable();
17
17
  const exporting = shallowRef(false);
18
18
  const initiateExport = () => {
19
19
  const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)
20
- ? { tableHandle: props.tableHandle, format: "csv" }
20
+ ? { tableHandle: props.tableHandle }
21
21
  : undefined;
22
22
 
23
23
  if (isNil(nativeOptions)) {
@@ -1,7 +1,7 @@
1
1
  import { type ColDef, type ColGroupDef, type GridApi } from "ag-grid-enterprise";
2
2
  import type {
3
+ FileFilter,
3
4
  PTableHandle,
4
- PTableDownloadFormat,
5
5
  PTableColumnSpec,
6
6
  PFrameSpecDriver,
7
7
  WritePTableToFsResult,
@@ -12,17 +12,57 @@ import { Nil } from "@milaboratories/helpers";
12
12
  import { getServices } from "../../internal/getServices";
13
13
  import { PlAgDataTableRowNumberColId } from "../PlAgDataTable";
14
14
 
15
- /** Options for the native CSV export path. */
15
+ /** Options for the native table export. */
16
16
  export interface ExportOptions {
17
17
  tableHandle: PTableHandle;
18
- format: PTableDownloadFormat;
19
18
  defaultFileName?: string;
20
19
  }
21
20
 
21
+ /** Save-dialog file-type filters for the native `exportPTable` path. */
22
+ const NATIVE_EXPORT_FILTERS: FileFilter[] = [
23
+ { name: "CSV", extensions: ["csv"] },
24
+ { name: "TSV", extensions: ["tsv"] },
25
+ { name: "Parquet", extensions: ["parquet"] },
26
+ { name: "Excel", extensions: ["xlsx"] },
27
+ ];
28
+
29
+ /**
30
+ * Save-dialog file-type filters for the `writePTableToFs` fallback. csv/tsv
31
+ * only, offered both plain and gzip-compressed — a trailing `.gz` in the
32
+ * chosen path selects gzip compression.
33
+ */
34
+ const FALLBACK_EXPORT_FILTERS: FileFilter[] = [
35
+ { name: "CSV (gzip)", extensions: ["csv.gz"] },
36
+ { name: "CSV", extensions: ["csv"] },
37
+ { name: "TSV (gzip)", extensions: ["tsv.gz"] },
38
+ { name: "TSV", extensions: ["tsv"] },
39
+ ];
40
+
41
+ /** Table format from a save path, ignoring a trailing `.gz`. e.g. `"t.csv.gz"` → `"csv"`. */
42
+ function tableFormatFromPath(path: string): string {
43
+ const lower = path.toLowerCase();
44
+ const base = lower.endsWith(".gz") ? lower.slice(0, -3) : lower;
45
+ return base.slice(base.lastIndexOf(".") + 1);
46
+ }
47
+
48
+ /** True when `path` ends with one of the filters' extensions (e.g. `".csv"`). */
49
+ function matchesFilterExtension(path: string, filters: FileFilter[]): boolean {
50
+ return filters.some(({ extensions }) => extensions.some((ext) => path.endsWith("." + ext)));
51
+ }
52
+
22
53
  /**
23
- * CSV export via the platforma desktop runtime. Prompts for a save
24
- * destination via the `Dialog` service, then streams the PTable to the
25
- * chosen path via `PFrame.writePTableToFs`.
54
+ * Table export via the platforma desktop runtime. Prompts for a save
55
+ * destination via the `Dialog` service offering the available output formats
56
+ * as file-type filters so the user picks the format — then writes the PTable to
57
+ * the chosen path.
58
+ *
59
+ * Prefers the native `PFrame.exportPTable` when the runtime advertises it: the
60
+ * table handle is the *visible* one, so exporting the whole handle reproduces
61
+ * exactly the visible columns/rows, and the format (`csv`/`tsv`/`parquet`/
62
+ * `xlsx`) is taken from the chosen file extension. Falls back to streaming the
63
+ * visible columns via `PFrame.writePTableToFs` (`csv`/`tsv`, optionally
64
+ * gzip-compressed when the chosen path ends in `.gz`) on runtimes that do not
65
+ * advertise `exportPTable`.
26
66
  */
27
67
  export async function exportCsv(
28
68
  gridApi: GridApi,
@@ -45,20 +85,39 @@ export async function exportCsv(
45
85
  return undefined;
46
86
  }
47
87
 
88
+ const baseFileName = nativeOptions.defaultFileName ?? `table_${formatTimestamp(new Date())}`;
89
+
90
+ if (typeof pframe.exportPTable === "function") {
91
+ const { canceled, path } = await dialog.showSaveDialog({
92
+ defaultFileName: `${baseFileName}.csv`,
93
+ filters: NATIVE_EXPORT_FILTERS,
94
+ });
95
+ if (canceled || isNil(path) || !matchesFilterExtension(path, NATIVE_EXPORT_FILTERS)) {
96
+ return undefined;
97
+ }
98
+
99
+ await pframe.exportPTable(nativeOptions.tableHandle, { path, columnIndices });
100
+ return undefined;
101
+ }
102
+
48
103
  const { canceled, path } = await dialog.showSaveDialog({
49
- defaultFileName:
50
- (nativeOptions.defaultFileName ?? `table_${formatTimestamp(new Date())}`) +
51
- `.${nativeOptions.format}.gz`,
104
+ defaultFileName: `${baseFileName}.csv.gz`,
105
+ filters: FALLBACK_EXPORT_FILTERS,
52
106
  });
53
- if (canceled || isNil(path)) {
107
+ if (canceled || isNil(path) || !matchesFilterExtension(path, FALLBACK_EXPORT_FILTERS)) {
108
+ return undefined;
109
+ }
110
+
111
+ const format = tableFormatFromPath(path);
112
+ if (format !== "csv" && format !== "tsv") {
54
113
  return undefined;
55
114
  }
56
115
 
57
116
  return pframe.writePTableToFs(nativeOptions.tableHandle, {
58
117
  path,
59
- format: nativeOptions.format,
118
+ format,
60
119
  columnIndices,
61
- compression: { type: "gzip" },
120
+ ...(path.toLowerCase().endsWith(".gz") && { compression: { type: "gzip" } }),
62
121
  });
63
122
  }
64
123