Fixed Object Version selector visibility in Add Lifecycle Rule modal (#2769)

- Fixed Object Version selector visibility in Add Lifecycle Rule modal
- Changed definition in swagger file to match camelCase standard
- Added a playwright test case to avoid this issue in the future

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2023-04-11 03:01:03 -06:00
committed by GitHub
parent 29507cda7e
commit 75b3a6bea4
14 changed files with 111 additions and 64 deletions

View File

@@ -36,17 +36,17 @@ import (
// swagger:model bucketVersioningResponse
type BucketVersioningResponse struct {
// exclude folders
ExcludeFolders bool `json:"ExcludeFolders,omitempty"`
// excluded prefixes
ExcludedPrefixes []*BucketVersioningResponseExcludedPrefixesItems0 `json:"ExcludedPrefixes"`
// m f a delete
MFADelete string `json:"MFADelete,omitempty"`
// exclude folders
ExcludeFolders bool `json:"excludeFolders,omitempty"`
// excluded prefixes
ExcludedPrefixes []*BucketVersioningResponseExcludedPrefixesItems0 `json:"excludedPrefixes"`
// status
Status string `json:"Status,omitempty"`
Status string `json:"status,omitempty"`
}
// Validate validates this bucket versioning response
@@ -76,9 +76,9 @@ func (m *BucketVersioningResponse) validateExcludedPrefixes(formats strfmt.Regis
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))
return ve.ValidateName("excludedPrefixes" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i))
return ce.ValidateName("excludedPrefixes" + "." + strconv.Itoa(i))
}
return err
}
@@ -110,9 +110,9 @@ func (m *BucketVersioningResponse) contextValidateExcludedPrefixes(ctx context.C
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))
return ve.ValidateName("excludedPrefixes" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("ExcludedPrefixes" + "." + strconv.Itoa(i))
return ce.ValidateName("excludedPrefixes" + "." + strconv.Itoa(i))
}
return err
}
@@ -147,7 +147,7 @@ func (m *BucketVersioningResponse) UnmarshalBinary(b []byte) error {
type BucketVersioningResponseExcludedPrefixesItems0 struct {
// prefix
Prefix string `json:"Prefix,omitempty"`
Prefix string `json:"prefix,omitempty"`
}
// Validate validates this bucket versioning response excluded prefixes items0

View File

@@ -0,0 +1,52 @@
// This file is part of MinIO Console Server
// Copyright (c) 2023 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { expect } from "@playwright/test";
import { test } from "./fixtures/baseFixture";
import { minioadminFile } from "./consts";
test.use({ storageState: minioadminFile });
test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:5005/buckets");
});
test("Test if Object Version selector is present in Lifecycle rule modal", async ({
page,
}) => {
await page.locator("#create-bucket").click();
await page.getByLabel("Bucket Name*").click();
await page.getByLabel("Bucket Name*").fill("versioned-bucket");
await page.locator("#versioned").check();
await page.getByRole("button", { name: "Create Bucket" }).click();
await page.locator("#manageBucket-versioned-bucket").click();
await page.getByRole("tab", { name: "Lifecycle" }).click();
await page.getByRole("button", { name: "Add Lifecycle Rule" }).click();
await expect(await page.locator("#object_version")).toBeTruthy();
});
test("Test if Object Version selector is not present when bucket is not versioned", async ({
page,
}) => {
await page.locator("#create-bucket").click();
await page.getByLabel("Bucket Name*").click();
await page.getByLabel("Bucket Name*").fill("non-versioned-bucket");
await page.getByRole("button", { name: "Create Bucket" }).click();
await page.locator("#manageBucket-non-versioned-bucket").click();
await page.getByRole("tab", { name: "Lifecycle" }).click();
await page.getByRole("button", { name: "Add Lifecycle Rule" }).click();
await expect(await page.locator("#object_version").count()).toEqual(0);
});

View File

@@ -791,12 +791,12 @@ export interface ListRemoteBucketsResponse {
}
export interface BucketVersioningResponse {
Status?: string;
status?: string;
MFADelete?: string;
ExcludedPrefixes?: {
Prefix?: string;
excludedPrefixes?: {
prefix?: string;
}[];
ExcludeFolders?: boolean;
excludeFolders?: boolean;
}
export interface SetBucketVersioning {

View File

@@ -49,10 +49,10 @@ import {
spacingUtils,
} from "../../Common/FormComponents/common/styleLibrary";
import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import { BucketVersioning } from "../types";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { selDistSet, setModalErrorSnackMessage } from "../../../../systemSlice";
import { useAppDispatch } from "../../../../store";
import { BucketVersioningInfo, ITiersDropDown } from "../types";
interface IReplicationModal {
open: boolean;
@@ -61,11 +61,6 @@ interface IReplicationModal {
bucketName: string;
}
export interface ITiersDropDown {
label: string;
value: string;
}
const styles = (theme: Theme) =>
createStyles({
formFieldRowFilter: {
@@ -88,7 +83,8 @@ const AddLifecycleModal = ({
const [loadingTiers, setLoadingTiers] = useState<boolean>(true);
const [tiersList, setTiersList] = useState<ITiersDropDown[]>([]);
const [addLoading, setAddLoading] = useState(false);
const [isVersioned, setIsVersioned] = useState<boolean>(false);
const [versioningInfo, setVersioningInfo] =
useState<BucketVersioningInfo | null>(null);
const [prefix, setPrefix] = useState("");
const [tags, setTags] = useState<string>("");
const [storageClass, setStorageClass] = useState("");
@@ -146,8 +142,8 @@ const AddLifecycleModal = ({
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) => {
@@ -258,7 +254,7 @@ const AddLifecycleModal = ({
]}
/>
</Grid>
{isVersioned && (
{versioningInfo?.status === "Enabled" && (
<Grid item xs={12}>
<SelectWrapper
value={targetVersion}

View File

@@ -372,7 +372,7 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => {
}
};
let versioningStatus = versioningInfo?.Status;
let versioningStatus = versioningInfo?.status;
let versioningText = "Unversioned (Default)";
if (versioningStatus === "Enabled") {
versioningText = "Versioned";
@@ -604,7 +604,7 @@ const BucketSummary = ({ classes }: IBucketSummaryProps) => {
isLoading={loadingVersioning}
/>
{versioningInfo?.Status === "Enabled" ? (
{versioningInfo?.status === "Enabled" ? (
<VersioningInfo versioningState={versioningInfo} />
) : null}
</Box>

View File

@@ -36,9 +36,8 @@ import {
spacingUtils,
} from "../../Common/FormComponents/common/styleLibrary";
import { LifeCycleItem } from "../types";
import { ITiersDropDown, LifeCycleItem } from "../types";
import { ErrorResponseHandler } from "../../../../common/types";
import { ITiersDropDown } from "./AddLifecycleModal";
import {
ITierElement,
ITierResponse,

View File

@@ -40,7 +40,7 @@ const EnableVersioningModal = ({
selectedBucket,
versioningInfo = {},
}: IVersioningEventProps) => {
const isVersioningEnabled = versioningInfo.Status === "Enabled";
const isVersioningEnabled = versioningInfo.status === "Enabled";
const dispatch = useAppDispatch();
const [versioningLoading, setVersioningLoading] = useState<boolean>(false);

View File

@@ -40,12 +40,11 @@ import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapp
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
import { ErrorResponseHandler } from "../../../../common/types";
import QueryMultiSelector from "../../Common/FormComponents/QueryMultiSelector/QueryMultiSelector";
import { ITiersDropDown } from "../BucketDetails/AddLifecycleModal";
import {
ITierElement,
ITierResponse,
} from "../../Configurations/TiersConfiguration/types";
import { MultiBucketResult } from "../types";
import { ITiersDropDown, MultiBucketResult } from "../types";
import { setModalErrorSnackMessage } from "../../../../systemSlice";
import { useAppDispatch } from "../../../../store";

View File

@@ -101,7 +101,7 @@ const DeleteObject = ({
};
const isVersionedDelete =
versioning?.Status === "Enabled" || versioning?.Status === "Suspended";
versioning?.status === "Enabled" || versioning?.status === "Suspended";
return (
<ConfirmDialog

View File

@@ -122,7 +122,7 @@ const DeleteObject = ({
)}
? <br />
<br />
{isVersionedMode(versioningInfo?.Status) &&
{isVersionedMode(versioningInfo?.status) &&
selectedVersion === "" && (
<Fragment>
<FormSwitchWrapper

View File

@@ -18,10 +18,10 @@ const VersioningInfo = ({
}}
>
<Box sx={{ fontWeight: "medium", display: "flex", gap: 2 }}>
{versioningState.ExcludeFolders ? (
{versioningState.excludeFolders ? (
<LabelWithIcon
icon={
versioningState.ExcludeFolders ? (
versioningState.excludeFolders ? (
<EnabledIcon style={{ color: "green" }} />
) : (
<DisabledIcon />
@@ -35,7 +35,7 @@ const VersioningInfo = ({
/>
) : null}
</Box>
{versioningState.ExcludedPrefixes?.length ? (
{versioningState.excludedPrefixes?.length ? (
<Box
sx={{
fontWeight: "medium",
@@ -57,7 +57,7 @@ const VersioningInfo = ({
display: "flex",
}}
>
{versioningState.ExcludedPrefixes?.map((it) => (
{versioningState.excludedPrefixes?.map((it) => (
<div>
<strong>{it.Prefix}</strong>
</div>

View File

@@ -52,15 +52,11 @@ export interface ArnList {
arns: string[];
}
export interface BucketVersioning {
is_versioned: boolean;
}
export interface BucketVersioningInfo {
ExcludeFolders?: boolean;
ExcludedPrefixes?: Record<"Prefix", string>[];
excludeFolders?: boolean;
excludedPrefixes?: Record<"Prefix", string>[];
MFADelete?: string;
Status?: "Enabled" | "Suspended" | "";
status?: "Enabled" | "Suspended" | "";
}
export interface BucketObjectLocking {
@@ -147,3 +143,8 @@ export interface MultiBucketResult {
export interface MultiBucketResult {
results: MultiBucketResult[];
}
export interface ITiersDropDown {
label: string;
value: string;
}

View File

@@ -5948,24 +5948,24 @@ func init() {
"bucketVersioningResponse": {
"type": "object",
"properties": {
"ExcludeFolders": {
"MFADelete": {
"type": "string"
},
"excludeFolders": {
"type": "boolean"
},
"ExcludedPrefixes": {
"excludedPrefixes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"Prefix": {
"prefix": {
"type": "string"
}
}
}
},
"MFADelete": {
"type": "string"
},
"Status": {
"status": {
"type": "string"
}
}
@@ -14384,7 +14384,7 @@ func init() {
"BucketVersioningResponseExcludedPrefixesItems0": {
"type": "object",
"properties": {
"Prefix": {
"prefix": {
"type": "string"
}
}
@@ -15084,19 +15084,19 @@ func init() {
"bucketVersioningResponse": {
"type": "object",
"properties": {
"ExcludeFolders": {
"MFADelete": {
"type": "string"
},
"excludeFolders": {
"type": "boolean"
},
"ExcludedPrefixes": {
"excludedPrefixes": {
"type": "array",
"items": {
"$ref": "#/definitions/BucketVersioningResponseExcludedPrefixesItems0"
}
},
"MFADelete": {
"type": "string"
},
"Status": {
"status": {
"type": "string"
}
}

View File

@@ -4944,18 +4944,18 @@ definitions:
bucketVersioningResponse:
type: object
properties:
Status:
status:
type: string
MFADelete:
type: string
ExcludedPrefixes:
excludedPrefixes:
type: array
items:
type: object
properties:
Prefix:
prefix:
type: string
ExcludeFolders:
excludeFolders:
type: boolean
setBucketVersioning: