mobile: export table to csv

This commit is contained in:
Ammar Ahmed
2026-01-15 13:21:33 +05:00
committed by Abdullah Atta
parent 2cf7f0cc27
commit ee139463d2
9 changed files with 92 additions and 1858 deletions

View File

@@ -28,11 +28,13 @@ import { getDefaultPresets } from "@notesnook/editor/dist/cjs/toolbar/tool-defin
import { strings } from "@notesnook/intl";
import Clipboard from "@react-native-clipboard/clipboard";
import React, { useCallback, useEffect, useRef } from "react";
import * as ScopedStorage from "react-native-scoped-storage";
import {
BackHandler,
Keyboard,
KeyboardEventListener,
NativeEventSubscription,
Platform,
useWindowDimensions
} from "react-native";
import { WebViewMessageEvent } from "react-native-webview";
@@ -82,6 +84,9 @@ import { useDragState } from "../../settings/editor/state";
import { EditorMessage, EditorProps, useEditorType } from "./types";
import { useTabStore } from "./use-tab-store";
import { editorState, openInternalLink } from "./utils";
import filesystem from "../../../common/filesystem";
import ReactNativeBlobUtil from "react-native-blob-util";
import { ShareComponent } from "../../../components/sheets/export-notes/share";
const publishNote = async () => {
const user = useUserStore.getState().user;
@@ -153,7 +158,9 @@ export const useEditorEvents = (
const features = useAreFeaturesAvailable([
"callout",
"outlineList",
"taskList"
"taskList",
"importCsvToTable",
"exportTableAsCsv"
]);
const deviceMode = useSettingStore((state) => state.deviceMode);
const fullscreen = useSettingStore((state) => state.fullscreen);
@@ -740,6 +747,62 @@ export const useEditorEvents = (
}
break;
}
case EditorEvents.downloadCsv: {
try {
const csv = editorMessage.value;
let filePath: string;
let fileName: string;
if (Platform.OS === "android") {
let file = await ScopedStorage.createDocument(
"table.csv",
"text/csv",
csv,
"utf8"
);
if (!file) return;
filePath = file.path || file.uri;
fileName = file.name;
} else {
const path = await filesystem.checkAndCreateDir("/");
let possibleFileName = "table.csv";
let counter = 1;
// Check if file exists and find available filename
while (
await ReactNativeBlobUtil.fs.exists(path + possibleFileName)
) {
possibleFileName = `table (${counter}).csv`;
counter++;
}
await ReactNativeBlobUtil.fs.writeFile(
path + possibleFileName,
csv,
"utf8"
);
filePath = path + possibleFileName;
fileName = possibleFileName;
}
await sleep(500);
presentSheet({
title: "Table saved to csv",
paragraph: strings.fileSaved(fileName, Platform.OS),
icon: "download",
context: "global",
component: (
<ShareComponent uri={filePath} name={fileName} padding={12} />
)
});
} catch (e) {
ToastManager.show({
type: "info",
message: "Could not save table to csv"
});
DatabaseLogger.error(e as Error);
}
break;
}
default:
break;

View File

@@ -331,9 +331,11 @@
"colord": "^2.9.3",
"detect-indent": "^7.0.1",
"entities": "5.0.0",
"file-saver": "^2.0.5",
"katex": "0.16.11",
"linkifyjs": "^4.1.3",
"nanoid": "5.0.7",
"papaparse": "^5.5.3",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "1.34.2",
@@ -350,7 +352,9 @@
"@mdi/js": "7.4.47",
"@theme-ui/components": "0.16.1",
"@theme-ui/core": "0.16.1",
"@types/file-saver": "^2.0.7",
"@types/katex": "0.16.7",
"@types/papaparse": "^5.5.2",
"@types/prismjs": "1.26.4",
"@types/react": "18.3.5",
"@types/react-color": "^3.0.12",

View File

@@ -99,9 +99,11 @@
"colord": "^2.9.3",
"detect-indent": "^7.0.1",
"entities": "5.0.0",
"file-saver": "^2.0.5",
"katex": "0.16.11",
"linkifyjs": "^4.1.3",
"nanoid": "5.0.7",
"papaparse": "^5.5.3",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "1.34.2",
@@ -118,7 +120,9 @@
"@mdi/js": "7.4.47",
"@theme-ui/components": "0.16.1",
"@theme-ui/core": "0.16.1",
"@types/file-saver": "^2.0.7",
"@types/katex": "0.16.7",
"@types/papaparse": "^5.5.2",
"@types/prismjs": "1.26.4",
"@types/react": "18.3.5",
"@types/react-color": "^3.0.12",

View File

@@ -114,6 +114,8 @@ const Tiptap = ({
callout: !!settings.features?.callout?.isAllowed,
outlineList: !!settings.features?.outlineList?.isAllowed,
taskList: !!settings.features?.taskList?.isAllowed,
importCsvToTable: !!settings.features?.importCsvToTable?.isAllowed,
exportTableAsCsv: !!settings.features?.exportTableAsCsv?.isAllowed,
insertAttachment: settings.loggedIn
},
onPermissionDenied: (claim) => {
@@ -165,6 +167,10 @@ const Tiptap = ({
attributes
});
},
downloadCsvTable: (csv) => {
console.log("download csv");
post("editor-events:download-csv", csv);
},
element: getContentDiv(),
editable: !tab.session?.readonly,
editorProps: {

View File

@@ -54,5 +54,6 @@ export const EditorEvents = {
goBack: "editor-events:go-back",
goForward: "editor-events:go-forward",
saveScroll: "editor-events:save-scroll",
newNote: "editor-events:new-note"
newNote: "editor-events:new-note",
downloadCsv: "editor-events:download-csv"
} as const;

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@ import { selectedRect, TableRect } from "./prosemirror-tables/commands.js";
import { saveAs } from "file-saver";
import { unparse, parse } from "papaparse";
import { hasPermission } from "../../types.js";
import { useToolbarStore } from "../../toolbar/stores/toolbar-store.js";
type TableCell = {
cell: Node;
@@ -244,8 +245,12 @@ function exportToCSV(editor?: Editor) {
node.forEach((cell) => row.push(cell.textContent));
rows.push(row);
});
saveAs(new Blob([new TextEncoder().encode(unparse(rows))]), "table.csv");
const csv = unparse(rows);
if (useToolbarStore.getState().isMobile) {
editor.storage.downloadCsvTable?.(csv);
} else {
saveAs(new Blob([new TextEncoder().encode(csv)]), "table.csv");
}
}
export {

View File

@@ -98,6 +98,7 @@ interface TiptapStorage {
openAttachmentPicker?: (type: AttachmentType) => void;
previewAttachment?: (attachment: Attachment) => void;
copyToClipboard?: (text: string, html?: string) => void;
downloadCsvTable?: (csv: string) => void;
createInternalLink?: (
attributes?: LinkAttributes
) => Promise<LinkAttributes | undefined>;
@@ -152,7 +153,7 @@ const useTiptap = (
dayFormat,
copyToClipboard,
createInternalLink,
downloadCsvTable,
doubleSpacedLines = true,
isMobile,
downloadOptions,
@@ -386,6 +387,7 @@ const useTiptap = (
editor.storage.copyToClipboard = copyToClipboard;
editor.storage.createInternalLink = createInternalLink;
editor.storage.getAttachmentData = getAttachmentData;
editor.storage.downloadCsvTable = downloadCsvTable;
if (onBeforeCreate) onBeforeCreate({ editor });
},

View File

@@ -62,7 +62,8 @@ export function TableSettings(props: ToolProps) {
"rowProperties",
"deleteRow",
"deleteColumn",
"deleteTable"
"deleteTable",
"exportToCSV"
]}
/>
);