Skip to content

Commit

Permalink
Merge pull request #1635 from bipuladh/file-upload
Browse files Browse the repository at this point in the history
Add support for file uploads in S3 browser
  • Loading branch information
openshift-merge-bot[bot] authored Oct 18, 2024
2 parents 3e44a45 + a5aeba0 commit c5952c7
Show file tree
Hide file tree
Showing 27 changed files with 1,271 additions and 49 deletions.
27 changes: 27 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,28 @@
"You do not have any objects in the bucket": "You do not have any objects in the bucket",
"many": "many",
"{{ fromCount }} - {{ toCount }} of {{ totalCount }}": "{{ fromCount }} - {{ toCount }} of {{ totalCount }}",
"Add objects": "Add objects",
"Transfer files to cloud storage, where each file (object) is stored with a unique identifier and metadata. By default, objects are private. To configure permissions or properties for objects in an S3 bucket, users can use the AWS Command Line Interface (CLI), AWS Management Console, or SDKs. To make objects publicly accessible or apply more specific permissions, users can set bucket policies, use access control lists (ACLs), or define IAM roles based on their requirements.": "Transfer files to cloud storage, where each file (object) is stored with a unique identifier and metadata. By default, objects are private. To configure permissions or properties for objects in an S3 bucket, users can use the AWS Command Line Interface (CLI), AWS Management Console, or SDKs. To make objects publicly accessible or apply more specific permissions, users can set bucket policies, use access control lists (ACLs), or define IAM roles based on their requirements.",
"Drag and drop files/folders here.": "Drag and drop files/folders here.",
"Standard uploads have a size limit of up to 5TB in S3. For objects, multipart upload will upload the object in parts, which are assembled in the bucket.": "Standard uploads have a size limit of up to 5TB in S3. For objects, multipart upload will upload the object in parts, which are assembled in the bucket.",
"Upload": "Upload",
"Uploading files to the bucket is complete": "Uploading files to the bucket is complete",
"Uploading files to the bucket is in progress": "Uploading files to the bucket is in progress",
"View uploads": "View uploads",
"Dismiss": "Dismiss",
"{{completedUploads}} of {{totalUploads}} have been uploaded": "{{completedUploads}} of {{totalUploads}} have been uploaded",
"Uploads": "Uploads",
"{{uploadedFiles}} of {{totalFiles}} files uploaded": "{{uploadedFiles}} of {{totalFiles}} files uploaded",
"Complete": "Complete",
"Uploading": "Uploading",
"Ongoing": "Ongoing",
"Succeeded: {{uploadedFiles}}": "Succeeded: {{uploadedFiles}}",
"Failed files: {{failedFiles}}": "Failed files: {{failedFiles}}",
"Completion time: {{totalTimeElapsed}}": "Completion time: {{totalTimeElapsed}}",
"Total Remaining: {{totalRemaining}}": "Total Remaining: {{totalRemaining}}",
"Estimated time remaining: {{timeRemaining}}": "Estimated time remaining: {{timeRemaining}}",
"Transfer rate: {{uploadSpeed}}": "Transfer rate: {{uploadSpeed}}",
"Standard uploads have a size limit of up to 5 TB in S3.": "Standard uploads have a size limit of up to 5 TB in S3.",
"<0>The amount of storage allocated to the client cluster for usage.</0><1>Due to simultaneous usage by multiple client clusters, actual available storage may vary affecting your allocated storage quota.</1>": "<0>The amount of storage allocated to the client cluster for usage.</0><1>Due to simultaneous usage by multiple client clusters, actual available storage may vary affecting your allocated storage quota.</1>",
"No storage clients found.": "No storage clients found.",
"You do not have any storage clients connected to this Data Foundation provider cluster.": "You do not have any storage clients connected to this Data Foundation provider cluster.",
Expand Down Expand Up @@ -1338,6 +1360,11 @@
"and": "and",
"GiB RAM": "GiB RAM",
"Configure Performance": "Configure Performance",
"Cancel upload": "Cancel upload",
"Cancel all ongoing uploads?": "Cancel all ongoing uploads?",
"Yes, cancel": "Yes, cancel",
"No, continue uploads": "No, continue uploads",
"Are you sure you want to cancel the ongoing uploads? Any files currently being uploaded will be stopped, and partially uploaded files will not be saved.": "Are you sure you want to cancel the ongoing uploads? Any files currently being uploaded will be stopped, and partially uploaded files will not be saved.",
"This name is already in use. Try using a different name for your folder.": "This name is already in use. Try using a different name for your folder.",
"The forward slash (\"/\") cannot be used.": "The forward slash (\"/\") cannot be used.",
"All characters are allowed except for the forward slash (\"/\").": "All characters are allowed except for the forward slash (\"/\").",
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
},
"dependencies": {
"@aws-sdk/client-s3": "3.667.0",
"@aws-sdk/lib-storage": "3.501.0",
"@aws-sdk/s3-request-presigner": "3.614.0",
"@openshift-console/dynamic-plugin-sdk": "1.3.0",
"@openshift-console/dynamic-plugin-sdk-internal": "1.0.0",
Expand Down Expand Up @@ -99,6 +100,7 @@
"react-dnd": "^15.1.1",
"react-dnd-html5-backend": "^15.1.2",
"react-dom": "^17.0.1",
"react-dropzone": "^14.2.9",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.42.1",
"react-i18next": "^11.11.4",
Expand All @@ -107,6 +109,8 @@
"react-router-dom": "5.3.x",
"react-router-dom-v5-compat": "^6.11.2",
"react-tagsinput": "^3.19.0",
"react-virtualized-auto-sizer": "^1.0.24",
"react-window": "^1.8.10",
"redux": "4.0.1",
"resolve-url-loader": "^5.0.0",
"sass": "^1.55.0",
Expand Down Expand Up @@ -142,6 +146,7 @@
"@types/react-helmet": "^6.1.1",
"@types/react-router": "^5.1.20",
"@types/react-router-dom": "5.3.x",
"@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^5.42",
"@typescript-eslint/parser": "^5.42",
"comment-json": "4.x",
Expand Down
3 changes: 2 additions & 1 deletion packages/odf/components/mcg/ObjectBucket.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { referenceForModel } from '@odf/shared/utils';
import { EventStreamWrapped, YAMLEditorWrapped } from '@odf/shared/utils/Tabs';
import {
K8sResourceCommon,
ListPageBody,
ListPageFilter,
ResourceLink as ResourceLinkWithKind,
Expand Down Expand Up @@ -211,7 +212,7 @@ export const ObjectBucketListPage: React.FC<ObjectBucketsPageProps> = (
};

type OBDetailsProps = {
obj: K8sResourceKind;
obj: K8sResourceCommon;
ownerLabel?: string;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import {
BUCKET_VERSIONING_CACHE_KEY_SUFFIX,
} from '@odf/core/constants';
import { DASH } from '@odf/shared';
import { LoadingBox } from '@odf/shared/generic/status-box';
import { SectionHeading } from '@odf/shared/heading/page-heading';
import { BucketPolicy } from '@odf/shared/s3';
import { K8sResourceKind } from '@odf/shared/types';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { GreenCheckCircleIcon } from '@openshift-console/dynamic-plugin-sdk';
import {
GreenCheckCircleIcon,
K8sResourceCommon,
} from '@openshift-console/dynamic-plugin-sdk';
import { TFunction } from 'i18next';
import { useParams } from 'react-router-dom-v5-compat';
import useSWR from 'swr';
Expand Down Expand Up @@ -166,16 +169,25 @@ const BucketDetailsOverview: React.FC<{}> = ({}) => {
};

type BucketDetailsProps = {
obj: K8sResourceKind;
obj: {
refresh: boolean;
resource?: K8sResourceCommon;
};
};

export const BucketDetails: React.FC<BucketDetailsProps> = ({ obj }) => {
export const BucketDetails: React.FC<BucketDetailsProps> = ({
obj: { resource, refresh },
}) => {
const { t } = useCustomTranslation();

return (
return refresh ? (
<>
<BucketDetailsOverview />
{obj && <OBDetails obj={obj} ownerLabel={t('Owner References')} />}
{resource && (
<OBDetails obj={resource} ownerLabel={t('Owner References')} />
)}
</>
) : (
<LoadingBox />
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import { BucketDetails } from '@odf/core/components/s3-browser/bucket-details/BucketDetails';
import { LoadingBox } from '@odf/shared/generic/status-box';
import PageHeading from '@odf/shared/heading/page-heading';
import { useRefresh } from '@odf/shared/hooks';
import { ModalKeys, defaultModalMap } from '@odf/shared/modals/types';
Expand All @@ -16,6 +15,7 @@ import {
useK8sWatchResource,
HorizontalNav,
useModal,
K8sResourceCommon,
} from '@openshift-console/dynamic-plugin-sdk';
import { LaunchModal } from '@openshift-console/dynamic-plugin-sdk/lib/app/modal-support/ModalProvider';
import { TFunction } from 'i18next';
Expand All @@ -27,9 +27,20 @@ import { PREFIX, BUCKETS_BASE_ROUTE } from '../../../constants';
import { NooBaaObjectBucketModel } from '../../../models';
import { getBreadcrumbs } from '../../../utils';
import { NoobaaS3Provider } from '../noobaa-context';
import { CustomActionsToggle, ObjectsList } from '../objects-list';
import { CustomActionsToggle } from '../objects-list';
import { ObjectListWithSidebar } from '../objects-list/ObjectListWithSidebar';
import { PageTitle } from './PageTitle';

type CustomYAMLEditorProps = {
obj: {
resource: K8sResourceCommon;
};
};

const CustomYAMLEditor: React.FC<CustomYAMLEditorProps> = ({
obj: { resource },
}) => <YAMLEditorWrapped obj={resource} />;

const getBucketActionsItems = (
t: TFunction,
launcher: LaunchModal,
Expand Down Expand Up @@ -118,7 +129,7 @@ const BucketOverview: React.FC<{}> = () => {
{
href: '',
name: t('Objects'),
component: ObjectsList,
component: ObjectListWithSidebar,
},
...(!foldersPath
? [
Expand All @@ -134,7 +145,7 @@ const BucketOverview: React.FC<{}> = () => {
{
href: 'yaml',
name: t('YAML'),
component: YAMLEditorWrapped,
component: CustomYAMLEditor,
},
]
: []),
Expand Down Expand Up @@ -187,14 +198,16 @@ const BucketOverview: React.FC<{}> = () => {
actions={actions}
className="pf-v5-u-mt-md"
/>
{fresh ? (
<HorizontalNav
pages={navPages}
resource={isCreatedByOBC && noobaaObjectBucket}
/>
) : (
<LoadingBox />
)}
<HorizontalNav
pages={navPages}
resource={
{
refresh: fresh,
triggerRefresh,
resource: noobaaObjectBucket,
} as any
}
/>
</NoobaaS3Provider>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react';
import { LoadingBox } from '@odf/shared/generic/status-box';
import { useParams } from 'react-router-dom-v5-compat';
import { NoobaaS3Context } from '../noobaa-context';
import UploadSidebar from '../upload-objects';
import { UploadProgress } from '../upload-objects';
import { FileUploadComponent } from '../upload-objects';
import { ObjectsList } from './ObjectsList';

type ObjectListWithSidebarProps = {
obj: { refresh: boolean; triggerRefresh: () => void };
};

export const ObjectListWithSidebar: React.FC<ObjectListWithSidebarProps> = ({
obj: { refresh, triggerRefresh },
}) => {
const [isExpanded, setExpanded] = React.useState(false);
const [uploadProgress, setUploadProgress] = React.useState<UploadProgress>(
{}
);
const [completionTime, setCompletionTime] = React.useState<number>();

const abortAll = React.useCallback(() => {
Object.values(uploadProgress).forEach((upload) => upload?.abort?.());
}, [uploadProgress]);

const { bucketName } = useParams();

const { noobaaS3 } = React.useContext(NoobaaS3Context);

const closeSidebar = () => setExpanded(false);
const showSidebar = () => setExpanded(true);

return (
<UploadSidebar
isExpanded={isExpanded}
closeSidebar={closeSidebar}
uploadProgress={uploadProgress}
completionTime={completionTime}
mainContent={
<>
<FileUploadComponent
client={noobaaS3}
bucketName={bucketName}
uploadProgress={uploadProgress}
setUploadProgress={setUploadProgress}
showSidebar={showSidebar}
abortAll={abortAll}
setCompletionTime={setCompletionTime}
triggerRefresh={triggerRefresh}
/>
{refresh ? <ObjectsList /> : <LoadingBox />}
</>
}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ export const ObjectsList: React.FC<{}> = () => {
deleteResponse={deleteResponse}
foldersPath={foldersPath}
/>
{/* ToDo: add upload objects option */}
<TableActions
onNext={async () => {
if (!!continuationTokens.next && loadedWOError)
Expand Down
Loading

0 comments on commit c5952c7

Please sign in to comment.