thru-mft-webcomponents
v0.1.17
Published
A collection of web components for file upload functionality, built with Preact and TypeScript. These components provide a robust, resumable file upload experience with progress tracking, error handling, and more.
Readme
Thru MFT Web Components
A collection of web components for file upload functionality, built with Preact and TypeScript. These components provide a robust, resumable file upload experience with progress tracking, error handling, and more.
Features
- Resumable File Uploads: Automatically resume interrupted uploads
- Chunked File Transfers: Files are split into chunks for efficient uploading
- Progress Tracking: Real-time upload progress with speed and time estimations
- Drag-and-Drop Support: User-friendly file selection interface
- Conflict Resolution: Handles file conflicts with options to resume or overwrite
- Auto-Upload: Configure whether uploads start automatically
- Error Handling: Comprehensive error reporting and recovery options
- Upload Cancellation: Ability to cancel uploads in progress
- Upload Interceptor: Modify upload context before an upload begins
- Multiple File Uploads: Support for uploading multiple files simultaneously
- Server Path Selection: Choose from available server paths or automatically use the first one
- Customizable Retry Logic: Configure retry attempts and delays for failed uploads
Installation
CDN Usage
Add the following to your HTML:
<script type="module" src="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css" />NPM Installation
npm install thru-mft-webcomponents
# or
yarn add thru-mft-webcomponents
# or
pnpm add thru-mft-webcomponentsUsage
Thru Upload Web Component
The thru-upload web component provides resumable file upload functionality with progress tracking and error handling.
<thru-upload
api-key="your-api-key"
flow-endpoint-id="123"
api-url="https://your-api-url.com/api"
auto-upload="true"
assume-first-server-path="false"
min-retry-delay="1000"
retry-attempts="3"
></thru-upload>Attributes
| Attribute | Type | Required | Default | Description |
| -------------------------- | ------- | -------- | ------- | ------------------------------------------------------------- |
| api-key | string | Yes | - | Your API key for authentication |
| flow-endpoint-id | number | Yes | - | ID of the flow endpoint to upload to |
| api-url | string | Yes | - | Base URL of your API |
| auto-upload | boolean | No | true | Whether to start upload automatically when files are selected |
| assume-first-server-path | boolean | No | false | Whether to automatically use the first available server path |
| min-retry-delay | number | No | - | Minimum delay between retry attempts in milliseconds |
| retry-attempts | number | No | - | Maximum number of retry attempts for failed uploads |
Events
The component dispatches the following custom events:
thru-upload-completed: Fired when an upload is completed successfullywindow.addEventListener("thru-upload-completed", (e) => { console.log(e.detail) // Contains upload details including id and uploadContext })upload-files-added: Fired when files are added to the upload queuewindow.addEventListener("upload-files-added", (e) => { console.log(e.detail.files) // Contains file details })
Methods
The component exposes the following methods:
triggerUploads(): Manually trigger the upload of selected filesconst uploadedFiles = await document.querySelector("thru-upload").triggerUploads()
Upload Interceptor
You can add an upload interceptor to modify the upload context before the upload begins:
const thruUploadElement = document.querySelector("thru-upload")
thruUploadElement.uploadInterceptor = async (context) => {
// Modify context as needed
context.filePath = "custom/path"
return context
}Resume Upload Logic
The component automatically handles resuming uploads in case of interruptions:
- Upload sessions are saved in localStorage with key
upload-session-{flowEndpointId}-{fileName}-{fileSize} - When the component is initialized, it checks for existing upload sessions
- For incomplete uploads, it presents options to resume or restart the upload
- When resuming, it retrieves the last uploaded chunk from the server and continues from there
Upload Lifecycle
The upload process follows these states:
- Initial: Upload is being prepared
- Waiting: Ready to start upload
- In-progress: Upload is ongoing, showing progress, speed, and time remaining
- Assembling: All chunks uploaded, server is assembling the file
- Completed: Upload successfully completed
- Error: Error occurred during upload (with retry option)
FileUpload Component (React/Preact)
The FileUpload component provides a resumable file upload functionality with progress tracking and error handling.
import { FileUpload } from "thru-mft-webcomponents"
// In your component:
<FileUpload
id="unique-upload-id"
fileToUpload={file}
abortController={new AbortController()}
initialUploadContext={{
flowEndpointId: number,
serverPath: string,
fileName: string,
fileSize: number,
filePath: string
}}
updateState={(updatedFile) => {
// Handle state updates
}}
autoUpload={true}
retryDelayMs={1000} // Optional
retryAttempts={3} // Optional
/>Props
| Prop | Type | Required | Description |
| ---------------------- | ---------------------- | -------- | -------------------------------------------- |
| id | string | Yes | Unique identifier for the upload |
| fileToUpload | File | Yes | The file to be uploaded |
| abortController | AbortController | Yes | Controller for handling upload cancellation |
| initialUploadContext | ResumableUploadContext | Yes | Initial context for the upload |
| updateState | (file: any) => void | Yes | Callback for state updates |
| autoUpload | boolean | Yes | Whether to start upload automatically |
| retryDelayMs | number | No | Delay between retry attempts in milliseconds |
| retryAttempts | number | No | Maximum number of retry attempts |
UploadModal Component (React/Preact)
The UploadModal component provides a modal interface for file uploads with drag-and-drop support.
import { UploadModal } from "thru-mft-webcomponents"
// In your component:
<UploadModal
selectedFlowEndpointId={123}
flowEnabled={true}
getUploadInterceptor={() => {
// Return your interceptor function
}}
autoUpload={true}
assumeFirstServerPath={true}
retryDelayMs={1000} // Optional
retryAttempts={3} // Optional
/>Props
| Prop | Type | Required | Description |
| ------------------------ | -------------- | -------- | -------------------------------------------- |
| selectedFlowEndpointId | number | Yes | ID of the selected flow endpoint |
| flowEnabled | boolean | Yes | Whether the flow is enabled |
| getUploadInterceptor | () => Function | Yes | Function to get the upload interceptor |
| autoUpload | boolean | Yes | Whether to start upload automatically |
| assumeFirstServerPath | boolean | Yes | Whether to assume the first server path |
| retryDelayMs | number | No | Delay between retry attempts in milliseconds |
| retryAttempts | number | No | Maximum number of retry attempts |
Implementation Guide
Basic HTML Implementation
- Add the required scripts and styles to your HTML page:
<script type="module" src="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css" />- Add the web component to your HTML:
<thru-upload
api-key="your-api-key"
flow-endpoint-id="123"
api-url="https://your-api-url.com/api"
></thru-upload>- Optionally, add event listeners for upload events:
document.addEventListener("DOMContentLoaded", () => {
window.addEventListener("thru-upload-completed", (e) => {
console.log("Upload completed:", e.detail)
})
})Advanced Usage
Triggering Uploads Manually
If you set auto-upload="false", you'll need to trigger uploads manually:
// Get the upload component
const uploadComponent = document.querySelector("thru-upload")
// Trigger uploads when a button is clicked
document.querySelector("#upload-button").addEventListener("click", async () => {
const results = await uploadComponent.triggerUploads()
console.log("Upload results:", results)
})Custom Upload Interception
Implement an upload interceptor to modify upload context:
const uploadComponent = document.querySelector("thru-upload")
uploadComponent.uploadInterceptor = async (context) => {
// Add metadata or modify paths
context.filePath = `user_${userId}/${context.filePath}`
// You can make API calls here if needed
const additionalData = await fetchUserUploadPreferences()
// Return the modified context
return {
...context,
...additionalData
}
}React/Next.js Integration
When using with React or Next.js:
import { useEffect, useRef } from "react"
// Load the web component scripts
useEffect(() => {
const script = document.createElement("script")
script.src = "https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"
script.type = "module"
document.head.appendChild(script)
const link = document.createElement("link")
link.rel = "stylesheet"
link.href = "https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css"
document.head.appendChild(link)
return () => {
document.head.removeChild(script)
document.head.removeChild(link)
}
}, [])
// Component that uses the web component
const FileUploader = ({ apiKey, flowEndpointId, apiUrl }) => {
const uploadRef = useRef(null)
useEffect(() => {
if (uploadRef.current) {
// Set up interceptor
uploadRef.current.uploadInterceptor = (context) => {
// Modify context
return context
}
// Listen for completion events
const handleUploadComplete = (e) => {
console.log("Upload completed:", e.detail)
}
window.addEventListener("thru-upload-completed", handleUploadComplete)
return () => {
window.removeEventListener("thru-upload-completed", handleUploadComplete)
}
}
}, [uploadRef.current])
return (
<div>
<thru-upload
ref={uploadRef}
api-key={apiKey}
flow-endpoint-id={flowEndpointId}
api-url={apiUrl}
auto-upload="true"
></thru-upload>
<button onClick={() => uploadRef.current?.triggerUploads()}>
Upload Files
</button>
</div>
)
}Technical Details
ResumableUploadContext
The upload context contains all the information needed for the upload:
type ResumableUploadContext = {
flowCode: string
endpointCode: string
flowEndpointId: number
serverPath: string
fileName: string
filePath: string
fileSize: number
lastUploadedChunkIndex?: number
sessionUID?: string
reportId?: string
chunkSize?: number
outcome?: {
success: boolean
error?: any
}
}Chunked Upload Process
Files are uploaded in chunks of 100MB by default:
const CHUNK_SIZE = 100 * 1024 * 1024 // 100MBThe upload process:
- Create an upload session
- Upload chunks sequentially
- Track upload progress
- Commit the session when all chunks are uploaded
- Handle errors and allow retries
CSS Customization
The component uses CSS variables for styling that can be overridden:
:root {
--primary-color: #4051a5;
--primary-color-bg: rgba(64, 81, 165, 0.1);
--primary-color-dark: #062491;
--off-theme-color: #415362;
--off-theme-color-accent: #5f778a;
--error-color: #d93025;
--theme-delete-color: #d93025;
--loader-color-bg: #e6e6e6;
}