Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 194 additions & 0 deletions components/multi-file-viewer-uploader/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Multi File Viewer

A Retool custom component for uploading and previewing multiple files, including images, PDFs, video, audio, text, JSON, CSV, and Excel files.

## What `{{ multiFileViewer1 }}` returns

When you reference the component directly in Retool:

```js
{{ multiFileViewer1 }}
```

it returns the component state object, which looks like this shape:

```js
{
pluginType: "DynamicWidget_MultiFileUploaderAndViewer_MultiFileViewer",
heightType: "auto",
files: [],
selectedFile: {
id: "",
name: "",
url: "",
previewUrl: "",
mimeType: "",
label: "",
kind: "unknown"
},
acceptedKind: "",
collectionUuid: "...",
allowMixedFileTypes: true,
id: "multiFileViewer1"
}
```

Depending on uploads and selection, `files` and `selectedFile` will contain real values.

## Recommended Retool usage

### Get the full component object

```js
{{ multiFileViewer1 }}
```

### Get all uploaded files

```js
{{ multiFileViewer1.files }}
```

### Get the currently selected file

```js
{{ multiFileViewer1.selectedFile }}
```

### Get the selected file name

```js
{{ multiFileViewer1.selectedFile.name }}
```

### Get the selected file MIME type

```js
{{ multiFileViewer1.selectedFile.mimeType }}
```

### Get the selected file preview URL

```js
{{ multiFileViewer1.selectedFile.previewUrl }}
```

### Get the selected file kind

```js
{{ multiFileViewer1.selectedFile.kind }}
```

### Check whether mixed file types are enabled

```js
{{ multiFileViewer1.allowMixedFileTypes }}
```

### Get the accepted upload kind for single-type mode

```js
{{ multiFileViewer1.acceptedKind }}
```

## File object structure

Each item inside `multiFileViewer1.files` follows this shape:

```js
{
id: "file-id",
name: "example.pdf",
url: "blob:...",
previewUrl: "blob:...",
mimeType: "application/pdf",
label: "PDF",
kind: "pdf",
objectUrl: "blob:...",
base64: "..."
}
```

## Selected file object structure

`multiFileViewer1.selectedFile` follows this shape:

```js
{
id: "file-id",
name: "example.pdf",
url: "blob:...",
previewUrl: "blob:...",
mimeType: "application/pdf",
label: "PDF",
kind: "pdf"
}
```

## Common examples

### Send the selected file to a query

```js
{{
{
name: multiFileViewer1.selectedFile.name,
type: multiFileViewer1.selectedFile.mimeType,
kind: multiFileViewer1.selectedFile.kind,
previewUrl: multiFileViewer1.selectedFile.previewUrl
}
}}
```

### Send all files to a query

```js
{{ multiFileViewer1.files }}
```

### Get only file names

```js
{{ multiFileViewer1.files.map(file => file.name) }}
```

### Get only base64 values

```js
{{ multiFileViewer1.files.map(file => file.base64) }}
```

### Get the first uploaded file

```js
{{ multiFileViewer1.files[0] }}
```

## Notes

- `files` is an array of uploaded files.
- `selectedFile` is the file currently chosen in the sidebar.
- `acceptedKind` is used when mixed file uploads are turned off.
- `allowMixedFileTypes` is the checkbox-controlled setting for mixed uploads.
- `heightType: "auto"` means the component is configured to work with auto height in Retool.
- `previewUrl` and `url` are usually blob URLs for local uploaded files.

## Best practice

In most Retool queries and transformers, use nested access instead of the whole object when possible.

Good:

```js
{{ multiFileViewer1.selectedFile }}
{{ multiFileViewer1.files }}
{{ multiFileViewer1.allowMixedFileTypes }}
```

Less useful on its own:

```js
{{ multiFileViewer1 }}
```

because that returns the entire component state wrapper, not just the selected file.
Binary file added components/multi-file-viewer-uploader/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions components/multi-file-viewer-uploader/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": "multi-file-viewer",
"title": "Multi File Viewer",
"author": "@widlestudiollp",
"shortDescription": "A responsive Retool custom component for uploading and previewing images, PDFs, spreadsheets, CSV, text, JSON, audio, video, and office files.",
"tags": [
"File Upload",
"File Preview",
"Retool",
"PDF",
"Spreadsheets",
"Media Viewer"
]
}
48 changes: 48 additions & 0 deletions components/multi-file-viewer-uploader/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "my-react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@tryretool/custom-component-support": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"xlsx": "^0.18.5"
},
"engines": {
"node": ">=20.0.0"
},
"scripts": {
"dev": "npx retool-ccl dev",
"deploy": "npx retool-ccl deploy",
"test": "vitest"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react": "^18.2.55",
"@typescript-eslint/eslint-plugin": "^7.3.1",
"@typescript-eslint/parser": "^7.3.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"postcss-modules": "^6.0.0",
"prettier": "^3.0.3",
"vitest": "^4.0.17"
},
"retoolCustomComponentLibraryConfig": {
"name": "MultileFileUploaderAndViewer",
"label": "Multile file uploader and viewer",
"description": "We can view multiple files that we uploaded",
"entryPoint": "src/index.tsx",
"outputPath": "dist"
}
}
Loading
Loading