Skip to content

Commit

Permalink
feat(import): add DOCX import and image upload docs
Browse files Browse the repository at this point in the history
  • Loading branch information
nperez0111 committed Dec 20, 2024
1 parent 7d9c3e7 commit d5a468a
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 11 deletions.
156 changes: 149 additions & 7 deletions src/content/collaboration/documents/conversion.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ meta:
description: Use Tiptap to convert documents from docx, odt or markdown to Tiptap
category: Collaboration
---

import { CodeDemo } from '@/components/CodeDemo'
import { Callout } from '@/components/ui/Callout'

<Callout title="Beta" variant="hint">
This feature is currently in beta and available to all users with a Tiptap account.
This feature is currently in beta and available to all users with a Tiptap account.
</Callout>

The document conversion API supports DOCX, ODT, and Markdown conversion from and to Tiptap’s JSON format.
Expand All @@ -18,7 +19,6 @@ The following demo uses the Document Conversion API by integrating both the [imp

<CodeDemo isPro path="/Extensions/ImportExport" />


<Callout title="Review the postman collection" variant="hint">
You can also experiment with the Document Conversion API by heading over to our [Postman
Collection](https://www.postman.com/docking-module-explorer-14290287/workspace/tiptap-collaboration-public/collection/33042171-cc186a66-df41-4df8-9c6e-e91b20deffe5?action=share&creator=32651125).
Expand All @@ -34,10 +34,61 @@ Instead of using the Document Conversion API directly, you can use Tiptap Editor

## /import endpoint

The /import endpoint enables the conversion of `docx`, `odt`, or `markdown` files into Tiptap’s JSON format. Users can POST documents to this endpoint and use various parameters to customize how different document elements are handled during the conversion process.
The `/import` endpoint enables the conversion of `docx`, `odt`, or `markdown` files into Tiptap’s JSON format. Users can POST documents to this endpoint and use various parameters to customize how different document elements are handled during the conversion process.

- **Method**: `POST`

### Required headers

| Name | Description |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `Authorization` | The JWT token to authenticate the request. Example: `Bearer your-jwt-token` |
| `X-App-Id` | The Convert App-ID from the Collaboration settings page: [https://cloud.tiptap.dev/convert-settings](https://cloud.tiptap.dev/convert-settings) |

### Body

| Name | Type | Description |
| ------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `file` | `File` | The file to convert |
| `imageUploadCallbackUrl` | `string` | The callback endpoint to upload images that were encountered within the uploaded document, [see more info](#image-uploading) |

### Query parameters

Specify how source document elements are mapped to ProseMirror nodes or marks, and adjust the conversion to meet your specific styling and structural preferences.

| Name | Default | Description |
| ---------------- | ---------------- | -------------------------------------------------------------------- |
| `paragraph` | `paragraph` | Defines which prosemirror type is used for paragraph conversion |
| `heading` | `heading` | Defines which prosemirror type is used for heading conversion |
| `blockquote` | `blockquote` | Defines which prosemirror type is used for blockquote conversion |
| `codeblock` | `codeblock` | Defines which prosemirror type is used for codeblock conversion |
| `bulletlist` | `bulletlist` | Defines which prosemirror type is used for bulletList conversion |
| `orderedlist` | `orderedlist` | Defines which prosemirror type is used for orderedList conversion |
| `listitem` | `listitem` | Defines which prosemirror type is used for listItem conversion |
| `hardbreak` | `hardbreak` | Defines which prosemirror type is used for hardbreak conversion |
| `horizontalrule` | `horizontalrule` | Defines which prosemirror type is used for horizontalRule conversion |
| `table` | `table` | Defines which prosemirror type is used for table conversion |
| `tablecell` | `tablecell` | Defines which prosemirror type is used for tableCell conversion |
| `tableheader` | `tableheader` | Defines which prosemirror type is used for tableHeader conversion |
| `tablerow` | `tablerow` | Defines which prosemirror type is used for tableRow conversion |
| `bold` | `bold` | Defines which prosemirror mark is used for bold conversion |
| `italic` | `italic` | Defines which prosemirror mark is used for italic conversion |
| `underline` | `underline` | Defines which prosemirror mark is used for underline conversion |
| `strikethrough` | `strike` | Defines which prosemirror mark is used for strikethrough conversion |
| `link` | `link` | Defines which prosemirror mark is used for link conversion |
| `code` | `code` | Defines which prosemirror mark is used for code conversion |
| `image` | `image` | Defines which prosemirror mark is used for image conversion |

## /import-docx endpoint (experimental)

The `/import-docx` endpoint enables the conversion of `docx` files into Tiptap’s JSON format. Users can POST documents to this endpoint and use various parameters to customize how different document elements are handled during the conversion process.

- **Method**: `POST`

<Callout title="Alpha" variant="hint">
This feature is currently in alpha and available to all users with a Tiptap account.
</Callout>

### Required headers

| Name | Description |
Expand All @@ -47,9 +98,10 @@ The /import endpoint enables the conversion of `docx`, `odt`, or `markdown` file

### Body

| Name | Type | Description |
| ------ | ------ | ------------------- |
| `file` | `File` | The file to convert |
| Name | Type | Description |
| ------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `file` | `File` | The file to convert |
| `imageUploadCallbackUrl` | `string` | The callback endpoint to upload images that were encountered within the uploaded document, [see more info](#image-uploading) |

### Query parameters

Expand All @@ -76,10 +128,11 @@ Specify how source document elements are mapped to ProseMirror nodes or marks, a
| `strikethrough` | `strike` | Defines which prosemirror mark is used for strikethrough conversion |
| `link` | `link` | Defines which prosemirror mark is used for link conversion |
| `code` | `code` | Defines which prosemirror mark is used for code conversion |
| `image` | `image` | Defines which prosemirror mark is used for image conversion |

## /export endpoint

The /export endpoint converts Tiptap documents back into formats like `docx`, `odt`, or `markdown`.
The `/export` endpoint converts Tiptap documents back into formats like `docx`, `odt`, or `markdown`.

- **Method**: `POST`

Expand Down Expand Up @@ -123,3 +176,92 @@ Convert a Tiptap document to a different format.
| `strikethrough` | `strike` | Defines which prosemirror mark is used for strikethrough conversion |
| `link` | `link` | Defines which prosemirror mark is used for link conversion |
| `code` | `code` | Defines which prosemirror mark is used for code conversion |

## Image Uploading

<Callout title="Note" variant="info">
Tiptap does not provide an image upload service. You will need to implement your own server to
handle image uploads.
</Callout>

When converting documents, some formats may include images that you may want to preserve in the converted document. To do this, you can provide the optional `imageUploadCallbackUrl` parameter in the request body. This parameter should be a URL that the Convert service can use to upload images found in the document.

The Convert service will make a `POST` request to the provided URL with the image file as the request body. The response should be a JSON object with a `url` key containing the URL where the image was uploaded.

### Tips

- The image upload callback URL should be a publicly accessible endpoint.
- The image upload callback URL should return a JSON object with a `url` key containing the URL where the image was uploaded.
- You can use any callback URL, so if you want to limit uploads, you can provide a URL that includes an API key or other authentication method.
- The URL you provide, will be written into the document as the image source, so make sure it is accessible to anyone who will view the document.

### Server Implementation Example

This example shows a simple server implementation that accepts image uploads & uploads them to an S3 bucket configured by environment variables.

```ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import { Upload } from '@aws-sdk/lib-storage'
import { S3Client } from '@aws-sdk/client-s3'

const {
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
AWS_REGION,
AWS_S3_BUCKET,
PORT = '3011',
AWS_ENDPOINT,
AWS_FORCE_STYLE,
} = process.env

if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY || !AWS_S3_BUCKET) {
console.error('Please provide AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_S3_BUCKET')
process.exit(1)
}

const s3 = new S3Client({
credentials: {
accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY,
},

region: AWS_REGION,
endpoint: AWS_ENDPOINT,
forcePathStyle: AWS_FORCE_STYLE === 'true',
})

const app = new Hono() as Hono<any>

app.post('/upload', async (c) => {
const body = await c.req.parseBody()
const file = body['file']

if (!file || typeof file === 'string') {
return c.json({ error: 'No file uploaded' }, 400)
}

try {
const data = await new Upload({
client: s3,
params: {
Bucket: AWS_S3_BUCKET,
// file.name is just current timestamp & file extension
Key: file.name,
Body: file,
ContentType: file.type,
},
}).done()

return c.json({ url: data.Location })
} catch (error) {
console.error(error)
return c.json({ error: 'Failed to upload file' }, 500)
}
})

serve({
fetch: app.fetch,
port: Number(PORT) || 3000,
})
```
17 changes: 13 additions & 4 deletions src/content/editor/extensions/functionality/import.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ const editor = new Editor({

// The JWT token you generated in the previous step
token: 'your-jwt',

// The URL to upload images to, if not provided, images will be stripped from the document
imageUploadCallbackUrl: 'https://your-image-upload-url.com',

// Enables the experimental DOCX import which should better preserve content styling
experimentalDocxImport: true,
}),
],
})
Expand Down Expand Up @@ -158,10 +164,12 @@ editor

## Options

| Name | Type | Default | Description |
| ------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `appId` | `string` | `undefined` | The convert app ID from the Convert settings page: [https://cloud.tiptap.dev/convert-settings](https://cloud.tiptap.dev/convert-settings) |
| `token` | `string` | `undefined` | The JWT token generated from your server via secret |
| Name | Type | Default | Description |
| ------------------------ | ---------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `appId` | `string` | `undefined` | The convert app ID from the Convert settings page: [https://cloud.tiptap.dev/convert-settings](https://cloud.tiptap.dev/convert-settings) |
| `token` | `string` | `undefined` | The JWT token generated from your server via secret |
| `imageUploadCallbackUrl` | `string` | `undefined` | The URL to upload images to, if not provided, images will be stripped from the document, [see more info](/collaboration/documents/conversion#image-uploading) |
| `experimentalDocxImport` | `boolean ` | `false` | Enables the experimental DOCX import which should better preserve content styling (experimental, and this API may not be completely stable while in alpha), only applies to DOCX files uploaded |

## Commands

Expand Down Expand Up @@ -189,6 +197,7 @@ editor

## Caveats and limitations

- **Image upload** - Images are assumed to be inline within the document so, your editor should be setup with `Image.configure({ inline: true })` to display them correctly, otherwise they will be stripped from the document
- **Unsupported docx elements on import** - Importing docx files currently does not support page breaks, page headers and footers, horizontal rules or text styles
- **Content added via suggestion mode** - Content added via suggestion mode is not included in the imported prosemirror document
- **PDF import & export** - Importing and PDF files is not yet supported
Expand Down

0 comments on commit d5a468a

Please sign in to comment.