Skip to content

Commit f1bc0da

Browse files
authored
Merge pull request #355 from lyjeileen/main
fix: send headers for file download
2 parents c3253cb + 8bc1d1b commit f1bc0da

File tree

5 files changed

+75
-29
lines changed

5 files changed

+75
-29
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rustic-ai/ui-components",
3-
"version": "0.0.41",
3+
"version": "0.0.42",
44
"keywords": [
55
"rustic-ai",
66
"conversational-ui"

src/components/multipart/chatCompletion/chatCompletion.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import '../../../index.css'
22
import '../multipart/multipart.css'
33

44
import Box from '@mui/material/Box'
5-
import IconButton from '@mui/material/IconButton'
6-
import Tooltip from '@mui/material/Tooltip'
75
import Typography from '@mui/material/Typography'
86
import React from 'react'
97

108
import FilePreview from '../../filePreview/filePreview'
11-
import Icon from '../../icon'
129
import MarkedMarkdown from '../../markdown'
1310
import type { ChatCompletionProps, Content } from '../../types'
11+
import DownloadButton from '../downloadButton'
1412

1513
function getFileName(fileUrl: string): string {
1614
const url = new URL(fileUrl)
@@ -51,16 +49,11 @@ export default function ChatCompletion(props: ChatCompletionProps) {
5149
getAuthHeaders={props.getAuthHeaders}
5250
>
5351
{file.url && (
54-
<Tooltip title="Download" className="rustic-shift-to-right-by-8">
55-
<IconButton
56-
component="a"
57-
href={file.url}
58-
download={file.name}
59-
data-cy="download-button"
60-
>
61-
<Icon name="download" />
62-
</IconButton>
63-
</Tooltip>
52+
<DownloadButton
53+
url={file.url}
54+
fileName={file.name}
55+
getAuthHeaders={props.getAuthHeaders}
56+
/>
6457
)}
6558
</FilePreview>
6659
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import IconButton from '@mui/material/IconButton'
2+
import Tooltip from '@mui/material/Tooltip'
3+
import React from 'react'
4+
5+
import Icon from '../icon/icon'
6+
import type { GetAuthHeaders } from '../types'
7+
8+
type DownloadButtonProps = {
9+
url: string
10+
fileName: string
11+
getAuthHeaders?: GetAuthHeaders
12+
}
13+
14+
export default function DownloadButton(props: DownloadButtonProps) {
15+
function handleAuthenticatedDownload(getHeadersFn: GetAuthHeaders) {
16+
getHeadersFn()
17+
.then((headersObj) => {
18+
return fetch(props.url, { ...headersObj })
19+
})
20+
.then((response) => {
21+
return response.blob()
22+
})
23+
.then((blob) => {
24+
const downloadUrl = window.URL.createObjectURL(blob)
25+
const temporaryLink = document.createElement('a')
26+
temporaryLink.href = downloadUrl
27+
temporaryLink.download = props.fileName
28+
document.body.appendChild(temporaryLink)
29+
temporaryLink.click()
30+
31+
document.body.removeChild(temporaryLink)
32+
window.URL.revokeObjectURL(downloadUrl)
33+
})
34+
.catch((error) => {
35+
throw new Error('Error downloading file. ' + error.message)
36+
})
37+
}
38+
39+
return (
40+
<Tooltip title="Download" className="rustic-shift-to-right-by-8">
41+
{props.getAuthHeaders ? (
42+
<IconButton
43+
onClick={() => handleAuthenticatedDownload(props.getAuthHeaders!)}
44+
data-cy="download-button"
45+
>
46+
<Icon name="download" />
47+
</IconButton>
48+
) : (
49+
<IconButton
50+
component="a"
51+
href={props.url}
52+
download={props.fileName}
53+
data-cy="download-button"
54+
>
55+
<Icon name="download" />
56+
</IconButton>
57+
)}
58+
</Tooltip>
59+
)
60+
}

src/components/multipart/multipart/multipart.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import '../../../index.css'
22
import './multipart.css'
33

4-
import IconButton from '@mui/material/IconButton'
5-
import Tooltip from '@mui/material/Tooltip'
64
import Typography from '@mui/material/Typography'
75
import Box from '@mui/system/Box'
86
import React from 'react'
97

108
import FilePreview from '../../filePreview/filePreview'
11-
import Icon from '../../icon/icon'
129
import MarkedMarkdown from '../../markdown'
1310
import type { MultipartProps } from '../../types'
11+
import DownloadButton from '../downloadButton'
1412

1513
/** The `Multipart` component is a versatile message format designed to accommodate both textual content and file attachments within a single message interface. */
1614
export default function Multipart(props: MultipartProps) {
@@ -24,16 +22,11 @@ export default function Multipart(props: MultipartProps) {
2422
key={index}
2523
>
2624
{file.url && (
27-
<Tooltip title="Download" className="rustic-shift-to-right-by-8">
28-
<IconButton
29-
component="a"
30-
href={file.url}
31-
download={file.name}
32-
data-cy="download-button"
33-
>
34-
<Icon name="download" />
35-
</IconButton>
36-
</Tooltip>
25+
<DownloadButton
26+
url={file.url}
27+
fileName={file.name}
28+
getAuthHeaders={props.getAuthHeaders}
29+
/>
3730
)}
3831
</FilePreview>
3932
)

0 commit comments

Comments
 (0)