From b8e14ee2691394483f5082963e12fe0705511c35 Mon Sep 17 00:00:00 2001 From: Prakash Senthil Vel <23444145+prakashsvmx@users.noreply.github.com> Date: Fri, 3 Mar 2023 00:11:44 +0530 Subject: [PATCH] improve versioning status display and delete with versions when versioning is suspended (#2689) --- integration/user_api_bucket_test.go | 24 ++-- models/bucket_versioning_response.go | 118 +++++++++++++++++- .../Buckets/BucketDetails/BrowserHandler.tsx | 6 +- .../BucketDetails/BucketSummaryPanel.tsx | 39 +++++- .../BucketDetails/EnableVersioningModal.tsx | 25 +++- .../ListObjects/DeleteMultipleObjects.tsx | 8 +- .../Objects/ListObjects/DeleteObject.tsx | 39 +++--- .../Objects/ListObjects/ListObjects.tsx | 4 +- .../Objects/ListObjects/ObjectDetailPanel.tsx | 7 +- .../Console/Buckets/VersioningInfo.tsx | 72 +++++++++++ .../src/screens/Console/Buckets/types.tsx | 7 ++ .../ObjectBrowser/objectBrowserSlice.ts | 7 +- .../screens/Console/ObjectBrowser/types.ts | 3 +- portal-ui/src/utils/validationFunctions.ts | 4 + restapi/embedded_spec.go | 45 ++++++- .../configuration/post_configs_import.go | 2 +- restapi/user_buckets.go | 12 +- swagger-console.yml | 14 ++- 18 files changed, 375 insertions(+), 61 deletions(-) create mode 100644 portal-ui/src/screens/Console/Buckets/VersioningInfo.tsx diff --git a/integration/user_api_bucket_test.go b/integration/user_api_bucket_test.go index bd681e873..e9ce19203 100644 --- a/integration/user_api_bucket_test.go +++ b/integration/user_api_bucket_test.go @@ -2289,16 +2289,21 @@ func TestBucketVersioning(t *testing.T) { 200, getVersioningResult.StatusCode, "Status Code is incorrect") } bodyBytes, _ := ioutil.ReadAll(getVersioningResult.Body) - structBucketRepl := models.BucketVersioningResponse{} + structBucketRepl := models.BucketVersioningResponse{ + ExcludeFolders: false, + ExcludedPrefixes: nil, + MFADelete: "", + Status: "", + } err = json.Unmarshal(bodyBytes, &structBucketRepl) if err != nil { log.Println(err) assert.Nil(err) } assert.Equal( - structBucketRepl.IsVersioned, - true, - structBucketRepl.IsVersioned, + structBucketRepl.Status, + "Enabled", + structBucketRepl.Status, ) fmt.Println("Versioned bucket creation test status:", response.Status) @@ -3045,7 +3050,7 @@ func TestSetBucketVersioning(t *testing.T) { return } - // 2. Set versioning as False + // 2. Set versioning as False i.e Suspend versioning response, err := SetBucketVersioning(bucket, false, nil, nil) assert.Nil(err) if err != nil { @@ -3069,13 +3074,18 @@ func TestSetBucketVersioning(t *testing.T) { 200, getVersioningResult.StatusCode, "Status Code is incorrect") } bodyBytes, _ := ioutil.ReadAll(getVersioningResult.Body) - result := models.BucketVersioningResponse{} + result := models.BucketVersioningResponse{ + ExcludeFolders: false, + ExcludedPrefixes: nil, + MFADelete: "", + Status: "", + } err = json.Unmarshal(bodyBytes, &result) if err != nil { log.Println(err) assert.Nil(err) } - assert.Equal(false, result.IsVersioned, result) + assert.Equal("Suspended", result.Status, result) } func EnableBucketEncryption(bucketName, encType, kmsKeyID string) (*http.Response, error) { diff --git a/models/bucket_versioning_response.go b/models/bucket_versioning_response.go index 4d083e46e..25c4fcd28 100644 --- a/models/bucket_versioning_response.go +++ b/models/bucket_versioning_response.go @@ -24,7 +24,9 @@ package models import ( "context" + "strconv" + "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" ) @@ -34,17 +36,90 @@ import ( // swagger:model bucketVersioningResponse type BucketVersioningResponse struct { - // is versioned - IsVersioned bool `json:"is_versioned,omitempty"` + // exclude folders + ExcludeFolders bool `json:"ExcludeFolders,omitempty"` + + // excluded prefixes + ExcludedPrefixes []*BucketVersioningResponseExcludedPrefixesItems0 `json:"ExcludedPrefixes"` + + // m f a delete + MFADelete string `json:"MFADelete,omitempty"` + + // status + Status string `json:"Status,omitempty"` } // Validate validates this bucket versioning response func (m *BucketVersioningResponse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateExcludedPrefixes(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } return nil } -// ContextValidate validates this bucket versioning response based on context it is used +func (m *BucketVersioningResponse) validateExcludedPrefixes(formats strfmt.Registry) error { + if swag.IsZero(m.ExcludedPrefixes) { // not required + return nil + } + + for i := 0; i < len(m.ExcludedPrefixes); i++ { + if swag.IsZero(m.ExcludedPrefixes[i]) { // not required + continue + } + + if m.ExcludedPrefixes[i] != nil { + if err := m.ExcludedPrefixes[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this bucket versioning response based on the context it is used func (m *BucketVersioningResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateExcludedPrefixes(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *BucketVersioningResponse) contextValidateExcludedPrefixes(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ExcludedPrefixes); i++ { + + if m.ExcludedPrefixes[i] != nil { + if err := m.ExcludedPrefixes[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + return nil } @@ -65,3 +140,40 @@ func (m *BucketVersioningResponse) UnmarshalBinary(b []byte) error { *m = res return nil } + +// BucketVersioningResponseExcludedPrefixesItems0 bucket versioning response excluded prefixes items0 +// +// swagger:model BucketVersioningResponseExcludedPrefixesItems0 +type BucketVersioningResponseExcludedPrefixesItems0 struct { + + // prefix + Prefix string `json:"Prefix,omitempty"` +} + +// Validate validates this bucket versioning response excluded prefixes items0 +func (m *BucketVersioningResponseExcludedPrefixesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this bucket versioning response excluded prefixes items0 based on context it is used +func (m *BucketVersioningResponseExcludedPrefixesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *BucketVersioningResponseExcludedPrefixesItems0) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *BucketVersioningResponseExcludedPrefixesItems0) UnmarshalBinary(b []byte) error { + var res BucketVersioningResponseExcludedPrefixesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx index a99dd9613..8b99803ef 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx @@ -54,7 +54,7 @@ import { decodeURLString, encodeURLString } from "../../../../common/utils"; import { permissionItems } from "../ListBuckets/Objects/utils"; import { setErrorSnackMessage } from "../../../../systemSlice"; import api from "../../../../common/api"; -import { BucketObjectLocking, BucketVersioning } from "../types"; +import { BucketObjectLocking, BucketVersioningInfo } from "../types"; import { ErrorResponseHandler } from "../../../../common/types"; import OBHeader from "../../ObjectBrowser/OBHeader"; @@ -401,8 +401,8 @@ const BrowserHandler = () => { if (displayListObjects) { api .invoke("GET", `/api/v1/buckets/${bucketName}/versioning`) - .then((res: BucketVersioning) => { - dispatch(setIsVersioned(res.is_versioned)); + .then((res: BucketVersioningInfo) => { + dispatch(setIsVersioned(res)); dispatch(setLoadingVersioning(false)); }) .catch((err: ErrorResponseHandler) => { diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/BucketSummaryPanel.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/BucketSummaryPanel.tsx index cf17c8cef..1fd38a615 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/BucketSummaryPanel.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/BucketSummaryPanel.tsx @@ -27,7 +27,7 @@ import { BucketObjectLocking, BucketQuota, BucketReplication, - BucketVersioning, + BucketVersioningInfo, } from "../types"; import { BucketList } from "../../Watch/types"; import { @@ -61,6 +61,7 @@ import { setBucketDetailsLoad, } from "./bucketDetailsSlice"; import { useAppDispatch } from "../../../../store"; +import VersioningInfo from "../VersioningInfo"; const SetAccessPolicy = withSuspense( React.lazy(() => import("./SetAccessPolicy")) @@ -121,7 +122,7 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => { const [loadingQuota, setLoadingQuota] = useState(true); const [loadingReplication, setLoadingReplication] = useState(true); const [loadingRetention, setLoadingRetention] = useState(true); - const [isVersioned, setIsVersioned] = useState(false); + const [versioningInfo, setVersioningInfo] = useState(); const [quotaEnabled, setQuotaEnabled] = useState(false); const [quota, setQuota] = useState(null); const [encryptionEnabled, setEncryptionEnabled] = useState(false); @@ -203,8 +204,8 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => { if (loadingVersioning && distributedSetup) { api .invoke("GET", `/api/v1/buckets/${bucketName}/versioning`) - .then((res: BucketVersioning) => { - setIsVersioned(res.is_versioned); + .then((res: BucketVersioningInfo) => { + setVersioningInfo(res); setLoadingVersioning(false); }) .catch((err: ErrorResponseHandler) => { @@ -370,6 +371,15 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => { loadAllBucketData(); } }; + + let versioningStatus = versioningInfo?.Status; + let versioningText = "Unversioned (Default)"; + if (versioningStatus === "Enabled") { + versioningText = "Versioned"; + } else if (versioningStatus === "Suspended") { + versioningText = "Suspended"; + } + // @ts-ignore return ( @@ -412,7 +422,7 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => { closeVersioningModalAndRefresh={closeEnableVersioning} modalOpen={enableVersioningOpen} selectedBucket={bucketName} - versioningCurrentState={isVersioned} + versioningInfo={versioningInfo} /> )} @@ -576,10 +586,27 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => { ]} resourceName={bucketName} property={"Current Status:"} - value={isVersioned ? "Versioned" : "Unversioned (Default)"} + value={ + +
{versioningText}
+
+ } onEdit={setBucketVersioning} isLoading={loadingVersioning} /> + + {versioningInfo?.Status === "Enabled" ? ( + + ) : null} diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/EnableVersioningModal.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/EnableVersioningModal.tsx index 8b1146b74..872d1c4e3 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/EnableVersioningModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/EnableVersioningModal.tsx @@ -24,20 +24,24 @@ import { ConfirmModalIcon } from "mds"; import { setErrorSnackMessage } from "../../../../systemSlice"; import { useAppDispatch } from "../../../../store"; +import { BucketVersioningInfo } from "../types"; +import VersioningInfo from "../VersioningInfo"; interface IVersioningEventProps { closeVersioningModalAndRefresh: (refresh: boolean) => void; modalOpen: boolean; selectedBucket: string; - versioningCurrentState: boolean; + versioningInfo: BucketVersioningInfo | undefined; } const EnableVersioningModal = ({ closeVersioningModalAndRefresh, modalOpen, selectedBucket, - versioningCurrentState, + versioningInfo = {}, }: IVersioningEventProps) => { + const isVersioningEnabled = versioningInfo.Status === "Enabled"; + const dispatch = useAppDispatch(); const [versioningLoading, setVersioningLoading] = useState(false); @@ -49,7 +53,7 @@ const EnableVersioningModal = ({ api .invoke("PUT", `/api/v1/buckets/${selectedBucket}/versioning`, { - versioning: !versioningCurrentState, + versioning: !isVersioningEnabled, }) .then(() => { setVersioningLoading(false); @@ -64,7 +68,7 @@ const EnableVersioningModal = ({ return ( } @@ -78,15 +82,24 @@ const EnableVersioningModal = ({ confirmationContent={ Are you sure you want to{" "} - {versioningCurrentState ? "disable" : "enable"}{" "} + {isVersioningEnabled ? "suspend" : "enable"}{" "} versioning for this bucket? - {versioningCurrentState && ( + {isVersioningEnabled && (

File versions won't be automatically deleted.
)} +
+ {isVersioningEnabled ? ( + + ) : null} +
} /> diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx index eac2f2fd1..794980038 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx @@ -28,6 +28,7 @@ import { AppState, useAppDispatch } from "../../../../../../store"; import { hasPermission } from "../../../../../../common/SecureComponent"; import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions"; import { useSelector } from "react-redux"; +import { BucketVersioningInfo } from "../../../types"; interface IDeleteObjectProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -35,7 +36,7 @@ interface IDeleteObjectProps { selectedObjects: string[]; selectedBucket: string; - versioning: boolean; + versioning: BucketVersioningInfo; } const DeleteObject = ({ @@ -99,6 +100,9 @@ const DeleteObject = ({ } }; + const isVersionedDelete = + versioning?.Status === "Enabled" || versioning?.Status === "Suspended"; + return ( Are you sure you want to delete the selected {selectedObjects.length}{" "} objects?{" "} - {versioning && ( + {isVersionedDelete && (

diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx index bd962211d..6ebce1573 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx @@ -29,6 +29,8 @@ import { AppState, useAppDispatch } from "../../../../../../store"; import { hasPermission } from "../../../../../../common/SecureComponent"; import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions"; import { useSelector } from "react-redux"; +import { BucketVersioningInfo } from "../../../types"; +import { isVersionedMode } from "../../../../../../utils/validationFunctions"; interface IDeleteObjectProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -36,7 +38,7 @@ interface IDeleteObjectProps { selectedObject: string; selectedBucket: string; - versioning: boolean; + versioningInfo: BucketVersioningInfo | undefined; selectedVersion?: string; } @@ -45,7 +47,7 @@ const DeleteObject = ({ deleteOpen, selectedBucket, selectedObject, - versioning, + versioningInfo, selectedVersion = "", }: IDeleteObjectProps) => { const dispatch = useAppDispatch(); @@ -120,22 +122,23 @@ const DeleteObject = ({ )} ?

- {versioning && selectedVersion === "" && ( - - { - setDeleteVersions(!deleteVersions); - }} - description="" - /> - - )} + {isVersionedMode(versioningInfo?.Status) && + selectedVersion === "" && ( + + { + setDeleteVersions(!deleteVersions); + }} + description="" + /> + + )} {canBypass && (deleteVersions || selectedVersion !== "") && (
{ ); const isVersioned = useSelector( - (state: AppState) => state.objectBrowser.isVersioned + (state: AppState) => state.objectBrowser.versionInfo ); const lockingEnabled = useSelector( (state: AppState) => state.objectBrowser.lockingEnabled @@ -1132,7 +1132,7 @@ const ListObjects = () => { internalPaths={selectedInternalPaths} bucketName={bucketName} onClosePanel={onClosePanel} - versioning={isVersioned} + versioningInfo={isVersioned} locking={lockingEnabled} /> )} diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx index 8ed39eee0..600159481 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx @@ -82,6 +82,7 @@ import { import RenameLongFileName from "../../../../ObjectBrowser/RenameLongFilename"; import TooltipWrapper from "../../../../Common/TooltipWrapper/TooltipWrapper"; import { downloadObject } from "../../../../ObjectBrowser/utils"; +import { BucketVersioningInfo } from "../../../types"; const styles = () => createStyles({ @@ -139,7 +140,7 @@ interface IObjectDetailPanelProps { classes: any; internalPaths: string; bucketName: string; - versioning: boolean; + versioningInfo: BucketVersioningInfo; locking: boolean; onClosePanel: (hardRefresh: boolean) => void; } @@ -148,7 +149,7 @@ const ObjectDetailPanel = ({ classes, internalPaths, bucketName, - versioning, + versioningInfo, locking, onClosePanel, }: IObjectDetailPanelProps) => { @@ -606,7 +607,7 @@ const ObjectDetailPanel = ({ selectedBucket={bucketName} selectedObject={internalPaths} closeDeleteModalAndRefresh={closeDeleteModal} - versioning={distributedSetup && versioning} + versioningInfo={distributedSetup ? versioningInfo : undefined} selectedVersion={selectedVersion} /> )} diff --git a/portal-ui/src/screens/Console/Buckets/VersioningInfo.tsx b/portal-ui/src/screens/Console/Buckets/VersioningInfo.tsx new file mode 100644 index 000000000..b888105bb --- /dev/null +++ b/portal-ui/src/screens/Console/Buckets/VersioningInfo.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import { Box } from "@mui/material"; +import { BucketVersioningInfo } from "./types"; +import LabelWithIcon from "./BucketDetails/SummaryItems/LabelWithIcon"; +import { DisabledIcon, EnabledIcon } from "mds"; + +const VersioningInfo = ({ + versioningState = {}, +}: { + versioningState?: BucketVersioningInfo; +}) => { + return ( + + + {versioningState.ExcludeFolders ? ( + + ) : ( + + ) + } + label={ + + } + /> + ) : null} + + {versioningState.ExcludedPrefixes?.length ? ( + + Excluded Prefixes : +
+ {versioningState.ExcludedPrefixes?.map((it) => ( +
+ {it.Prefix} +
+ ))} +
+
+ ) : null} +
+ ); +}; + +export default VersioningInfo; diff --git a/portal-ui/src/screens/Console/Buckets/types.tsx b/portal-ui/src/screens/Console/Buckets/types.tsx index d3aac9b5a..1f43ad748 100644 --- a/portal-ui/src/screens/Console/Buckets/types.tsx +++ b/portal-ui/src/screens/Console/Buckets/types.tsx @@ -81,6 +81,13 @@ export interface BucketVersioning { is_versioned: boolean; } +export interface BucketVersioningInfo { + ExcludeFolders?: boolean; + ExcludedPrefixes?: Record<"Prefix", string>[]; + MFADelete?: string; + Status?: "Enabled" | "Suspended" | ""; +} + export interface BucketObjectLocking { object_locking_enabled: boolean; } diff --git a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts index 26e105ee3..ae7e97e9a 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts @@ -21,6 +21,7 @@ import { IRestoreLocalObjectList, } from "../Buckets/ListBuckets/Objects/ListObjects/types"; import { IRetentionConfig } from "../../../common/types"; +import { BucketVersioningInfo } from "../Buckets/types"; const defaultRewind = { rewindEnabled: false, @@ -57,7 +58,7 @@ const initialState: ObjectBrowserState = { records: [], loadRecords: true, loadingVersioning: true, - isVersioned: false, + versionInfo: {}, lockingEnabled: false, loadingLocking: false, selectedObjects: [], @@ -290,8 +291,8 @@ export const objectBrowserSlice = createSlice({ setLoadingVersioning: (state, action: PayloadAction) => { state.loadingVersioning = action.payload; }, - setIsVersioned: (state, action: PayloadAction) => { - state.isVersioned = action.payload; + setIsVersioned: (state, action: PayloadAction) => { + state.versionInfo = action.payload; }, setLockingEnabled: (state, action: PayloadAction) => { state.lockingEnabled = action.payload; diff --git a/portal-ui/src/screens/Console/ObjectBrowser/types.ts b/portal-ui/src/screens/Console/ObjectBrowser/types.ts index 9b3a114de..b1ebf82aa 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/types.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/types.ts @@ -16,6 +16,7 @@ import { BucketObjectItem } from "../Buckets/ListBuckets/Objects/ListObjects/types"; import { IRetentionConfig } from "../../../common/types"; +import { BucketVersioningInfo } from "../Buckets/types"; export const REWIND_SET_ENABLE = "REWIND/SET_ENABLE"; export const REWIND_RESET_REWIND = "REWIND/RESET_REWIND"; @@ -83,7 +84,7 @@ export interface ObjectBrowserState { records: BucketObjectItem[]; loadRecords: boolean; loadingVersioning: boolean; - isVersioned: boolean; + versionInfo: BucketVersioningInfo; lockingEnabled: boolean; loadingLocking: boolean; selectedObjects: string[]; diff --git a/portal-ui/src/utils/validationFunctions.ts b/portal-ui/src/utils/validationFunctions.ts index e4f611b77..9f89bf58c 100644 --- a/portal-ui/src/utils/validationFunctions.ts +++ b/portal-ui/src/utils/validationFunctions.ts @@ -69,3 +69,7 @@ export const commonFormValidation = (fieldsValidate: IValidation[]) => { return returnErrors; }; + +export const isVersionedMode = (status: string | undefined) => { + return status === "Enabled" || status === "Suspended"; +}; diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index abd62f08d..9c3d9a3d6 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -2597,7 +2597,7 @@ func init() { "tags": [ "Configuration" ], - "summary": "Uploads an Object.", + "summary": "Uploads a file to import MinIO server config.", "parameters": [ { "type": "file", @@ -5906,8 +5906,25 @@ func init() { "bucketVersioningResponse": { "type": "object", "properties": { - "is_versioned": { + "ExcludeFolders": { "type": "boolean" + }, + "ExcludedPrefixes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Prefix": { + "type": "string" + } + } + } + }, + "MFADelete": { + "type": "string" + }, + "Status": { + "type": "string" } } }, @@ -11432,7 +11449,7 @@ func init() { "tags": [ "Configuration" ], - "summary": "Uploads an Object.", + "summary": "Uploads a file to import MinIO server config.", "parameters": [ { "type": "file", @@ -14172,6 +14189,14 @@ func init() { } } }, + "BucketVersioningResponseExcludedPrefixesItems0": { + "type": "object", + "properties": { + "Prefix": { + "type": "string" + } + } + }, "LoginRequestFeatures": { "type": "object", "properties": { @@ -14867,8 +14892,20 @@ func init() { "bucketVersioningResponse": { "type": "object", "properties": { - "is_versioned": { + "ExcludeFolders": { "type": "boolean" + }, + "ExcludedPrefixes": { + "type": "array", + "items": { + "$ref": "#/definitions/BucketVersioningResponseExcludedPrefixesItems0" + } + }, + "MFADelete": { + "type": "string" + }, + "Status": { + "type": "string" } } }, diff --git a/restapi/operations/configuration/post_configs_import.go b/restapi/operations/configuration/post_configs_import.go index d10a13de3..2c273afc6 100644 --- a/restapi/operations/configuration/post_configs_import.go +++ b/restapi/operations/configuration/post_configs_import.go @@ -51,7 +51,7 @@ func NewPostConfigsImport(ctx *middleware.Context, handler PostConfigsImportHand /* PostConfigsImport swagger:route POST /configs/import Configuration postConfigsImport -Uploads an Object. +Uploads a file to import MinIO server config. */ type PostConfigsImport struct { Context *middleware.Context diff --git a/restapi/user_buckets.go b/restapi/user_buckets.go index e51bbed16..64c94d7dc 100644 --- a/restapi/user_buckets.go +++ b/restapi/user_buckets.go @@ -357,9 +357,19 @@ func getBucketVersionedResponse(session *models.Principal, params bucketApi.GetB ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err)) } + excludedPrefixes := make([]*models.BucketVersioningResponseExcludedPrefixesItems0, len(res.ExcludedPrefixes)) + for i, v := range res.ExcludedPrefixes { + excludedPrefixes[i] = &models.BucketVersioningResponseExcludedPrefixesItems0{ + Prefix: v.Prefix, + } + } + // serialize output bucketVResponse := &models.BucketVersioningResponse{ - IsVersioned: res.Status == "Enabled", + ExcludeFolders: res.ExcludeFolders, + ExcludedPrefixes: excludedPrefixes, + MFADelete: res.MFADelete, + Status: res.Status, } return bucketVResponse, nil } diff --git a/swagger-console.yml b/swagger-console.yml index dcded1ea1..053017259 100644 --- a/swagger-console.yml +++ b/swagger-console.yml @@ -4908,8 +4908,20 @@ definitions: bucketVersioningResponse: type: object properties: - is_versioned: + Status: + type: string + MFADelete: + type: string + ExcludedPrefixes: + type: array + items: + type: object + properties: + Prefix: + type: string + ExcludeFolders: type: boolean + setBucketVersioning: type: object properties: