Skip to content
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

Create Bucket page: display CreateOBC form. #1594

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,7 @@
"BucketClass": "BucketClass",
"Enable replication": "Enable replication",
"This option provides higher resiliency of objects stored in NooBaa buckets": "This option provides higher resiliency of objects stored in NooBaa buckets",
"A namespace controls access to the OBC and ties the buckets to a specific project.": "A namespace controls access to the OBC and ties the buckets to a specific project.",
"Create ObjectBucketClaim": "Create ObjectBucketClaim",
"Event log bucket": "Event log bucket",
"Enter a bucket name": "Enter a bucket name",
Expand Down Expand Up @@ -1096,6 +1097,14 @@
"NamespaceStore details": "NamespaceStore details",
"Target Blob Container": "Target Blob Container",
"Num Volumes": "Num Volumes",
"Create Bucket": "Create Bucket",
"An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.": "An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.",
"Select bucket creation method": "Select bucket creation method",
"Create via S3 API": "Create via S3 API",
"Ideal for applications and systems that need to interact directly with S3-compatible storage.": "Ideal for applications and systems that need to interact directly with S3-compatible storage.",
"Create via Object Bucket Claim": "Create via Object Bucket Claim",
"Ideal for Kubernetes environments providing a more abstracted approach to managing storage resources and leveraging dynamic provisioning.": "Ideal for Kubernetes environments providing a more abstracted approach to managing storage resources and leveraging dynamic provisioning.",
"OBC references a StorageClass that uses a provisioner to interact with the S3 API and create the bucket. Kubernetes binds the OBC to the bucket, making it accessible to applications.": "OBC references a StorageClass that uses a provisioner to interact with the S3 API and create the bucket. Kubernetes binds the OBC to the bucket, making it accessible to applications.",
"<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
143 changes: 101 additions & 42 deletions packages/odf/components/mcg/CreateObjectBucketClaim.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { NOOBAA_PROVISIONER } from '@odf/core/constants';
import { namespaceResource } from '@odf/core/resources';
import { BucketClassKind, ObjectBucketClaimKind } from '@odf/core/types';
import {
createNewObjectBucketClaim,
Expand All @@ -13,7 +14,7 @@ import ResourcesDropdown from '@odf/shared/dropdown/ResourceDropdown';
import { FormGroupController } from '@odf/shared/form-group-controller';
import { ButtonBar } from '@odf/shared/generic/ButtonBar';
import { TextInputWithFieldRequirements } from '@odf/shared/input-with-requirements';
import { StorageClassModel } from '@odf/shared/models';
import { NamespaceModel, StorageClassModel } from '@odf/shared/models';
import { getName } from '@odf/shared/selectors';
import { K8sResourceKind, StorageClassResourceKind } from '@odf/shared/types';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
Expand All @@ -22,6 +23,7 @@ import { useYupValidationResolver } from '@odf/shared/yup-validation-resolver';
import {
getAPIVersionForModel,
k8sCreate,
K8sResourceCommon,
NamespaceBar,
useActiveNamespace,
} from '@openshift-console/dynamic-plugin-sdk';
Expand Down Expand Up @@ -364,10 +366,25 @@ export const CreateOBCForm: React.FC<CreateOBCFormProps> = (props) => {
);
};

export const CreateOBCPage: React.FC<{}> = () => {
type CreateOBCProps = {
showNamespaceSelector?: boolean;
};

export const CreateOBC: React.FC<CreateOBCProps> = ({
showNamespaceSelector = false,
}) => {
const { t } = useCustomTranslation();
const [state, dispatch] = React.useReducer(commonReducer, defaultState);
const [namespace, setNamespace] = useActiveNamespace();
const [projectNs, setProjectNs] = useActiveNamespace();
const { odfNamespace } = useODFNamespaceSelector();
const [namespace, setNamespace] = React.useState(
showNamespaceSelector ? odfNamespace : projectNs
);
alfonsomthd marked this conversation as resolved.
Show resolved Hide resolved
// Keep form namespace in sync with project ns when ns form selector is not shown.
if (!showNamespaceSelector && projectNs !== namespace) {
setNamespace(projectNs);
}

const isAllProjectsInitially = React.useRef<boolean>(
namespace === ALL_NAMESPACES_KEY
);
Expand Down Expand Up @@ -403,16 +420,19 @@ export const CreateOBCPage: React.FC<{}> = () => {
* Also, if initial selection is "All Projects", it automatically re-selects "default" as the initial project.
*/
React.useEffect(() => {
if (showNamespaceSelector) {
return;
}
if (isAllProjectsInitially.current) {
setNamespace(DEFAULT_NS);
setProjectNs(DEFAULT_NS);
initialNamespace.current = DEFAULT_NS;
isAllProjectsInitially.current = false;
} else if (initialNamespace.current !== namespace) {
navigate(
`/odf/object-storage/${referenceForModel(NooBaaObjectBucketClaimModel)}`
);
}
}, [navigate, namespace, setNamespace]);
}, [navigate, namespace, setProjectNs, showNamespaceSelector]);

const save = (
alfonsomthd marked this conversation as resolved.
Show resolved Hide resolved
_unused: any,
Expand Down Expand Up @@ -455,6 +475,7 @@ export const CreateOBCPage: React.FC<{}> = () => {
})
.then((resource) => {
dispatch({ type: 'unsetProgress' });
//@TODO: update the resource path with the new bucket details path.
const resourcePath = `${referenceForModel(
NooBaaObjectBucketClaimModel
)}/${resource.metadata.name}`;
Expand All @@ -477,6 +498,80 @@ export const CreateOBCPage: React.FC<{}> = () => {
// Using "allowFallback" in "NamespaceSafetyBox" so that they can default to "openshift-storage" (if case of access issues),
// which is current use case as well (as we do not officially support UI if ODF is installed in any other Namespace).
// ToDo (Sanjal): Update the non-admin "Role" to a "ClusterRole", then read list of NooBaa/BucketClasses across all namespaces.
return (
<NamespaceSafetyBox allowFallback>
<Form onSubmit={handleSubmit(save)}>
{showNamespaceSelector && (
<FormGroupController
name="ns-dropdown"
control={control}
formGroupProps={{
fieldId: 'ns-dropdown',
label: t('Namespace'),
helperText: t(
'A namespace controls access to the OBC and ties the buckets to a specific project.'
),
isRequired: true,
}}
render={({ onBlur }) => (
<ResourcesDropdown<K8sResourceCommon>
resourceModel={NamespaceModel}
onSelect={(selectedNamespace) =>
setNamespace(getName(selectedNamespace))
SanjalKatiyar marked this conversation as resolved.
Show resolved Hide resolved
}
onBlur={onBlur}
initialSelection={(resources) =>
resources?.find((res) => getName(res) === namespace)
}
className="odf-mcg__resource-dropdown"
id="ns-dropdown"
data-test="ns-dropdown"
resource={namespaceResource}
/>
)}
/>
)}
<CreateOBCForm
state={state}
dispatch={dispatch}
namespace={namespace}
control={control}
fieldRequirements={fieldRequirements}
/>
{!isValid && isSubmitted && (
<Alert
variant="danger"
isInline
title={t('Address form errors to proceed')}
/>
)}
<ButtonBar errorMessage={state.error} inProgress={state.progress}>
<ActionGroup className="pf-v5-c-form">
<Button
id={submitBtnId}
type="submit"
variant="primary"
data-test="obc-create"
>
{t('Create')}
</Button>
<Button
onClick={() => navigate(-1)}
type="button"
variant="secondary"
>
{t('Cancel')}
</Button>
</ActionGroup>
</ButtonBar>
</Form>
</NamespaceSafetyBox>
);
};

export const CreateOBCPage: React.FC<{}> = () => {
const { t } = useCustomTranslation();

return (
<>
<NamespaceBar />
Expand All @@ -487,43 +582,7 @@ export const CreateOBCPage: React.FC<{}> = () => {
<h1 className="odf-m-pane__heading odf-m-pane__heading--baseline">
<div>{t('Create ObjectBucketClaim')}</div>
</h1>
<NamespaceSafetyBox allowFallback>
<Form onSubmit={handleSubmit(save)}>
<CreateOBCForm
state={state}
dispatch={dispatch}
namespace={namespace}
control={control}
fieldRequirements={fieldRequirements}
/>
{!isValid && isSubmitted && (
<Alert
variant="danger"
isInline
title={t('Address form errors to proceed')}
/>
)}
<ButtonBar errorMessage={state.error} inProgress={state.progress}>
<ActionGroup className="pf-v5-c-form">
<Button
id={submitBtnId}
type="submit"
variant="primary"
data-test="obc-create"
>
{t('Create')}
</Button>
<Button
onClick={() => navigate(-1)}
type="button"
variant="secondary"
>
{t('Cancel')}
</Button>
</ActionGroup>
</ButtonBar>
</Form>
</NamespaceSafetyBox>
<CreateOBC />
</div>
</>
);
Expand Down
73 changes: 73 additions & 0 deletions packages/odf/components/s3-browser/create-bucket/CreateBucket.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import * as React from 'react';
import { CreateOBC } from '@odf/core/components/mcg/CreateObjectBucketClaim';
import { useCustomTranslation } from '@odf/shared';
import { Alert, FormGroup, Tile } from '@patternfly/react-core';

enum CreationMethod {
OBC = 'obc',
S3 = 's3',
}
alfonsomthd marked this conversation as resolved.
Show resolved Hide resolved

const CreateBucket: React.FC<{}> = () => {
const { t } = useCustomTranslation();
const [method, setMethod] = React.useState<CreationMethod>(CreationMethod.S3);

return (
<>
<div className="co-create-operand__header">
<h1 className="co-create-operand__header-text">{t('Create Bucket')}</h1>
<p>
{t(
'An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.'
)}
</p>
</div>
<div className="co-m-pane__body">
<div className="pf-v5-c-form">
<FormGroup
label={t('Select bucket creation method')}
isRequired
className="pf-v5-u-mb-md"
>
<Tile
title={t('Create via S3 API')}
isSelected={method === CreationMethod.S3}
onClick={() => setMethod(CreationMethod.S3)}
className="pf-v5-u-w-33 pf-v5-u-mr-md"
>
{t(
'Ideal for applications and systems that need to interact directly with S3-compatible storage.'
)}
</Tile>
<Tile
title={t('Create via Object Bucket Claim')}
isSelected={method === CreationMethod.OBC}
onClick={() => setMethod(CreationMethod.OBC)}
className="pf-v5-u-w-33"
>
{t(
'Ideal for Kubernetes environments providing a more abstracted approach to managing storage resources and leveraging dynamic provisioning.'
)}
</Tile>
</FormGroup>
</div>
{method === CreationMethod.OBC && (
<>
<Alert
variant="info"
isInline
title={t(
'OBC references a StorageClass that uses a provisioner to interact with the S3 API and create the bucket. Kubernetes binds the OBC to the bucket, making it accessible to applications.'
)}
className="pf-v5-u-mb-md"
/>
<CreateOBC showNamespaceSelector={true} />
</>
)}
{/* @TODO: implement S3 form. */}
</div>
</>
);
};

export default CreateBucket;
1 change: 1 addition & 0 deletions packages/shared/src/dropdown/ResourceDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ const ResourceDropdown: ResourceDropdown = <T extends unknown>({
filterName(searchText, getName(res)) &&
(filterResource ? filterResource(res) : true)
)
.sort((a, b) => getName(a).localeCompare(getName(b)))
alfonsomthd marked this conversation as resolved.
Show resolved Hide resolved
.reduce((acc, curr) => {
return [
...acc,
Expand Down
8 changes: 8 additions & 0 deletions plugins/odf/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@
}
}
},
{
"type": "console.page/route",
"properties": {
"path": ["/odf/object-storage/create-bucket"],
"exact": true,
"component": { "$codeRef": "createBucket.default" }
}
},
{
"type": "console.page/route",
"properties": {
Expand Down
1 change: 1 addition & 0 deletions plugins/odf/console-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"obc": "@odf/core/components/mcg/ObjectBucketClaim",
"createOBC": "@odf/core/components/mcg/CreateObjectBucketClaim",
"ob": "@odf/core/components/mcg/ObjectBucket",
"createBucket": "@odf/core/components/s3-browser/create-bucket/CreateBucket",
"ocs": "@odf/ocs/dashboards/odf-system-dashboard",
"blockPoolDetailsPage": "@odf/ocs/storage-pool/BlockPoolDetailsPage",
"createStoragePools": "@odf/ocs/storage-pool/CreateStoragePool",
Expand Down
Loading