index.tsx
TLDR
This file contains a React component called Attachment
that represents an attachment block. The Attachment
component has a Display
component for rendering the attachment and an Input
component for selecting and saving attachments. The component also includes a runSlashCommand
function for running a slash command related to attachments.
Classes
Attachment
The Attachment
component represents an attachment block. It includes the following features:
- Name: 'attachment'
- DisplayName: 'Attachment'
- SlashCommand: '/attachment'
- Prefix: ''
- Editable: false
Display
The Display
component is responsible for rendering the attachment. It receives BlockInputProps<FileInfo>
as its props and displays the following:
- A link to the attachment file
- The attachment filename
Input
The Input
component is responsible for selecting and saving attachments. It receives BlockInputProps<FileInfo>
as its props and displays the following:
- An input field of type 'file' for selecting attachments
END
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useRef, useEffect, useState} from 'react'
import {BlockInputProps, ContentType} from '../types'
import octoClient from '../../../../octoClient'
import './attachment.scss'
type FileInfo = {
file: string|File
filename: string
}
const Attachment: ContentType<FileInfo> = {
name: 'attachment',
displayName: 'Attachment',
slashCommand: '/attachment',
prefix: '',
runSlashCommand: (): void => {},
editable: false,
Display: (props: BlockInputProps<FileInfo>) => {
const [fileDataUrl, setFileDataUrl] = useState<string|null>(null)
useEffect(() => {
if (!fileDataUrl) {
const loadFile = async () => {
if (props.value && props.value.file && typeof props.value.file === 'string') {
const fileURL = await octoClient.getFileAsDataUrl(props.currentBoardId || '', props.value.file)
setFileDataUrl(fileURL.url || '')
}
}
loadFile()
}
}, [props.value, props.value.file, props.currentBoardId])
return (
<div
className='AttachmentView'
data-testid='attachment'
>
<a
href={fileDataUrl || '#'}
onClick={(e) => e.stopPropagation()}
download={props.value.filename}
>
{'📎'} {props.value.filename}
</a>
</div>
)
},
Input: (props: BlockInputProps<FileInfo>) => {
const ref = useRef<HTMLInputElement|null>(null)
useEffect(() => {
ref.current?.click()
}, [])
return (
<input
ref={ref}
className='Attachment'
data-testid='attachment-input'
type='file'
onChange={(e) => {
const files = e.currentTarget?.files
if (files) {
for (let i = 0; i < files.length; i++) {
const file = files.item(i)
if (file) {
props.onSave({file, filename: file.name})
}
}
}
}}
/>
)
},
}
Attachment.runSlashCommand = (changeType: (contentType: ContentType<FileInfo>) => void, changeValue: (value: FileInfo) => void): void => {
changeType(Attachment)
changeValue({} as any)
}
export default Attachment