-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add object actions - presigned URL, download and preview #1604
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,50 +4,19 @@ import { K8sResourceKind } from '@odf/shared/types'; | |
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook'; | ||
import { ResourceStatus } from '@openshift-console/dynamic-plugin-sdk'; | ||
import Status from '@openshift-console/dynamic-plugin-sdk/lib/app/components/status/Status'; | ||
import useSWR from 'swr'; | ||
import { Skeleton, Label, Button, ButtonVariant } from '@patternfly/react-core'; | ||
import { Label, Button, ButtonVariant } from '@patternfly/react-core'; | ||
import { CopyIcon } from '@patternfly/react-icons'; | ||
import { LIST_BUCKET } from '../../../constants'; | ||
import { getPath } from '../../../utils'; | ||
import { NoobaaS3Context } from '../noobaa-context'; | ||
import './bucket-overview.scss'; | ||
|
||
type TitleProps = { | ||
bucketName: string; | ||
foldersPath: string; | ||
currentFolder: string; | ||
fresh: boolean; | ||
isCreatedByOBC: boolean; | ||
noobaaObjectBucket: K8sResourceKind; | ||
}; | ||
|
||
const CreatedOnSkeleton: React.FC<{}> = () => ( | ||
<Skeleton width="25%" height="15%" /> | ||
); | ||
|
||
const CreatedOn: React.FC<{ bucketName: string }> = ({ bucketName }) => { | ||
const { t } = useCustomTranslation(); | ||
|
||
const { noobaaS3 } = React.useContext(NoobaaS3Context); | ||
const { data, error, isLoading } = useSWR(LIST_BUCKET, () => | ||
noobaaS3.listBuckets() | ||
); | ||
|
||
const bucketCreatedOn = | ||
!isLoading && !error | ||
? data?.Buckets?.find((bucket) => bucket?.Name === bucketName) | ||
?.CreationDate | ||
: null; | ||
|
||
return isLoading ? ( | ||
<CreatedOnSkeleton /> | ||
) : ( | ||
<h4 className="text-muted"> | ||
{t('Created on: ') + bucketCreatedOn?.toString()} | ||
</h4> | ||
); | ||
}; | ||
|
||
Comment on lines
-24
to
-50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can not be determined that easily, decided to remove it instead... |
||
const BucketResourceStatus: React.FC<{ resourceStatus: string }> = ({ | ||
resourceStatus, | ||
}) => ( | ||
|
@@ -60,7 +29,6 @@ export const PageTitle: React.FC<TitleProps> = ({ | |
bucketName, | ||
foldersPath, | ||
currentFolder, | ||
fresh, | ||
isCreatedByOBC, | ||
noobaaObjectBucket, | ||
}) => { | ||
|
@@ -99,8 +67,6 @@ export const PageTitle: React.FC<TitleProps> = ({ | |
</> | ||
)} | ||
</div> | ||
{!foldersPath && | ||
(fresh ? <CreatedOn bucketName={bucketName} /> : <CreatedOnSkeleton />)} | ||
<h4> | ||
{t('Object path: ')} | ||
<span className="text-muted">{objectPath}</span> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { GetObjectCommandOutput } from '@aws-sdk/client-s3'; | ||
import { S3Commands } from '@odf/shared/s3'; | ||
import { getName } from '@odf/shared/selectors'; | ||
import { ObjectCrFormat } from '../../../types'; | ||
|
||
type DownloadAndPreviewFunction = ( | ||
bucketName: string, | ||
object: ObjectCrFormat, | ||
noobaaS3: S3Commands, | ||
setDownloadAndPreview: React.Dispatch< | ||
React.SetStateAction<DownloadAndPreviewState> | ||
> | ||
) => void; | ||
|
||
type GetObjectURL = ( | ||
bucketName: string, | ||
object: ObjectCrFormat, | ||
noobaaS3: S3Commands | ||
) => Promise<string>; | ||
|
||
export type DownloadAndPreviewState = { | ||
isDownloading: boolean; | ||
isPreviewing: boolean; | ||
}; | ||
|
||
const getObjectURL: GetObjectURL = async (bucketName, object, noobaaS3) => { | ||
const responseStream: GetObjectCommandOutput = await noobaaS3.getObject({ | ||
Bucket: bucketName, | ||
Key: getName(object), | ||
}); | ||
const blob = await new Response(responseStream.Body as ReadableStream).blob(); | ||
|
||
return window.URL.createObjectURL(blob); | ||
}; | ||
|
||
export const onDownload: DownloadAndPreviewFunction = async ( | ||
bucketName, | ||
object, | ||
noobaaS3, | ||
setDownloadAndPreview | ||
) => { | ||
try { | ||
setDownloadAndPreview((downloadAndPreview) => ({ | ||
...downloadAndPreview, | ||
isDownloading: true, | ||
})); | ||
|
||
const objectURL = await getObjectURL(bucketName, object, noobaaS3); | ||
|
||
// create a download element and trigger download | ||
const downloadLink = document.createElement('a'); | ||
downloadLink.href = objectURL; | ||
downloadLink.download = getName(object); | ||
document.body.appendChild(downloadLink); | ||
downloadLink.click(); | ||
document.body.removeChild(downloadLink); | ||
|
||
window.URL.revokeObjectURL(objectURL); | ||
} catch (err) { | ||
// eslint-disable-next-line no-console | ||
console.error('Error fetching S3 object:', err); | ||
} finally { | ||
setDownloadAndPreview((downloadAndPreview) => ({ | ||
...downloadAndPreview, | ||
isDownloading: false, | ||
})); | ||
} | ||
}; | ||
|
||
export const onPreview: DownloadAndPreviewFunction = async ( | ||
bucketName, | ||
object, | ||
noobaaS3, | ||
setDownloadAndPreview | ||
) => { | ||
try { | ||
setDownloadAndPreview((downloadAndPreview) => ({ | ||
...downloadAndPreview, | ||
isPreviewing: true, | ||
})); | ||
|
||
const objectURL = await getObjectURL(bucketName, object, noobaaS3); | ||
|
||
// open the object URL in a new browser tab | ||
window.open(objectURL, '_blank'); | ||
} catch (err) { | ||
// eslint-disable-next-line no-console | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can consider to allow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make sense to me !! |
||
console.error('Error fetching S3 object:', err); | ||
} finally { | ||
setDownloadAndPreview((downloadAndPreview) => ({ | ||
...downloadAndPreview, | ||
isPreviewing: false, | ||
})); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reason why we need this: https://stackoverflow.com/a/1214753
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Luxon is a modern replacement for deprecated Moment.js