Changed Object Browser components to use new mds components (#2796)

This commit is contained in:
Alex
2023-05-02 18:29:21 -06:00
committed by GitHub
parent 51226a74d0
commit be60569a14
46 changed files with 1208 additions and 1527 deletions

View File

@@ -20,7 +20,6 @@ import {
Theme,
ThemeProvider,
} from "@mui/material/styles";
import withStyles from "@mui/styles/withStyles";
import theme from "./theme/main";
import "react-virtualized/styles.css";
import "react-grid-layout/css/styles.css";
@@ -46,48 +45,19 @@ const StyleHandler = ({ children }: IStyleHandler) => {
(state: AppState) => state.system.overrideStyles
);
let thm = theme;
let globalBody: any = {};
let rowColor: any = { color: "#393939" };
let detailsListPanel: any = { backgroundColor: "#fff" };
let thm = undefined;
if (colorVariants) {
thm = generateOverrideTheme(colorVariants);
globalBody = {
backgroundColor: `${colorVariants.backgroundColor}!important`,
};
rowColor = { color: `${colorVariants.fontColor}!important` };
detailsListPanel = {
backgroundColor: colorVariants.backgroundColor,
color: colorVariants.fontColor,
};
}
// Kept for Compatibility purposes. Once mds migration is complete then this will be removed
const GlobalCss = withStyles({
// @global is handled by jss-plugin-global.
"@global": {
body: {
...globalBody,
},
".rowLine": {
...rowColor,
},
".detailsListPanel": {
...detailsListPanel,
},
},
})(() => null);
// ThemeHandler is needed for MDS components theming. Eventually we will remove Theme Provider & use only mds themes.
return (
<Fragment>
<GlobalStyles />
<GlobalCss />
<StyledEngineProvider injectFirst>
<ThemeProvider theme={thm}>
<ThemeHandler>{children}</ThemeHandler>
<ThemeProvider theme={theme}>
<ThemeHandler customTheme={thm}>{children}</ThemeHandler>
</ThemeProvider>
</StyledEngineProvider>
</Fragment>

View File

@@ -48,16 +48,58 @@ export interface IBytesCalc {
}
export interface IEmbeddedCustomButton {
backgroundColor?: string;
textColor?: string;
hoverColor?: string;
hoverText?: string;
activeColor?: string;
activeText?: string;
backgroundColor: string;
textColor: string;
hoverColor: string;
hoverText: string;
activeColor: string;
activeText: string;
disabledColor: string;
disabledText: string;
}
export interface IEmbeddedCustomTable {
border: string;
disabledBorder: string;
disabledBG: string;
selected: string;
deletedDisabled: string;
hoverColor: string;
}
export interface IEmbeddedInputBox {
border: string;
hoverBorder: string;
textColor: string;
backgroundColor: string;
}
export interface IEmbeddedSwitch {
switchBackground: string;
bulletBorderColor: string;
bulletBGColor: string;
disabledBackground: string;
disabledBulletBorderColor: string;
disabledBulletBGColor: string;
}
export interface IEmbeddedCustomStyles {
backgroundColor: string;
fontColor: string;
secondaryFontColor: string;
borderColor: string;
loaderColor: string;
boxBackground: string;
okColor: string;
errorColor: string;
warnColor: string;
linkColor: string;
disabledLinkColor: string;
hoverLinkColor: string;
tableColors: IEmbeddedCustomTable;
buttonStyles: IEmbeddedCustomButton;
secondaryButtonStyles: IEmbeddedCustomButton;
regularButtonStyles: IEmbeddedCustomButton;
inputBox: IEmbeddedInputBox;
switch: IEmbeddedSwitch;
}

View File

@@ -12,12 +12,15 @@ code {
/* Chrome, Safari, Edge, Opera */
input.removeArrows::-webkit-outer-spin-button,
input.removeArrows::-webkit-inner-spin-button {
input.removeArrows::-webkit-inner-spin-button,
.removeArrows input::-webkit-outer-spin-button,
.removeArrows input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input.removeArrows[type="number"] {
input.removeArrows[type="number"],
.removeArrows input[type="number"] {
-moz-appearance: textfield;
}

View File

@@ -1,72 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 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 React, { Fragment } from "react";
import ObjectActionButton from "./ObjectActionButton";
import { withStyles } from "@mui/styles";
import createStyles from "@mui/styles/createStyles";
import { detailsPanel } from "../../../../Common/FormComponents/common/styleLibrary";
import TooltipWrapper from "../../../../Common/TooltipWrapper/TooltipWrapper";
const styles = () =>
createStyles({
...detailsPanel,
});
export interface MultiSelectionItem {
action: () => void;
label: string;
disabled: boolean;
icon: React.ReactNode;
tooltip: string;
}
interface IActionsListSectionProps {
items: MultiSelectionItem[];
title: string | React.ReactNode;
classes: any;
}
const ActionsListSection = ({
items,
classes,
title,
}: IActionsListSectionProps) => {
return (
<Fragment>
<div className={classes.titleLabel}>{title}</div>
<ul className={classes.objectActions}>
<li>Actions:</li>
{items.map((actionItem, index) => {
return (
<li key={`action-element-${index.toString()}`}>
<TooltipWrapper tooltip={actionItem.tooltip || ""}>
<ObjectActionButton
label={actionItem.label}
icon={actionItem.icon}
onClick={actionItem.action}
disabled={actionItem.disabled}
/>
</TooltipWrapper>
</li>
);
})}
</ul>
</Fragment>
);
};
export default withStyles(styles)(ActionsListSection);

View File

@@ -16,10 +16,8 @@
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button, CreateNewPathIcon } from "mds";
import { Button, CreateNewPathIcon, InputBox, Grid } from "mds";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import { Grid } from "@mui/material";
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import {
@@ -155,7 +153,7 @@ const CreatePathModal = ({
</div>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
<InputBox
value={pathUrl}
label={"New Folder Path"}
id={"folderPath"}

View File

@@ -15,14 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useState } from "react";
import { DialogContentText } from "@mui/material";
import { ErrorResponseHandler } from "../../../../../../common/types";
import useApi from "../../../../Common/Hooks/useApi";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import { ConfirmDeleteIcon } from "mds";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { ConfirmDeleteIcon, Switch } from "mds";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { AppState, useAppDispatch } from "../../../../../../store";
import { hasPermission } from "../../../../../../common/SecureComponent";
@@ -113,14 +109,14 @@ const DeleteObject = ({
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
<Fragment>
Are you sure you want to delete the selected {selectedObjects.length}{" "}
objects?{" "}
{isVersionedDelete && (
<Fragment>
<br />
<br />
<FormSwitchWrapper
<Switch
label={"Delete All Versions"}
indicatorLabels={["Yes", "No"]}
checked={deleteVersions}
@@ -139,7 +135,7 @@ const DeleteObject = ({
marginTop: 10,
}}
>
<FormSwitchWrapper
<Switch
label={"Bypass Governance Mode"}
indicatorLabels={["Yes", "No"]}
checked={bypassGovernance}
@@ -176,7 +172,7 @@ const DeleteObject = ({
)}
</Fragment>
)}
</DialogContentText>
</Fragment>
}
/>
);

View File

@@ -16,17 +16,13 @@
import React, { Fragment, useEffect, useState } from "react";
import { DialogContentText } from "@mui/material";
import Grid from "@mui/material/Grid";
import { ErrorResponseHandler } from "../../../../../../common/types";
import { decodeURLString } from "../../../../../../common/utils";
import { ConfirmDeleteIcon } from "mds";
import { ConfirmDeleteIcon, Switch, Grid, InputBox } from "mds";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import api from "../../../../../../common/api";
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { AppState, useAppDispatch } from "../../../../../../store";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { hasPermission } from "../../../../../../common/SecureComponent";
import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
import { useSelector } from "react-redux";
@@ -105,7 +101,7 @@ const DeleteNonCurrentVersions = ({
disabled: typeConfirm !== "YES, PROCEED" || deleteLoading,
}}
confirmationContent={
<DialogContentText>
<Fragment>
Are you sure you want to delete all the non-current versions for:{" "}
<b>{decodeURLString(selectedObject)}</b>? <br />
{canBypass && (
@@ -115,7 +111,7 @@ const DeleteNonCurrentVersions = ({
marginTop: 10,
}}
>
<FormSwitchWrapper
<Switch
label={"Bypass Governance Mode"}
indicatorLabels={["Yes", "No"]}
checked={bypassGovernance}
@@ -132,8 +128,10 @@ const DeleteNonCurrentVersions = ({
)}
<br />
To continue please type <b>YES, PROCEED</b> in the box.
<br />
<br />
<Grid item xs={12}>
<InputBoxWrapper
<InputBox
id="type-confirm"
name="retype-tenant"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
@@ -143,7 +141,7 @@ const DeleteNonCurrentVersions = ({
value={typeConfirm}
/>
</Grid>
</DialogContentText>
</Fragment>
}
/>
);

View File

@@ -15,15 +15,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useState } from "react";
import { DialogContentText } from "@mui/material";
import { ErrorResponseHandler } from "../../../../../../common/types";
import { decodeURLString } from "../../../../../../common/utils";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import useApi from "../../../../Common/Hooks/useApi";
import { ConfirmDeleteIcon } from "mds";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { ConfirmDeleteIcon, Switch } from "mds";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { AppState, useAppDispatch } from "../../../../../../store";
import { hasPermission } from "../../../../../../common/SecureComponent";
@@ -102,11 +98,7 @@ const DeleteObject = ({
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText
sx={{
width: "430px",
}}
>
<Fragment>
Are you sure you want to delete: <br />
<b>{decodeURLString(selectedObject)}</b>{" "}
{selectedVersion !== "" ? (
@@ -125,7 +117,7 @@ const DeleteObject = ({
{isVersionedMode(versioningInfo?.status) &&
selectedVersion === "" && (
<Fragment>
<FormSwitchWrapper
<Switch
label={"Delete All Versions"}
indicatorLabels={["Yes", "No"]}
checked={deleteVersions}
@@ -146,7 +138,7 @@ const DeleteObject = ({
marginTop: 10,
}}
>
<FormSwitchWrapper
<Switch
label={"Bypass Governance Mode"}
indicatorLabels={["Yes", "No"]}
checked={bypassGovernance}
@@ -181,7 +173,7 @@ const DeleteObject = ({
Are you sure you want to continue?
</Fragment>
)}
</DialogContentText>
</Fragment>
}
/>
);

View File

@@ -17,8 +17,7 @@
import React from "react";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { Grid, IconButton } from "@mui/material";
import { ClosePanelIcon } from "mds";
import { Button, ClosePanelIcon, Grid } from "mds";
import makeStyles from "@mui/styles/makeStyles";
interface IDetailsListPanel {
@@ -58,14 +57,6 @@ const useStyles = makeStyles((theme: Theme) =>
},
},
},
closePanel: {
position: "absolute",
right: 0,
top: 8,
"& .min-icon": {
width: 14,
},
},
})
);
@@ -80,13 +71,24 @@ const DetailsListPanel = ({
return (
<Grid
item
className={`${classes.detailsList} ${
open ? "open" : ""
} ${className} detailsListPanel`}
className={`${classes.detailsList} ${open ? "open" : ""} ${className}`}
>
<IconButton onClick={closePanel} className={classes.closePanel}>
<ClosePanelIcon />
</IconButton>
<Button
variant={"text"}
id={"close-details-list"}
onClick={closePanel}
icon={<ClosePanelIcon />}
sx={{
position: "absolute",
right: 5,
top: 18,
padding: 0,
height: 14,
"&:hover:not(:disabled)": {
backgroundColor: "transparent",
},
}}
/>
{children}
</Grid>
);

View File

@@ -15,7 +15,14 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import { Button, InspectMenuIcon, PasswordKeyIcon } from "mds";
import {
Button,
InspectMenuIcon,
PasswordKeyIcon,
Switch,
Grid,
Box,
} from "mds";
import withStyles from "@mui/styles/withStyles";
import {
decodeURLString,
@@ -24,9 +31,7 @@ import {
getCookieValue,
performDownload,
} from "../../../../../../common/utils";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import Grid from "@mui/material/Grid";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import {
@@ -34,7 +39,7 @@ import {
modalStyleUtils,
spacingUtils,
} from "../../../../Common/FormComponents/common/styleLibrary";
import { Box, DialogContentText } from "@mui/material";
import { DialogContentText } from "@mui/material";
import KeyRevealer from "../../../../Tools/KeyRevealer";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { useAppDispatch } from "../../../../../../store";
@@ -139,7 +144,7 @@ const InspectObject = ({
>
Would you like to encrypt <b>{decodeURLString(inspectPath)}</b>?{" "}
<br />
<FormSwitchWrapper
<Switch
label={"Encrypt"}
indicatorLabels={["Yes", "No"]}
checked={isEncrypt}

View File

@@ -26,9 +26,9 @@ import { useSelector } from "react-redux";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { useDropzone } from "react-dropzone";
import { Theme } from "@mui/material/styles";
import { CSSObject } from "styled-components";
import {
AccessRuleIcon,
ActionsList,
BucketsIcon,
Button,
DeleteIcon,
@@ -37,6 +37,7 @@ import {
PageLayout,
PreviewIcon,
RefreshIcon,
ScreenTitle,
ShareIcon,
} from "mds";
import { DateTime } from "luxon";
@@ -67,8 +68,6 @@ import {
IRetentionConfig,
} from "../../../../../../common/types";
import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle";
import { AppState, useAppDispatch } from "../../../../../../store";
import {
IAM_SCOPES,
@@ -82,7 +81,6 @@ import withSuspense from "../../../../Common/Components/withSuspense";
import UploadFilesButton from "../../UploadFilesButton";
import DetailsListPanel from "./DetailsListPanel";
import ObjectDetailPanel from "./ObjectDetailPanel";
import ActionsListSection from "./ActionsListSection";
import VersionsNavigator from "../ObjectDetails/VersionsNavigator";
import CheckboxWrapper from "../../../../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
@@ -175,6 +173,7 @@ const useStyles = makeStyles((theme: Theme) =>
},
screenTitleContainer: {
border: "#EAEDEE 1px solid",
padding: "0 5px",
},
labelStyle: {
color: "#969FA8",
@@ -184,9 +183,12 @@ const useStyles = makeStyles((theme: Theme) =>
padding: "12px 14px 5px",
},
fullContainer: {
width: "100%",
position: "relative",
"@media (max-width: 799px)": {
width: 0,
"&.detailsOpen": {
"@media (max-width: 799px)": {
display: "none",
},
},
},
hideListOnSmall: {
@@ -281,9 +283,6 @@ const ListObjects = () => {
const anonymousMode = useSelector(
(state: AppState) => state.system.anonymousMode
);
const colorVariants = useSelector(
(state: AppState) => state.system.overrideStyles
);
const anonymousAccessOpen = useSelector(
(state: AppState) => state.objectBrowser.anonymousAccessOpen
);
@@ -806,40 +805,6 @@ const ListObjects = () => {
createdTime = DateTime.fromISO(bucketInfo.creation_date);
}
let regularButtonOverride: CSSObject = {};
let callActionButtonOverride: CSSObject = {};
if (colorVariants) {
regularButtonOverride = {
backgroundColor: "transparent",
};
callActionButtonOverride = {
color: get(colorVariants, "buttonStyles.textColor", "#fff"),
backgroundColor: get(
colorVariants,
"buttonStyles.backgroundColor",
"#07193E"
),
"&:hover": {
color: get(colorVariants, "buttonStyles.hoverText", "#fff"),
backgroundColor: get(
colorVariants,
"buttonStyles.hoverColor",
"#0D2453"
),
},
"&:active": {
color: get(colorVariants, "buttonStyles.activeText", "#fff"),
backgroundColor: get(
colorVariants,
"buttonStyles.activeColor",
"#05132F"
),
},
};
}
const multiActionButtons = [
{
action: () => {
@@ -968,277 +933,263 @@ const ListObjects = () => {
)}
<PageLayout variant={"full"}>
<Grid container spacing={1}>
{anonymousMode && (
<div style={{ paddingBottom: 16 }}>
<FilterObjectsSB />
</div>
)}
<Grid item xs={12} className={classes.screenTitleContainer}>
<ScreenTitle
icon={
<span>
<BucketsIcon style={{ width: 30 }} />
</span>
}
title={<span className={classes.titleSpacer}>{bucketName}</span>}
subTitle={
!anonymousMode ? (
<Fragment>
<Grid item xs={12} className={classes.bucketDetails}>
{anonymousMode && (
<div style={{ paddingBottom: 16 }}>
<FilterObjectsSB />
</div>
)}
<Grid item xs={12} className={classes.screenTitleContainer}>
<ScreenTitle
icon={
<span>
<BucketsIcon style={{ width: 30 }} />
</span>
}
title={bucketName}
subTitle={
!anonymousMode ? (
<Fragment>
<span className={classes.detailsSpacer}>
Created on:&nbsp;&nbsp;
<strong>
{bucketInfo?.creation_date
? createdTime.toFormat(
"ccc, LLL dd yyyy HH:mm:ss (ZZZZ)"
)
: ""}
</strong>
</span>
<span className={classes.detailsSpacer}>
Access:&nbsp;&nbsp;&nbsp;
<strong>{bucketInfo?.access || ""}</strong>
</span>
{bucketInfo && (
<Fragment>
<span className={classes.detailsSpacer}>
Created on:&nbsp;&nbsp;
<strong>
{bucketInfo?.creation_date
? createdTime.toFormat(
"ccc, LLL dd yyyy HH:mm:ss (ZZZZ)"
)
: ""}
</strong>
{bucketInfo.size && (
<Fragment>{niceBytesInt(bucketInfo.size)}</Fragment>
)}
{bucketInfo.size && quota && (
<Fragment> / {niceBytesInt(quota.quota)}</Fragment>
)}
{bucketInfo.size && bucketInfo.objects ? " - " : ""}
{bucketInfo.objects && (
<Fragment>
{bucketInfo.objects}&nbsp;Object
{bucketInfo.objects && bucketInfo.objects !== 1
? "s"
: ""}
</Fragment>
)}
</span>
<span className={classes.detailsSpacer}>
Access:&nbsp;&nbsp;&nbsp;
<strong>{bucketInfo?.access || ""}</strong>
</span>
{bucketInfo && (
<Fragment>
<span className={classes.detailsSpacer}>
{bucketInfo.size && (
<Fragment>
{niceBytesInt(bucketInfo.size)}
</Fragment>
)}
{bucketInfo.size && quota && (
<Fragment>
{" "}
/ {niceBytesInt(quota.quota)}
</Fragment>
)}
{bucketInfo.size && bucketInfo.objects ? " - " : ""}
{bucketInfo.objects && (
<Fragment>
{bucketInfo.objects}&nbsp;Object
{bucketInfo.objects && bucketInfo.objects !== 1
? "s"
: ""}
</Fragment>
)}
</span>
</Fragment>
)}
</Grid>
</Fragment>
) : null
}
actions={
<div className={classes.actionsSection}>
{!anonymousMode && (
<TooltipWrapper tooltip={"Rewind Bucket"}>
<Button
id={"rewind-objects-list"}
label={"Rewind"}
icon={
<Badge
badgeContent=" "
color="secondary"
variant="dot"
invisible={!rewindEnabled}
className={classes.badgeOverlap}
sx={{ height: 16 }}
>
<HistoryIcon
style={{
minWidth: 16,
minHeight: 16,
width: 16,
height: 16,
marginTop: -3,
}}
/>
</Badge>
}
variant={"regular"}
onClick={() => {
setRewindSelect(true);
}}
disabled={
!isVersioned ||
!hasPermission(bucketName, [
IAM_SCOPES.S3_GET_OBJECT,
IAM_SCOPES.S3_GET_ACTIONS,
])
}
sx={regularButtonOverride}
/>
</TooltipWrapper>
</Fragment>
)}
<TooltipWrapper tooltip={"Reload List"}>
</Fragment>
) : null
}
actions={
<Fragment>
{!anonymousMode && (
<TooltipWrapper tooltip={"Rewind Bucket"}>
<Button
id={"refresh-objects-list"}
label={"Refresh"}
icon={<RefreshIcon />}
id={"rewind-objects-list"}
label={"Rewind"}
icon={
<Badge
badgeContent=" "
color="secondary"
variant="dot"
invisible={!rewindEnabled}
className={classes.badgeOverlap}
sx={{ height: 16 }}
>
<HistoryIcon
style={{
minWidth: 16,
minHeight: 16,
width: 16,
height: 16,
marginTop: -3,
}}
/>
</Badge>
}
variant={"regular"}
onClick={() => {
if (versionsMode) {
dispatch(setLoadingVersions(true));
} else {
dispatch(resetMessages());
dispatch(setLoadingRecords(true));
dispatch(setLoadingObjects(true));
}
setRewindSelect(true);
}}
disabled={
anonymousMode
? false
: !hasPermission(bucketName, [
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]) || rewindEnabled
!isVersioned ||
!hasPermission(bucketName, [
IAM_SCOPES.S3_GET_OBJECT,
IAM_SCOPES.S3_GET_ACTIONS,
])
}
sx={regularButtonOverride}
/>
</TooltipWrapper>
<input
type="file"
multiple
onChange={handleUploadButton}
style={{ display: "none" }}
ref={fileUpload}
/>
<input
type="file"
multiple
onChange={handleUploadButton}
style={{ display: "none" }}
ref={folderUpload}
/>
<UploadFilesButton
bucketName={bucketName}
uploadPath={uploadPath.join("/")}
uploadFileFunction={(closeMenu) => {
if (fileUpload && fileUpload.current) {
fileUpload.current.click();
}
closeMenu();
}}
uploadFolderFunction={(closeMenu) => {
if (folderUpload && folderUpload.current) {
folderUpload.current.click();
}
closeMenu();
}}
overrideStyles={callActionButtonOverride}
/>
</div>
}
/>
</Grid>
<Grid item xs={12}>
<div
id="object-list-wrapper"
{...getRootProps({ style: { ...dndStyles } })}
>
<input {...getInputProps()} />
<Grid
item
xs={12}
className={classes.tableBlock}
sx={{ border: "#EAEDEE 1px solid", borderTop: 0 }}
>
{versionsMode ? (
<Fragment>
{selectedInternalPaths !== null && (
<VersionsNavigator
internalPaths={selectedInternalPaths}
bucketName={bucketName}
/>
)}
</Fragment>
) : (
<SecureComponent
scopes={[
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<Grid item xs={12} className={classes.fullContainer}>
{!anonymousMode && (
<Grid
item
xs={12}
className={classes.breadcrumbsContainer}
>
<BrowserBreadcrumbs
bucketName={bucketName}
internalPaths={pageTitle}
additionalOptions={
!isVersioned || rewindEnabled ? null : (
<div>
<CheckboxWrapper
name={"deleted_objects"}
id={"showDeletedObjects"}
value={"deleted_on"}
label={"Show deleted objects"}
onChange={setDeletedAction}
checked={showDeleted}
overrideLabelClasses={classes.labelStyle}
className={classes.overrideShowDeleted}
noTopMargin
/>
</div>
)
}
hidePathButton={false}
/>
</Grid>
)}
<ListObjectsTable internalPaths={selectedInternalPaths} />
</Grid>
</SecureComponent>
)}
{!anonymousMode && (
<SecureComponent
scopes={[
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<DetailsListPanel
open={detailsOpen}
closePanel={() => {
onClosePanel(false);
}}
className={`${
versionsMode ? classes.hideListOnSmall : ""
}`}
>
{selectedObjects.length > 0 && (
<ActionsListSection
items={multiActionButtons}
title={"Selected Objects:"}
/>
)}
{selectedInternalPaths !== null && (
<ObjectDetailPanel
internalPaths={selectedInternalPaths}
bucketName={bucketName}
onClosePanel={onClosePanel}
versioningInfo={isVersioned}
locking={lockingEnabled}
/>
)}
</DetailsListPanel>
</SecureComponent>
)}
</Grid>
</div>
</Grid>
<TooltipWrapper tooltip={"Reload List"}>
<Button
id={"refresh-objects-list"}
label={"Refresh"}
icon={<RefreshIcon />}
variant={"regular"}
onClick={() => {
if (versionsMode) {
dispatch(setLoadingVersions(true));
} else {
dispatch(resetMessages());
dispatch(setLoadingRecords(true));
dispatch(setLoadingObjects(true));
}
}}
disabled={
anonymousMode
? false
: !hasPermission(bucketName, [
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]) || rewindEnabled
}
/>
</TooltipWrapper>
<input
type="file"
multiple
onChange={handleUploadButton}
style={{ display: "none" }}
ref={fileUpload}
/>
<input
type="file"
multiple
onChange={handleUploadButton}
style={{ display: "none" }}
ref={folderUpload}
/>
<UploadFilesButton
bucketName={bucketName}
uploadPath={uploadPath.join("/")}
uploadFileFunction={(closeMenu) => {
if (fileUpload && fileUpload.current) {
fileUpload.current.click();
}
closeMenu();
}}
uploadFolderFunction={(closeMenu) => {
if (folderUpload && folderUpload.current) {
folderUpload.current.click();
}
closeMenu();
}}
/>
</Fragment>
}
bottomBorder={false}
/>
</Grid>
<div
id="object-list-wrapper"
{...getRootProps({ style: { ...dndStyles } })}
>
<input {...getInputProps()} />
<Grid
item
xs={12}
className={classes.tableBlock}
sx={{ border: "#EAEDEE 1px solid", borderTop: 0 }}
>
{versionsMode ? (
<Fragment>
{selectedInternalPaths !== null && (
<VersionsNavigator
internalPaths={selectedInternalPaths}
bucketName={bucketName}
/>
)}
</Fragment>
) : (
<SecureComponent
scopes={[
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<Grid
item
xs={12}
className={`${classes.fullContainer} ${
detailsOpen ? "detailsOpen" : ""
} `}
>
{!anonymousMode && (
<Grid item xs={12} className={classes.breadcrumbsContainer}>
<BrowserBreadcrumbs
bucketName={bucketName}
internalPaths={pageTitle}
additionalOptions={
!isVersioned || rewindEnabled ? null : (
<div>
<CheckboxWrapper
name={"deleted_objects"}
id={"showDeletedObjects"}
value={"deleted_on"}
label={"Show deleted objects"}
onChange={setDeletedAction}
checked={showDeleted}
overrideLabelClasses={classes.labelStyle}
className={classes.overrideShowDeleted}
noTopMargin
/>
</div>
)
}
hidePathButton={false}
/>
</Grid>
)}
<ListObjectsTable internalPaths={selectedInternalPaths} />
</Grid>
</SecureComponent>
)}
{!anonymousMode && (
<SecureComponent
scopes={[
IAM_SCOPES.S3_LIST_BUCKET,
IAM_SCOPES.S3_ALL_LIST_BUCKET,
]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<DetailsListPanel
open={detailsOpen}
closePanel={() => {
onClosePanel(false);
}}
className={`${versionsMode ? classes.hideListOnSmall : ""}`}
>
{selectedObjects.length > 0 && (
<ActionsList
items={multiActionButtons}
title={"Selected Objects:"}
/>
)}
{selectedInternalPaths !== null && (
<ObjectDetailPanel
internalPaths={selectedInternalPaths}
bucketName={bucketName}
onClosePanel={onClosePanel}
versioningInfo={isVersioned}
locking={lockingEnabled}
/>
)}
</DetailsListPanel>
</SecureComponent>
)}
</Grid>
</div>
</PageLayout>
</Fragment>
);

View File

@@ -15,9 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { listModeColumns, rewindModeColumns } from "./ListObjectsHelpers";
import TableWrapper, {
ItemActions,
} from "../../../../Common/TableWrapper/TableWrapper";
import { ItemActions } from "../../../../Common/TableWrapper/TableWrapper";
import React, { useState } from "react";
import makeStyles from "@mui/styles/makeStyles";
import { Theme } from "@mui/material/styles";
@@ -45,18 +43,12 @@ import {
import { hasPermission } from "../../../../../../common/SecureComponent";
import { downloadObject } from "../../../../ObjectBrowser/utils";
import { IFileInfo } from "../ObjectDetails/types";
import { DataTable } from "mds";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
browsePaper: {
border: 0,
height: "calc(100vh - 290px)",
"&.isEmbedded": {
height: "calc(100vh - 315px)",
},
"&.actionsPanelOpen": {
minHeight: "100%",
},
"@media (max-width: 800px)": {
width: 800,
},
@@ -67,6 +59,9 @@ const useStyles = makeStyles((theme: Theme) =>
"@media (max-width: 800px)": {
overflowX: "auto",
},
"@media (max-width: 1060px)": {
height: "calc(100% - 115px)",
},
},
"@global": {
".rowLine:hover .iconFileElm": {
@@ -247,17 +242,21 @@ const ListObjectsTable = ({ internalPaths }: IListObjectTable) => {
"Objects List unavailable. Please review your WebSockets configuration and try again";
}
let customPaperHeight = "calc(100vh - 290px)";
if (obOnly) {
customPaperHeight = "calc(100vh - 315px)";
}
return (
<TableWrapper
<DataTable
itemActions={tableActions}
columns={rewindEnabled ? rewindModeColumns : listModeColumns}
isLoading={loadingObjects}
entityName="Objects"
idField="name"
records={payload}
customPaperHeight={`${classes.browsePaper} ${
obOnly ? "isEmbedded" : ""
} ${detailsOpen ? "actionsPanelOpen" : ""}`}
customPaperHeight={customPaperHeight}
selectedItems={selectedObjects}
onSelect={!anonymousMode ? selectListObjects : undefined}
customEmptyMessage={errorMessage}
@@ -275,6 +274,10 @@ const ListObjectsTable = ({ internalPaths }: IListObjectTable) => {
return "";
}}
parentClassName={classes.parentWrapper}
sx={{
minHeight: detailsOpen ? "100%" : "initial",
}}
noBackground
/>
);
};

View File

@@ -18,8 +18,8 @@ import React, { Fragment, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Box } from "@mui/material";
import { withStyles } from "@mui/styles";
import { CSSObject } from "styled-components";
import {
ActionsList,
Button,
DeleteIcon,
DownloadIcon,
@@ -31,6 +31,7 @@ import {
PreviewIcon,
RetentionIcon,
ShareIcon,
SimpleHeader,
TagsIcon,
VersionsIcon,
} from "mds";
@@ -69,7 +70,6 @@ import {
} from "../../../../../../common/SecureComponent";
import PreviewFileModal from "../Preview/PreviewFileModal";
import ObjectMetaData from "../ObjectDetails/ObjectMetaData";
import ActionsListSection from "./ActionsListSection";
import { displayFileIconName } from "./utils";
import TagsModal from "../ObjectDetails/TagsModal";
import InspectObject from "./InspectObject";
@@ -104,17 +104,6 @@ const styles = () =>
alignItems: "center",
marginLeft: 10,
},
headerForSection: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
paddingBottom: 15,
borderBottom: "#E2E2E2 2px solid",
fontWeight: "bold",
fontSize: 18,
color: "#000",
margin: "20px 22px",
},
capitalizeFirst: {
textTransform: "capitalize",
},
@@ -166,9 +155,6 @@ const ObjectDetailPanel = ({
const loadingObjectInfo = useSelector(
(state: AppState) => state.objectBrowser.loadingObjectInfo
);
const colorVariants = useSelector(
(state: AppState) => state.system.overrideStyles
);
const [shareFileModalOpen, setShareFileModalOpen] = useState<boolean>(false);
const [retentionModalOpen, setRetentionModalOpen] = useState<boolean>(false);
@@ -586,14 +572,6 @@ const ObjectDetailPanel = ({
return formatTime.trim() !== "" ? `${formatTime} ago` : "Just now";
};
let regularButtonOverride: CSSObject = {};
if (colorVariants) {
regularButtonOverride = {
backgroundColor: "transparent",
};
}
return (
<Fragment>
{shareFileModalOpen && actualInfo && (
@@ -679,7 +657,7 @@ const ObjectDetailPanel = ({
<Fragment>{loaderForContainer}</Fragment>
) : (
<Fragment>
<ActionsListSection
<ActionsList
title={
<div className={classes.ObjectDetailsTitle}>
{displayFileIconName(objectName, true)}
@@ -729,17 +707,13 @@ const ObjectDetailPanel = ({
sx={{
width: "calc(100% - 44px)",
margin: "8px 0",
...regularButtonOverride,
}}
label={`Delete${selectedVersion !== "" ? " version" : ""}`}
/>
</SecureComponent>
</Grid>
</TooltipWrapper>
<Grid item xs={12} className={classes.headerForSection}>
<span>Object Info</span>
<ObjectInfoIcon />
</Grid>
<SimpleHeader icon={<ObjectInfoIcon />} label={"Object Info"} />
<Box className={classes.detailContainer}>
<strong>Name:</strong>
<br />
@@ -839,10 +813,7 @@ const ObjectDetailPanel = ({
</Box>
{!actualInfo.is_delete_marker && (
<Fragment>
<Grid item xs={12} className={classes.headerForSection}>
<span>Metadata</span>
<MetadataIcon />
</Grid>
<SimpleHeader label={"Metadata"} icon={<MetadataIcon />} />
<Box className={classes.detailContainer}>
{actualInfo && metaData ? (
<ObjectMetaData metaData={metaData} linear />

View File

@@ -17,11 +17,9 @@
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { LinearProgress } from "@mui/material";
import { Button } from "mds";
import Grid from "@mui/material/Grid";
import { Button, Grid, Switch } from "mds";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import DateTimePickerWrapper from "../../../../Common/FormComponents/DateTimePickerWrapper/DateTimePickerWrapper";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { AppState, useAppDispatch } from "../../../../../../store";
import {
resetRewind,
@@ -103,7 +101,7 @@ const RewindEnable = ({
<Grid container>
{rewindEnabled && (
<Grid item xs={12} sx={{ marginBottom: "10px" }}>
<FormSwitchWrapper
<Switch
value="status"
id="status"
name="status"

View File

@@ -15,16 +15,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useEffect, useState } from "react";
import { DialogContentText } from "@mui/material";
import { ErrorResponseHandler } from "../../../../../../common/types";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import { ConfirmDeleteIcon } from "mds";
import { ConfirmDeleteIcon, Switch } from "mds";
import api from "../../../../../../common/api";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { AppState, useAppDispatch } from "../../../../../../store";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { hasPermission } from "../../../../../../common/SecureComponent";
import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
import { useSelector } from "react-redux";
@@ -116,7 +112,7 @@ const DeleteObject = ({
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
<Fragment>
Are you sure you want to delete the selected {selectedVersions.length}{" "}
versions for <strong>{selectedObject}</strong>?
{canBypass && (
@@ -126,7 +122,7 @@ const DeleteObject = ({
marginTop: 10,
}}
>
<FormSwitchWrapper
<Switch
label={"Bypass Governance Mode"}
indicatorLabels={["Yes", "No"]}
checked={bypassGovernance}
@@ -141,7 +137,7 @@ const DeleteObject = ({
</div>
</Fragment>
)}
</DialogContentText>
</Fragment>
}
/>
);

View File

@@ -15,15 +15,20 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import Grid from "@mui/material/Grid";
import createStyles from "@mui/styles/createStyles";
import { DateTime } from "luxon";
import { Theme } from "@mui/material/styles";
import { withStyles } from "@mui/styles";
import styled from "styled-components";
import get from "lodash/get";
import { displayFileIconName } from "../ListObjects/utils";
import { IFileInfo } from "./types";
import { IconButton, Tooltip } from "@mui/material";
import { DownloadIcon, PreviewIcon, RecoverIcon, ShareIcon } from "mds";
import {
DownloadIcon,
PreviewIcon,
RecoverIcon,
ShareIcon,
IconButton,
Tooltip,
Grid,
} from "mds";
import { niceBytes } from "../../../../../../common/utils";
import SpecificVersionPill from "./SpecificVersionPill";
import CheckboxWrapper from "../../../../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
@@ -41,45 +46,40 @@ interface IFileVersionItem {
onRestore: (versionInfo: IFileInfo) => void;
onPreview: (versionInfo: IFileInfo) => void;
globalClick: (versionInfo: IFileInfo) => void;
classes: any;
key: any;
style: any;
}
const styles = (theme: Theme) =>
createStyles({
mainFileVersionItem: {
borderBottom: "#E2E2E2 1px solid",
const FileVersionStyled = styled.div(({ theme }) => {
return {
"&:before": {
content: "' '",
display: "block",
position: "absolute",
width: "2px",
height: "calc(100% + 2px)",
backgroundColor: get(theme, "borderColor", "#F8F8F8"),
left: "24px",
},
"& .mainFileVersionItem": {
borderBottom: `${get(theme, "borderColor", "#F8F8F8")} 1px solid`,
padding: "1rem 0",
margin: "0 0.5rem 0 2.5rem",
cursor: "pointer",
"&.deleted": {
color: "#868686",
},
"@media (max-width: 799px)": {
padding: "5px 0px",
margin: 0,
},
},
intermediateLayer: {
"& .intermediateLayer": {
margin: "0 1.5rem 0 1.5rem",
"&:hover, &.selected": {
backgroundColor: "#F8F8F8",
backgroundColor: get(theme, "boxBackground", "#F8F8F8"),
"& > div": {
borderBottomColor: "#F8F8F8",
},
},
"@media (max-width: 799px)": {
margin: 0,
"&:hover, &.selected": {
backgroundColor: "transparent",
"& > div": {
borderBottomColor: "#E2E2E2",
},
borderBottomColor: get(theme, "boxBackground", "#F8F8F8"),
},
},
},
versionContainer: {
"& .versionContainer": {
fontSize: 16,
fontWeight: "bold",
display: "flex",
@@ -91,25 +91,14 @@ const styles = (theme: Theme) =>
minHeight: 18,
marginRight: 10,
},
"@media (max-width: 799px)": {
fontSize: 14,
"& svg.min-icon": {
display: "none",
},
},
},
buttonContainer: {
"& .buttonContainer": {
textAlign: "right",
"& button": {
marginLeft: "1.5rem",
},
"@media (max-width: 600px)": {
"& button": {
marginLeft: "5px",
},
},
},
versionID: {
"& .versionID": {
fontSize: "12px",
margin: "2px 0",
whiteSpace: "nowrap",
@@ -117,49 +106,59 @@ const styles = (theme: Theme) =>
maxWidth: "95%",
overflow: "hidden",
},
versionData: {
"& .versionData": {
marginRight: "10px",
fontSize: 12,
color: "#868686",
"@media (max-width: 799px)": {
},
"@media (max-width: 600px)": {
"& .buttonContainer": {
"& button": {
marginLeft: "5px",
},
},
},
"@media (max-width: 799px)": {
"&:before": {
display: "none",
},
"& .mainFileVersionItem": {
padding: "5px 0px",
margin: 0,
},
"& .intermediateLayer": {
margin: 0,
"&:hover, &.selected": {
backgroundColor: "transparent",
"& > div": {
borderBottomColor: get(theme, "boxBackground", "#F8F8F8"),
},
},
},
"& .versionContainer": {
fontSize: 14,
"& svg.min-icon": {
display: "none",
},
},
"& .versionData": {
textOverflow: "ellipsis",
maxWidth: "95%",
overflow: "hidden",
whiteSpace: "nowrap",
},
},
ctrItem: {
position: "relative",
"&::before": {
content: "' '",
display: "block",
position: "absolute",
width: "2px",
height: "calc(100% + 2px)",
backgroundColor: "#F8F8F8",
left: "24px",
},
"@media (max-width: 799px)": {
"&::before": {
display: "none",
},
},
},
collapsableInfo: {
"@media (max-width: 799px)": {
"& .collapsableInfo": {
display: "flex",
flexDirection: "column",
},
},
versionItem: {
"@media (max-width: 799px)": {
"& .versionItem": {
display: "none",
},
},
});
};
});
const FileVersionItem = ({
classes,
fileName,
versionInfo,
isSelected,
@@ -217,121 +216,120 @@ const FileVersionItem = ({
}
return (
<Grid
container
flex={1}
className={classes.ctrItem}
onClick={() => {
globalClick(versionInfo);
}}
key={key}
style={style}
>
<FileVersionStyled>
<Grid
item
xs={12}
className={`${classes.intermediateLayer} ${
isSelected ? "selected" : ""
}`}
container
className={"ctrItem"}
onClick={() => {
globalClick(versionInfo);
}}
key={key}
style={style}
>
<Grid
item
xs={12}
className={`${classes.mainFileVersionItem} ${
versionInfo.is_delete_marker ? "deleted" : ""
}`}
className={`${"intermediateLayer"} ${isSelected ? "selected" : ""}`}
>
<Grid item xs={12} justifyContent={"space-between"}>
<Grid container>
<Grid item xs md={4} className={classes.versionContainer}>
{checkable && (
<CheckboxWrapper
checked={isChecked}
id={`select-${versionInfo.version_id}`}
label={""}
name={`select-${versionInfo.version_id}`}
onChange={(e) => {
e.stopPropagation();
e.preventDefault();
onCheck(versionInfo.version_id || "");
}}
value={versionInfo.version_id || ""}
disabled={versionInfo.is_delete_marker}
overrideCheckboxStyles={{
paddingLeft: 0,
height: 34,
width: 25,
}}
noTopMargin
/>
)}
{displayFileIconName(fileName, true)} v{index.toString()}
<span className={classes.versionItem}>
{pill && <SpecificVersionPill type={pill} />}
</span>
</Grid>
<Grid item xs={10} md={8} className={classes.buttonContainer}>
{versionItemButtons.map((button, index) => {
return (
<Tooltip
title={button.tooltip}
key={`version-action-${
button.tooltip
}-${index.toString()}`}
>
<IconButton
size={"small"}
id={`version-action-${
<Grid
item
xs
className={`mainFileVersionItem ${
versionInfo.is_delete_marker ? "deleted" : ""
}`}
>
<Grid item xs={12}>
<Grid container>
<Grid item xs md={4} className={"versionContainer"}>
{checkable && (
<CheckboxWrapper
checked={isChecked}
id={`select-${versionInfo.version_id}`}
label={""}
name={`select-${versionInfo.version_id}`}
onChange={(e) => {
e.stopPropagation();
e.preventDefault();
onCheck(versionInfo.version_id || "");
}}
value={versionInfo.version_id || ""}
disabled={versionInfo.is_delete_marker}
overrideCheckboxStyles={{
paddingLeft: 0,
height: 34,
width: 25,
}}
noTopMargin
/>
)}
{displayFileIconName(fileName, true)} v{index.toString()}
<span className={"versionItem"}>
{pill && <SpecificVersionPill type={pill} />}
</span>
</Grid>
<Grid item xs={10} md={8} className={"buttonContainer"}>
{versionItemButtons.map((button, index) => {
return (
<Tooltip
tooltip={button.tooltip}
key={`version-action-${
button.tooltip
}-${index.toString()}`}
className={`${classes.spacing} ${
disableButtons ? classes.buttonDisabled : ""
}`}
disabled={disableButtons}
onClick={(e) => {
e.stopPropagation();
if (!disableButtons) {
button.action(versionInfo);
} else {
e.preventDefault();
}
}}
sx={{
backgroundColor: "#F8F8F8",
borderRadius: "100%",
width: "28px",
height: "28px",
padding: "5px",
"& .min-icon": {
width: "14px",
height: "14px",
},
}}
>
{button.icon}
</IconButton>
</Tooltip>
);
})}
<IconButton
size={"small"}
id={`version-action-${
button.tooltip
}-${index.toString()}`}
className={`${"spacing"} ${
disableButtons ? "buttonDisabled" : ""
}`}
disabled={disableButtons}
onClick={(e) => {
e.stopPropagation();
if (!disableButtons) {
button.action(versionInfo);
} else {
e.preventDefault();
}
}}
sx={{
backgroundColor: "#F8F8F8",
borderRadius: "100%",
width: "28px",
height: "28px",
padding: "5px",
"& .min-icon": {
width: "14px",
height: "14px",
},
}}
>
{button.icon}
</IconButton>
</Tooltip>
);
})}
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} className={classes.versionID}>
{versionInfo.version_id !== "null" ? versionInfo.version_id : "-"}
</Grid>
<Grid item xs={12} className={classes.collapsableInfo}>
<span className={classes.versionData}>
<strong>Last modified:</strong>{" "}
{lastModified.toFormat("ccc, LLL dd yyyy HH:mm:ss (ZZZZ)")}
</span>
<span className={classes.versionData}>
<strong>Size:</strong> {niceBytes(versionInfo.size || "0")}
</span>
<Grid item xs={12} className={"versionID"}>
{versionInfo.version_id !== "null" ? versionInfo.version_id : "-"}
</Grid>
<Grid item xs={12} className={"collapsableInfo"}>
<span className={"versionData"}>
<strong>Last modified:</strong>{" "}
{lastModified.toFormat("ccc, LLL dd yyyy HH:mm:ss (ZZZZ)")}
</span>
<span className={"versionData"}>
<strong>Size:</strong> {niceBytes(versionInfo.size || "0")}
</span>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</FileVersionStyled>
);
};
export default withStyles(styles)(FileVersionItem);
export default FileVersionItem;

View File

@@ -15,18 +15,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import { DialogContentText } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
import { ErrorResponseHandler } from "../../../../../../common/types";
import { encodeURLString } from "../../../../../../common/utils";
import api from "../../../../../../common/api";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import { RecoverIcon } from "mds";
import { Box, RecoverIcon } from "mds";
import { setErrorSnackMessage } from "../../../../../../systemSlice";
import { useAppDispatch } from "../../../../../../store";
import { IFileInfo } from "./types";
@@ -68,7 +65,6 @@ const RestoreFileVersion = ({
)}&version_id=${versionToRestore.version_id}`
)
.then((res: any) => {
console.log("REStORE", res);
setRestoreLoading(false);
onCloseAndUpdate(true);
dispatch(
@@ -100,12 +96,12 @@ const RestoreFileVersion = ({
onCloseAndUpdate(false);
}}
confirmationContent={
<DialogContentText id="alert-dialog-description">
<Box id="alert-dialog-description">
Are you sure you want to restore <br />
<b>{objectPath}</b> <br /> with Version ID:
<br />
<b className={classes.wrapText}>{versionToRestore.version_id}</b>?
</DialogContentText>
</Box>
}
/>
);

View File

@@ -19,8 +19,7 @@ import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import get from "lodash/get";
import Grid from "@mui/material/Grid";
import { Button } from "mds";
import { Button, Grid, Switch } from "mds";
import {
formFieldStyles,
modalStyleUtils,
@@ -30,7 +29,6 @@ import {
import { IFileInfo } from "./types";
import { ErrorResponseHandler } from "../../../../../../common/types";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import api from "../../../../../../common/api";
import { encodeURLString } from "../../../../../../common/utils";
@@ -118,7 +116,7 @@ const SetLegalHoldModal = ({
}}
>
<Grid item xs={12} className={classes.formFieldRow}>
<FormSwitchWrapper
<Switch
value="legalhold"
id="legalhold"
name="legalhold"

View File

@@ -19,8 +19,7 @@ import React, { useEffect, useRef, useState } from "react";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import Grid from "@mui/material/Grid";
import { Button } from "mds";
import { Button, Grid, RadioGroup, Switch } from "mds";
import {
formFieldStyles,
modalStyleUtils,
@@ -31,34 +30,18 @@ import { IFileInfo } from "./types";
import { twoDigitDate } from "../../../../Common/FormComponents/DateSelector/utils";
import { ErrorResponseHandler } from "../../../../../../common/types";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import RadioGroupSelector from "../../../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
import DateSelector from "../../../../Common/FormComponents/DateSelector/DateSelector";
import api from "../../../../../../common/api";
import { encodeURLString } from "../../../../../../common/utils";
import { setModalErrorSnackMessage } from "../../../../../../systemSlice";
import { useAppDispatch } from "../../../../../../store";
import { AppState, useAppDispatch } from "../../../../../../store";
import { useSelector } from "react-redux";
const styles = (theme: Theme) =>
createStyles({
...formFieldStyles,
...modalStyleUtils,
...spacingUtils,
dateSelector: {
"& div": {
borderBottom: 0,
marginBottom: 0,
"& div:nth-child(2)": {
border: "1px solid #EAEAEA",
paddingLeft: 5,
"& div": {
border: 0,
},
},
},
},
});
interface ISetRetentionProps {
@@ -83,6 +66,10 @@ const SetRetention = ({
bucketName,
}: ISetRetentionProps) => {
const dispatch = useAppDispatch();
const retentionConfig = useSelector(
(state: AppState) => state.objectBrowser.retentionConfig
);
const [statusEnabled, setStatusEnabled] = useState<boolean>(true);
const [type, setType] = useState<string>("");
const [date, setDate] = useState<string>("");
@@ -92,7 +79,7 @@ const SetRetention = ({
useEffect(() => {
if (objectInfo.retention_mode) {
setType(objectInfo.retention_mode.toLowerCase());
setType(retentionConfig?.mode || "governance");
setAlreadyConfigured(true);
}
// get retention_until_date if defined
@@ -108,7 +95,7 @@ const SetRetention = ({
}
setAlreadyConfigured(true);
}
}, [objectInfo]);
}, [objectInfo, retentionConfig?.mode]);
const dateElement = useRef<IRefObject>(null);
@@ -122,7 +109,7 @@ const SetRetention = ({
const resetForm = () => {
setStatusEnabled(false);
setType("");
setType("governance");
if (dateElement.current) {
dateElement.current.resetDate();
}
@@ -216,7 +203,7 @@ const SetRetention = ({
>
{showSwitcher && (
<Grid item xs={12} className={classes.formFieldRow}>
<FormSwitchWrapper
<Switch
value="status"
id="status"
name="status"
@@ -230,8 +217,8 @@ const SetRetention = ({
</Grid>
)}
<Grid item xs={12} className={classes.formFieldRow}>
<RadioGroupSelector
currentSelection={type}
<RadioGroup
currentValue={type}
id="type"
name="type"
label="Type"

View File

@@ -17,7 +17,7 @@
import React, { Fragment, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Theme } from "@mui/material/styles";
import { Button, CopyIcon, ShareIcon } from "mds";
import { Button, CopyIcon, ReadBox, ShareIcon } from "mds";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import CopyToClipboard from "react-copy-to-clipboard";
@@ -32,7 +32,6 @@ import { IFileInfo } from "./types";
import { ErrorResponseHandler } from "../../../../../../common/types";
import api from "../../../../../../common/api";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import PredefinedList from "../../../../Common/FormComponents/PredefinedList/PredefinedList";
import DaysSelector from "../../../../Common/FormComponents/DaysSelector/DaysSelector";
import { encodeURLString } from "../../../../../../common/utils";
import {
@@ -231,34 +230,31 @@ const ShareFile = ({
xs={12}
className={`${classes.copyShareLink} ${classes.formFieldRow} `}
>
<Grid item xs={12} className={classes.copyShareLinkInput}>
<PredefinedList
content={shareURL}
actionButton={
<CopyToClipboard text={shareURL}>
<Button
id={"copy-path"}
variant="regular"
onClick={() => {
dispatch(
setModalSnackMessage(
"Share URL Copied to clipboard"
)
);
}}
disabled={shareURL === "" || isLoadingFile}
style={{
marginRight: "5px",
width: "28px",
height: "28px",
padding: "0px",
}}
icon={<CopyIcon />}
/>
</CopyToClipboard>
}
/>
</Grid>
<ReadBox
actionButton={
<CopyToClipboard text={shareURL}>
<Button
id={"copy-path"}
variant="regular"
onClick={() => {
dispatch(
setModalSnackMessage("Share URL Copied to clipboard")
);
}}
disabled={shareURL === "" || isLoadingFile}
style={{
marginRight: "5px",
width: "28px",
height: "28px",
padding: "0px",
}}
icon={<CopyIcon />}
/>
</CopyToClipboard>
}
>
{shareURL}
</ReadBox>
</Grid>
</Fragment>
)}

View File

@@ -18,12 +18,18 @@ import React, { Fragment, useState } from "react";
import get from "lodash/get";
import { useSelector } from "react-redux";
import { Box, Grid } from "@mui/material";
import { AddNewTagIcon, Button, DisabledIcon, EditTagIcon } from "mds";
import {
AddNewTagIcon,
Button,
DisabledIcon,
EditTagIcon,
InputBox,
SectionTitle,
} from "mds";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { ErrorResponseHandler } from "../../../../../../common/types";
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import api from "../../../../../../common/api";
import { encodeURLString } from "../../../../../../common/utils";
@@ -186,13 +192,7 @@ const AddTagModal = ({
<Fragment>
<ModalWrapper
modalOpen={modalOpen}
title={
deleteEnabled ? (
<span style={{ color: "#C83B51" }}>Delete Tag</span>
) : (
`Edit Tags`
)
}
title={deleteEnabled ? "Delete Tag" : `Edit Tags`}
onClose={() => {
onCloseAndUpdate(true);
}}
@@ -304,11 +304,11 @@ const AddTagModal = ({
errorProps={{ disabled: true, onClick: null }}
>
<Grid container>
<Grid item xs={12} className={classes.newTileHeader}>
<AddNewTagIcon /> Add New Tag
</Grid>
<SectionTitle icon={<AddNewTagIcon />} separator={false}>
Add New Tag
</SectionTitle>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
<InputBox
value={newKey}
label={"Tag Key"}
id={"newTagKey"}
@@ -320,7 +320,7 @@ const AddTagModal = ({
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
<InputBox
value={newLabel}
label={"Tag Label"}
id={"newTagLabel"}

View File

@@ -20,7 +20,7 @@ import { useSelector } from "react-redux";
import { withStyles } from "@mui/styles";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { LinearProgress, SelectChangeEvent } from "@mui/material";
import { LinearProgress } from "@mui/material";
import Grid from "@mui/material/Grid";
import ShareFile from "./ShareFile";
import {
@@ -42,7 +42,6 @@ import {
encodeURLString,
niceBytesInt,
} from "../../../../../../common/utils";
import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle";
import RestoreFileVersion from "./RestoreFileVersion";
import { AppState, useAppDispatch } from "../../../../../../store";
@@ -50,11 +49,12 @@ import {
Button,
DeleteIcon,
DeleteNonCurrentIcon,
Select,
SelectMultipleIcon,
VersionsIcon,
ScreenTitle,
} from "mds";
import FileVersionItem from "./FileVersionItem";
import SelectWrapper from "../../../../Common/FormComponents/SelectWrapper/SelectWrapper";
import PreviewFileModal from "../Preview/PreviewFileModal";
import DeleteNonCurrent from "../ListObjects/DeleteNonCurrent";
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
@@ -101,16 +101,6 @@ const styles = (theme: Theme) =>
},
screenTitleContainer: {
position: "relative",
"&::before": {
content: "' '",
display: "block",
position: "absolute",
width: "2px",
backgroundColor: "#F8F8F8",
left: "24px",
height: "40px",
bottom: 0,
},
"@media (max-width: 799px)": {
"&::before": {
display: "none",
@@ -520,27 +510,22 @@ const VersionsNavigator = ({
<VersionsIcon />
</span>
}
title={
<span className={classes.titleSpacer}>
{objectNameArray.length > 0
? objectNameArray[objectNameArray.length - 1]
: actualInfo.name}{" "}
Versions
</span>
}
title={`${
objectNameArray.length > 0
? objectNameArray[objectNameArray.length - 1]
: actualInfo.name
} Versions`}
subTitle={
<Fragment>
<Grid item xs={12} className={classes.bucketDetails}>
<span className={classes.detailsSpacer}>
<strong>
{versions.length} Version
{versions.length === 1 ? "" : "s"}&nbsp;&nbsp;&nbsp;
</strong>
</span>
<span className={classes.detailsSpacer}>
<strong>{niceBytesInt(totalSpace)}</strong>
</span>
</Grid>
<span className={classes.detailsSpacer}>
<strong>
{versions.length} Version
{versions.length === 1 ? "" : "s"}&nbsp;&nbsp;&nbsp;
</strong>
</span>
<span className={classes.detailsSpacer}>
<strong>{niceBytesInt(totalSpace)}</strong>
</span>
</Fragment>
}
actions={
@@ -582,15 +567,8 @@ const VersionsNavigator = ({
disabled={versions.length <= 1}
/>
</TooltipWrapper>
<span className={classes.sortByLabel}>Sort by</span>
<SelectWrapper
<Select
id={"sort-by"}
label={""}
value={sortValue}
onChange={(e: SelectChangeEvent<string>) => {
setSortValue(e.target.value as string);
}}
name={"sort-by"}
options={[
{ label: "Date", value: "date" },
{
@@ -598,10 +576,16 @@ const VersionsNavigator = ({
value: "size",
},
]}
value={sortValue}
label={"Sort by"}
onChange={(newValue) => {
setSortValue(newValue);
}}
noLabelMinWidth
/>
</Fragment>
}
className={classes.noBottomBorder}
bottomBorder={false}
/>
</Grid>
<Grid item xs={12} className={classes.versionsVirtualPanel}>

View File

@@ -21,34 +21,17 @@ import React, {
useState,
} from "react";
import clsx from "clsx";
import Grid from "@mui/material/Grid";
import { SelectChangeEvent } from "@mui/material";
import { Box, Grid, HelpIcon, InputLabel, Select, Switch, Tooltip } from "mds";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import InputLabel from "@mui/material/InputLabel";
import Tooltip from "@mui/material/Tooltip";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import InputBase from "@mui/material/InputBase";
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
import { HelpIcon } from "mds";
import FormSwitchWrapper from "../FormSwitchWrapper/FormSwitchWrapper";
import { days, months, validDate, years } from "./utils";
const styles = (theme: Theme) =>
createStyles({
dateInput: {
"&:not(:last-child)": {
marginRight: 22,
},
},
...fieldBasic,
...tooltipHelper,
labelContainer: {
flex: 1,
},
fieldContainer: {
...fieldBasic.fieldContainer,
display: "flex",
@@ -58,29 +41,8 @@ const styles = (theme: Theme) =>
marginTop: 11,
marginBottom: 6,
},
fieldContainerBorder: {
borderBottom: "#9c9c9c 1px solid",
marginBottom: 20,
},
});
const SelectStyled = withStyles((theme: Theme) =>
createStyles({
root: {
"& .MuiSelect-icon": {
color: "#000",
"&.Mui-disabled": {
color: "#9c9c9c",
},
},
},
input: {
borderBottom: 0,
fontSize: 12,
},
})
)(InputBase);
interface IDateSelectorProps {
classes: any;
id: string;
@@ -120,6 +82,7 @@ const DateSelector = forwardRef(
// assume is in the format "2021-12-30"
if (value !== "") {
const valueSplit = value.split("-");
setYear(valueSplit[0]);
setMonth(valueSplit[1]);
// Turn to single digit to be displayed on dropdown buttons
@@ -148,17 +111,9 @@ const DateSelector = forwardRef(
}
};
const onMonthChange = (e: SelectChangeEvent<string>) => {
setMonth(e.target.value as string);
};
const onDayChange = (e: SelectChangeEvent<string>) => {
setDay(e.target.value as string);
};
const onYearChange = (e: SelectChangeEvent<string>) => {
setYear(e.target.value as string);
};
const monthForDropDown = [{ value: "", label: "<Month>" }, ...months];
const daysForDrop = [{ value: "", label: "<Day>" }, ...days];
const yearsForDrop = [{ value: "", label: "<Year>" }, ...years];
return (
<Grid
@@ -170,11 +125,11 @@ const DateSelector = forwardRef(
>
<div className={classes.labelContainer}>
<Grid container>
<InputLabel htmlFor={id} className={classes.inputLabel}>
<InputLabel htmlFor={id}>
<span>{label}</span>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<Tooltip tooltip={tooltip} placement="top">
<div className={classes.tooltip}>
<HelpIcon />
</div>
@@ -183,7 +138,7 @@ const DateSelector = forwardRef(
)}
</InputLabel>
{addSwitch && (
<FormSwitchWrapper
<Switch
indicatorLabels={["Specific Date", "Default (7 Days)"]}
checked={dateEnabled}
value={"date_enabled"}
@@ -200,80 +155,43 @@ const DateSelector = forwardRef(
)}
</Grid>
</div>
<div>
<FormControl
<Box sx={{ display: "flex", gap: 12 }}>
<Select
id={`${id}-month`}
name={`${id}-month`}
value={month}
onChange={(newValue) => {
setMonth(newValue);
}}
options={monthForDropDown}
label={""}
disabled={isDateDisabled()}
className={classes.dateInput}
>
<Select
id={`${id}-month`}
name={`${id}-month`}
value={month}
displayEmpty
onChange={onMonthChange}
input={<SelectStyled />}
>
<MenuItem value="" disabled>
{"<Month>"}
</MenuItem>
{months.map((option) => (
<MenuItem
value={option.value}
key={`select-${id}-monthOP-${option.label}`}
>
{option.label}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
/>
<Select
id={`${id}-day`}
name={`${id}-day`}
value={day}
onChange={(newValue) => {
setDay(newValue);
}}
options={daysForDrop}
label={""}
disabled={isDateDisabled()}
className={classes.dateInput}
>
<Select
id={`${id}-day`}
name={`${id}-day`}
value={day}
displayEmpty
onChange={onDayChange}
input={<SelectStyled />}
>
<MenuItem value="" disabled>
{"<Day>"}
</MenuItem>
{days.map((dayNumber) => (
<MenuItem
value={dayNumber}
key={`select-${id}-dayOP-${dayNumber}`}
>
{dayNumber}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
/>
<Select
id={`${id}-year`}
name={`${id}-year`}
value={year}
onChange={(newValue) => {
setYear(newValue);
}}
options={yearsForDrop}
label={""}
disabled={isDateDisabled()}
className={classes.dateInput}
>
<Select
id={`${id}-year`}
name={`${id}-year`}
value={year}
displayEmpty
onChange={onYearChange}
input={<SelectStyled />}
>
<MenuItem value="" disabled>
{"<Year>"}
</MenuItem>
{years.map((year) => (
<MenuItem value={year} key={`select-${id}-yearOP-${year}`}>
{year}
</MenuItem>
))}
</Select>
</FormControl>
</div>
/>
</Box>
</Grid>
);
}

View File

@@ -29,14 +29,17 @@ export const months = [
{ value: "12", label: "December" },
];
export const days = Array.from(Array(31), (_, num) => num + 1);
export const days = Array.from(Array(31), (_, num) => ({
value: (num + 1).toString(),
label: (num + 1).toString(),
}));
const currentYear = new Date().getFullYear();
export const years = Array.from(
Array(25),
(_, numYear) => numYear + currentYear
);
export const years = Array.from(Array(50), (_, numYear) => ({
value: (numYear + currentYear).toString(),
label: (numYear + currentYear).toString(),
}));
export const validDate = (year: string, month: string, day: string): any[] => {
const currentDate = Date.parse(`${year}-${month}-${day}`);

View File

@@ -16,8 +16,8 @@
import React, { Fragment } from "react";
import { DateTime } from "luxon";
import { HelpIcon, OpenListIcon } from "mds";
import { Grid, InputLabel, TextField, Tooltip } from "@mui/material";
import { HelpIcon, OpenListIcon, Grid, InputLabel, Tooltip, Box } from "mds";
import { TextField } from "@mui/material";
import { DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon";
import InputAdornment from "@mui/material/InputAdornment";
@@ -108,7 +108,7 @@ const styles = (theme: Theme) =>
flexGrow: 1,
},
textBoxContainer: {
flexGrow: 1,
width: "calc(100% - 190px)",
},
openListIcon: {
color: "#9D9E9D",
@@ -315,19 +315,20 @@ const DateTimePickerWrapper = ({
item
xs={12}
className={`${containerCls} ${classNamePrefix}input-field-container`}
sx={{
display: "flex",
alignItems: "center",
}}
>
{label !== "" && (
<InputLabel
htmlFor={id}
className={`${classes.inputLabel} ${classNamePrefix}input-label`}
>
<InputLabel htmlFor={id}>
<span>
{label}
{required ? "*" : ""}
</span>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<Tooltip tooltip={tooltip} placement="top">
<div className={classes.tooltip}>
<HelpIcon />
</div>
@@ -337,11 +338,11 @@ const DateTimePickerWrapper = ({
</InputLabel>
)}
<div
<Box
className={`${classes.textBoxContainer} ${classNamePrefix}input-wrapper`}
>
{inputItem}
</div>
</Box>
</Grid>
</Fragment>
);

View File

@@ -15,15 +15,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useEffect, useState } from "react";
import Grid from "@mui/material/Grid";
import InputLabel from "@mui/material/InputLabel";
import { DateTime } from "luxon";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
import InputBoxWrapper from "../InputBoxWrapper/InputBoxWrapper";
import { LinkIcon } from "mds";
import { LinkIcon, InputLabel, InputBox, Grid } from "mds";
interface IDaysSelector {
classes: any;
@@ -53,13 +50,11 @@ const styles = (theme: Theme) =>
marginTop: 11,
marginBottom: 6,
},
dateInputContainer: {
margin: "0 10px",
},
durationInputs: {
display: "flex",
alignItems: "center",
alignItems: "flex-start",
justifyContent: "flex-start",
gap: 10,
},
validityIndicator: {
@@ -192,33 +187,31 @@ const DaysSelector = ({
selectedMinutes,
]);
const extraInputProps = {
style: {
const extraStyles = {
"& .textBoxContainer": {
minWidth: 0,
},
"& input": {
textAlign: "center" as const,
paddingRight: 10,
paddingLeft: 10,
width: 25,
width: 40,
},
className: "removeArrows" as const,
};
return (
<Fragment>
<Grid container className={classes.fieldContainer}>
<Grid item xs={12} className={classes.labelContainer}>
<InputLabel
htmlFor={id}
className={classes.inputLabel}
sx={{ marginLeft: "10px" }}
>
<span>{label}</span>
<InputLabel htmlFor={id} sx={{ marginLeft: "10px" }}>
{label}
</InputLabel>
</Grid>
<Grid item xs={12} className={classes.durationInputs}>
<Grid item className={classes.dateInputContainer}>
<InputBoxWrapper
<Grid item xs className={classes.dateInputContainer}>
<InputBox
id={id}
className={classes.reverseInput}
className={`${classes.reverseInput} removeArrows`}
type="number"
min="0"
max={maxDays ? maxDays.toString() : "999"}
@@ -228,14 +221,14 @@ const DaysSelector = ({
setSelectedDays(parseInt(e.target.value));
}}
value={selectedDays.toString()}
extraInputProps={extraInputProps}
sx={extraStyles}
noLabelMinWidth
/>
</Grid>
<Grid item className={classes.dateInputContainer}>
<InputBoxWrapper
<Grid item xs className={classes.dateInputContainer}>
<InputBox
id={id}
className={classes.reverseInput}
className={`${classes.reverseInput} removeArrows`}
type="number"
min="0"
max="23"
@@ -245,14 +238,14 @@ const DaysSelector = ({
setSelectedHours(parseInt(e.target.value));
}}
value={selectedHours.toString()}
extraInputProps={extraInputProps}
sx={extraStyles}
noLabelMinWidth
/>
</Grid>
<Grid item className={classes.dateInputContainer}>
<InputBoxWrapper
<Grid item xs className={classes.dateInputContainer}>
<InputBox
id={id}
className={classes.reverseInput}
className={`${classes.reverseInput} removeArrows`}
type="number"
min="0"
max="59"
@@ -262,7 +255,7 @@ const DaysSelector = ({
setSelectedMinutes(parseInt(e.target.value));
}}
value={selectedMinutes.toString()}
extraInputProps={extraInputProps}
sx={extraStyles}
noLabelMinWidth
/>
</Grid>

View File

@@ -207,41 +207,7 @@ export const actionsTray = {
};
export const searchField = {
searchField: {
flexGrow: 1,
height: 38,
background: "#FFFFFF",
borderRadius: 3,
border: "#EAEDEE 1px solid",
display: "flex",
justifyContent: "center",
padding: "0 16px",
"& label, & label.MuiInputLabel-shrink": {
fontSize: 10,
transform: "translate(5px, 2px)",
transformOrigin: "top left",
},
"& input": {
fontSize: 12,
fontWeight: 700,
color: "#000",
"&::placeholder": {
color: "#858585",
opacity: 1,
fontWeight: 400,
},
},
"&:hover": {
borderColor: "#000",
},
"& .min-icon": {
width: 16,
height: 16,
},
"&:focus-within": {
borderColor: "rgba(0, 0, 0, 0.87)",
},
},
searchField: {},
};
export const predefinedList = {
@@ -659,33 +625,6 @@ export const wizardCommon = {
},
};
export const tenantDetailsStyles = {
buttonContainer: {
display: "flex",
justifyContent: "flex-end",
},
multiContainer: {
display: "flex" as const,
alignItems: "center" as const,
justifyContent: "flex-start" as const,
},
paperContainer: {
padding: "15px 15px 15px 50px",
},
breadcrumLink: {
textDecoration: "none",
color: "black",
},
...modalBasic,
...actionsTray,
...searchField,
actionsTray: {
...actionsTray.actionsTray,
padding: "15px 0 0",
},
};
export const inputFieldStyles = {
root: {
borderRadius: 3,
@@ -806,17 +745,6 @@ export const tableStyles: any = {
tableBlock: {
display: "flex",
flexDirection: "row",
"& .ReactVirtualized__Table__headerRow.rowLine, .ReactVirtualized__Table__row.rowLine":
{
borderBottom: "1px solid #EAEAEA",
},
"& .rowLine:hover:not(.ReactVirtualized__Table__headerRow)": {
backgroundColor: "#F8F8F8",
},
"& .ReactVirtualized__Table__row.rowLine": {
fontSize: ".8rem",
},
"& .optionsAlignment ": {
textAlign: "right",

View File

@@ -15,15 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import {
Dialog,
DialogActions,
DialogContent,
DialogTitle,
} from "@mui/material";
import { Button } from "mds";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import { Button, ModalBox, Box } from "mds";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
@@ -71,41 +63,22 @@ const ConfirmDialog = ({
confirmationButtonSimple = false,
}: ConfirmDialogProps) => {
return (
<Dialog
<ModalBox
title={title}
titleIcon={titleIcon}
onClose={onClose}
open={isOpen}
onClose={(event, reason) => {
if (reason !== "backdropClick") {
onClose(); // close on Esc but not on click outside
}
}}
className={classes.root}
sx={{
"& .MuiPaper-root": {
padding: "1rem 2rem 2rem 1rem",
},
}}
customMaxWidth={510}
>
<DialogTitle className={classes.title}>
<div className={classes.titleText}>
{titleIcon} {title}
</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={onClose}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent className={classes.content}>
{confirmationContent}
</DialogContent>
<DialogActions className={classes.actions}>
<Box className={classes.content}>{confirmationContent}</Box>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
gap: 10,
marginTop: 20,
}}
>
<Button
onClick={onCancel || onClose}
disabled={isLoading}
@@ -124,8 +97,8 @@ const ConfirmDialog = ({
variant={"secondary"}
{...confirmButtonProps}
/>
</DialogActions>
</Dialog>
</Box>
</ModalBox>
);
};

View File

@@ -15,9 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import IconButton from "@mui/material/IconButton";
import Snackbar from "@mui/material/Snackbar";
import { Dialog, DialogContent, DialogTitle } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
@@ -26,9 +24,10 @@ import {
snackBarCommon,
} from "../FormComponents/common/styleLibrary";
import { AppState, useAppDispatch } from "../../../../store";
import CloseIcon from "@mui/icons-material/Close";
import MainError from "../MainError/MainError";
import { setModalSnackMessage } from "../../../../systemSlice";
import { ModalBox } from "mds";
import { CSSObject } from "styled-components";
interface IModalProps {
classes: any;
@@ -37,21 +36,13 @@ interface IModalProps {
title: string | React.ReactNode;
children: any;
wideLimit?: boolean;
noContentPadding?: boolean;
titleIcon?: React.ReactNode;
sx?: CSSObject;
}
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
content: {
padding: 25,
paddingBottom: 0,
},
customDialogSize: {
width: "100%",
maxWidth: 765,
},
...snackBarCommon,
});
@@ -62,8 +53,8 @@ const ModalWrapper = ({
children,
classes,
wideLimit = true,
noContentPadding,
titleIcon = null,
sx,
}: IModalProps) => {
const dispatch = useAppDispatch();
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
@@ -94,14 +85,6 @@ const ModalWrapper = ({
dispatch(setModalSnackMessage(""));
};
const customSize = wideLimit
? {
classes: {
paper: classes.customDialogSize,
},
}
: { maxWidth: "lg" as const, fullWidth: true };
let message = "";
if (modalSnackMessage) {
@@ -115,36 +98,14 @@ const ModalWrapper = ({
}
return (
<Dialog
<ModalBox
onClose={onClose}
open={modalOpen}
classes={classes}
{...customSize}
scroll={"paper"}
onClose={(event, reason) => {
if (reason !== "backdropClick") {
onClose(); // close on Esc but not on click outside
}
}}
className={classes.root}
title={title}
titleIcon={titleIcon}
widthLimit={wideLimit}
sx={sx}
>
<DialogTitle className={classes.title}>
<div className={classes.titleText}>
{titleIcon} {title}
</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
id={"close"}
className={classes.closeButton}
onClick={onClose}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<MainError isModal={true} />
<Snackbar
open={openSnackbar}
@@ -164,10 +125,8 @@ const ModalWrapper = ({
modalSnackMessage && modalSnackMessage.type === "error" ? 10000 : 5000
}
/>
<DialogContent className={noContentPadding ? "" : classes.content}>
{children}
</DialogContent>
</Dialog>
{children}
</ModalBox>
);
};

View File

@@ -60,7 +60,6 @@ const styles = (theme: Theme) =>
},
},
headItem: {
color: "#000",
fontSize: 14,
fontWeight: "bold",
width: "100%",

View File

@@ -21,7 +21,7 @@ import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { IconButton, Tooltip } from "@mui/material";
import { AppState, useAppDispatch } from "../../../../store";
import { RemoveAllIcon } from "mds";
import { Box, RemoveAllIcon } from "mds";
import ObjectHandled from "./ObjectHandled";
import {
cleanList,
@@ -32,9 +32,7 @@ import clsx from "clsx";
const styles = (theme: Theme) =>
createStyles({
downloadContainer: {
border: "#EAEDEE 1px solid",
boxShadow: "rgba(0, 0, 0, 0.08) 0 2px 10px",
backgroundColor: "#fff",
position: "absolute",
right: 20,
top: 62,
@@ -62,7 +60,6 @@ const styles = (theme: Theme) =>
paddingBottom: 20,
borderBottom: "#E2E2E2 1px solid",
margin: "25px 30px 5px 30px",
color: "#000",
},
actionsContainer: {
overflowY: "auto",
@@ -104,11 +101,13 @@ const ObjectManager = ({ classes }: IObjectManager) => {
return (
<Fragment>
{managerOpen && (
<div
<Box
className={clsx(classes.downloadContainer, {
[classes.downloadContainerAnonymous]: anonymousMode,
open: managerOpen,
})}
useBackground
withBorders
>
<div className={classes.cleanIcon}>
<Tooltip title={"Clean Completed Objects"} placement="bottom-start">
@@ -134,7 +133,7 @@ const ObjectManager = ({ classes }: IObjectManager) => {
/>
))}
</div>
</div>
</Box>
)}
</Fragment>
);

View File

@@ -15,64 +15,38 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import InputAdornment from "@mui/material/InputAdornment";
import { SearchIcon } from "mds";
import TextField from "@mui/material/TextField";
import withStyles from "@mui/styles/withStyles";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { searchField } from "./FormComponents/common/styleLibrary";
const styles = (theme: Theme) =>
createStyles({
searchField: {
...searchField.searchField,
},
adornment: {},
});
import { InputBox, SearchIcon } from "mds";
type SearchBoxProps = {
placeholder?: string;
value: string;
classes: any;
onChange: (value: string) => void;
adornmentPosition?: "start" | "end";
overrideClass?: any;
};
const SearchBox = ({
placeholder = "",
classes,
onChange,
adornmentPosition = "end",
overrideClass,
value,
}: SearchBoxProps) => {
const inputProps = {
disableUnderline: true,
[`${adornmentPosition}Adornment`]: (
<InputAdornment
position={adornmentPosition}
className={classes.adornment}
>
<SearchIcon />
</InputAdornment>
),
};
return (
<TextField
<InputBox
placeholder={placeholder}
className={overrideClass ? overrideClass : classes.searchField}
className={overrideClass ? overrideClass : ""}
id="search-resource"
label=""
InputProps={inputProps}
onChange={(e) => {
onChange(e.target.value);
}}
variant="standard"
value={value}
overlayObject={
<SearchIcon
style={{ width: 16, height: 16, marginTop: 5, marginRight: 5 }}
/>
}
/>
);
};
export default withStyles(styles)(SearchBox);
export default SearchBox;

View File

@@ -15,25 +15,13 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { cloneElement } from "react";
import { Tooltip } from "@mui/material";
import { Tooltip } from "mds";
interface ITooltipWrapperProps {
tooltip: string;
children: any;
errorProps?: any;
placement?:
| "bottom-end"
| "bottom-start"
| "bottom"
| "left-end"
| "left-start"
| "left"
| "right-end"
| "right-start"
| "right"
| "top-end"
| "top-start"
| "top";
placement?: "bottom" | "left" | "right" | "top";
}
const TooltipWrapper = ({
@@ -43,7 +31,7 @@ const TooltipWrapper = ({
placement,
}: ITooltipWrapperProps) => {
return (
<Tooltip title={tooltip} placement={placement}>
<Tooltip tooltip={tooltip} placement={placement}>
<span>
{errorProps ? cloneElement(children, { ...errorProps }) : children}
</span>

View File

@@ -22,12 +22,11 @@ import React, {
useState,
} from "react";
import { Theme } from "@mui/material/styles";
import { Button } from "mds";
import { Button, MainContainer } from "mds";
import debounce from "lodash/debounce";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { LinearProgress } from "@mui/material";
import CssBaseline from "@mui/material/CssBaseline";
import Snackbar from "@mui/material/Snackbar";
import { Navigate, Route, Routes, useLocation } from "react-router-dom";
import { useSelector } from "react-redux";
@@ -481,110 +480,101 @@ const Console = ({ classes }: IConsoleProps) => {
return (
<Fragment>
{session && session.status === "ok" ? (
<div className={classes.root}>
<CssBaseline />
{!hideMenu && <Menu />}
<main className={classes.content}>
{needsRestart && (
<div className={classes.warningBar}>
{isServerLoading ? (
<Fragment>
The server is restarting.
<LinearProgress className={classes.progress} />
</Fragment>
) : (
<Fragment>
The instance needs to be restarted for configuration changes
to take effect.{" "}
<Button
id={"restart-server"}
variant="secondary"
onClick={() => {
restartServer();
}}
label={"Restart"}
/>
</Fragment>
)}
</div>
)}
{loadingProgress < 100 && (
<LinearProgress
className={classes.progress}
variant="determinate"
value={loadingProgress}
/>
)}
<MainError />
<div className={classes.snackDiv}>
<Snackbar
open={openSnackbar}
onClose={() => {
closeSnackBar();
}}
autoHideDuration={
snackBarMessage.type === "error" ? 10000 : 5000
}
message={snackBarMessage.message}
className={classes.snackBarExternal}
ContentProps={{
className: `${classes.snackBar} ${
snackBarMessage.type === "error"
? classes.errorSnackBar
: ""
}`,
}}
/>
<MainContainer menu={!hideMenu ? <Menu /> : null}>
{needsRestart && (
<div className={classes.warningBar}>
{isServerLoading ? (
<Fragment>
The server is restarting.
<LinearProgress className={classes.progress} />
</Fragment>
) : (
<Fragment>
The instance needs to be restarted for configuration changes
to take effect.{" "}
<Button
id={"restart-server"}
variant="secondary"
onClick={() => {
restartServer();
}}
label={"Restart"}
/>
</Fragment>
)}
</div>
<Suspense fallback={<LoadingComponent />}>
<ObjectManager />
</Suspense>
<Routes>
{allowedRoutes.map((route: any) => (
<Route
key={route.path}
path={`${route.path}/*`}
element={
<Suspense fallback={<LoadingComponent />}>
<route.component {...route.props} />
</Suspense>
}
/>
))}
)}
{loadingProgress < 100 && (
<LinearProgress
className={classes.progress}
variant="determinate"
value={loadingProgress}
/>
)}
<MainError />
<div className={classes.snackDiv}>
<Snackbar
open={openSnackbar}
onClose={() => {
closeSnackBar();
}}
autoHideDuration={snackBarMessage.type === "error" ? 10000 : 5000}
message={snackBarMessage.message}
className={classes.snackBarExternal}
ContentProps={{
className: `${classes.snackBar} ${
snackBarMessage.type === "error" ? classes.errorSnackBar : ""
}`,
}}
/>
</div>
<Suspense fallback={<LoadingComponent />}>
<ObjectManager />
</Suspense>
<Routes>
{allowedRoutes.map((route: any) => (
<Route
key={"icons"}
path={"icons"}
key={route.path}
path={`${route.path}/*`}
element={
<Suspense fallback={<LoadingComponent />}>
<IconsScreen />
<route.component {...route.props} />
</Suspense>
}
/>
<Route
key={"components"}
path={"components"}
element={
<Suspense fallback={<LoadingComponent />}>
<ComponentsScreen />
</Suspense>
}
/>
<Route
path={"*"}
element={
<Fragment>
{allowedRoutes.length > 0 ? (
<Navigate to={allowedRoutes[0].path} />
) : (
<Fragment />
)}
</Fragment>
}
/>
</Routes>
</main>
</div>
))}
<Route
key={"icons"}
path={"icons"}
element={
<Suspense fallback={<LoadingComponent />}>
<IconsScreen />
</Suspense>
}
/>
<Route
key={"components"}
path={"components"}
element={
<Suspense fallback={<LoadingComponent />}>
<ComponentsScreen />
</Suspense>
}
/>
<Route
path={"*"}
element={
<Fragment>
{allowedRoutes.length > 0 ? (
<Navigate to={allowedRoutes[0].path} />
) : (
<Fragment />
)}
</Fragment>
}
/>
</Routes>
</MainContainer>
) : null}
</Fragment>
);

View File

@@ -51,7 +51,9 @@ const ZoomWidget = ({
}}
modalOpen={modalOpen}
wideLimit={false}
noContentPadding
sx={{
padding: 0,
}}
>
<Fragment>
{componentToUse(value, timeStart, timeEnd, true, apiPrefix, true)}

View File

@@ -160,7 +160,6 @@ const UsersSelectors = ({
<div className={classes.searchBox}>
<SearchBox
placeholder="Filter Users"
adornmentPosition="end"
onChange={setFilter}
value={filter}
/>

View File

@@ -16,17 +16,14 @@
import React, { Fragment, useState } from "react";
import { useSelector } from "react-redux";
import { CSSObject } from "styled-components";
import CopyToClipboard from "react-copy-to-clipboard";
import Grid from "@mui/material/Grid";
import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
import { Theme } from "@mui/material/styles";
import { Link, useNavigate } from "react-router-dom";
import { IconButton } from "@mui/material";
import { objectBrowserCommon } from "../Common/FormComponents/common/styleLibrary";
import { encodeURLString } from "../../../common/utils";
import { BackCaretIcon, Button, CopyIcon, NewPathIcon, Tooltip } from "mds";
import { Button, CopyIcon, NewPathIcon, Tooltip, Breadcrumbs } from "mds";
import { hasPermission } from "../../../common/SecureComponent";
import {
IAM_SCOPES,
@@ -81,9 +78,6 @@ const BrowserBreadcrumbs = ({
const anonymousMode = useSelector(
(state: AppState) => state.system.anonymousMode
);
const colorVariants = useSelector(
(state: AppState) => state.system.overrideStyles
);
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
@@ -187,14 +181,6 @@ const BrowserBreadcrumbs = ({
}
};
let regularButtonOverride: CSSObject = {};
if (colorVariants) {
regularButtonOverride = {
backgroundColor: "transparent",
};
}
return (
<Fragment>
<div className={classes.breadcrumbsMain}>
@@ -206,52 +192,44 @@ const BrowserBreadcrumbs = ({
onClose={closeAddFolderModal}
/>
)}
<Grid item xs={12} className={`${classes.breadcrumbs}`}>
<IconButton
onClick={goBackFunction}
sx={{
border: "#EAEDEE 1px solid",
backgroundColor: "#fff",
borderLeft: 0,
borderRadius: 0,
width: 38,
height: 38,
marginRight: "10px",
}}
>
<BackCaretIcon />
</IconButton>
<div className={classes.breadcrumbsList} dir="rtl">
{listBreadcrumbs}
</div>
<CopyToClipboard text={`${bucketName}/${splitPaths.join("/")}`}>
<Button
id={"copy-path"}
icon={
<CopyIcon
<Breadcrumbs
goBackFunction={goBackFunction}
additionalOptions={
<Fragment>
<CopyToClipboard text={`${bucketName}/${splitPaths.join("/")}`}>
<Button
id={"copy-path"}
icon={
<CopyIcon
style={{
width: "12px",
height: "12px",
fill: "#969FA8",
marginTop: -1,
}}
/>
}
variant={"regular"}
onClick={() => {
dispatch(setSnackBarMessage("Path copied to clipboard"));
}}
style={{
width: "12px",
height: "12px",
fill: "#969FA8",
marginTop: -1,
width: "28px",
height: "28px",
color: "#969FA8",
border: "#969FA8 1px solid",
marginRight: 5,
}}
/>
}
variant={"regular"}
onClick={() => {
dispatch(setSnackBarMessage("Path copied to clipboard"));
}}
style={{
width: "28px",
height: "28px",
color: "#969FA8",
border: "#969FA8 1px solid",
marginRight: 5,
}}
/>
</CopyToClipboard>
<div className={classes.additionalOptions}>{additionalOptions}</div>
</Grid>
</CopyToClipboard>
<div className={classes.additionalOptions}>
{additionalOptions}
</div>
</Fragment>
}
>
{listBreadcrumbs}
</Breadcrumbs>
{!hidePathButton && (
<Tooltip
tooltip={
@@ -275,7 +253,6 @@ const BrowserBreadcrumbs = ({
}}
variant={"regular"}
label={"Create new path"}
sx={regularButtonOverride}
/>
</Tooltip>
)}

View File

@@ -18,7 +18,14 @@ import React, { Fragment, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Theme } from "@mui/material/styles";
import { BucketsIcon, Button, HelpBox, PageLayout, RefreshIcon } from "mds";
import {
BucketsIcon,
Button,
DataTable,
HelpBox,
PageLayout,
RefreshIcon,
} from "mds";
import createStyles from "@mui/styles/createStyles";
import { LinearProgress } from "@mui/material";
import Grid from "@mui/material/Grid";
@@ -45,14 +52,13 @@ import AutoColorIcon from "../Common/Components/AutoColorIcon";
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
import AButton from "../Common/AButton/AButton";
import makeStyles from "@mui/styles/makeStyles";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
import { niceBytesInt } from "../../../common/utils";
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
import {
Bucket,
Error,
HttpResponse,
ListBucketsResponse,
Error,
} from "../../../api/consoleApi";
import { api } from "../../../api";
import { errorToHandler } from "../../../api/errors";
@@ -189,7 +195,7 @@ const OBListBuckets = () => {
className={`${classes.bucketList} ${obOnly ? "isEmbedded" : ""}`}
>
{filteredRecords.length !== 0 && (
<TableWrapper
<DataTable
isLoading={loading}
records={filteredRecords}
entityName={"Buckets"}

View File

@@ -15,9 +15,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment } from "react";
import { Box, Button } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { HelpBox, WarnIcon, Grid } from "mds";
import { Box } from "@mui/material";
import { Button, Grid, HelpBox, WarnIcon } from "mds";
interface IRegisterCluster {
compactMode?: boolean;
@@ -28,8 +28,9 @@ const RegisterCluster = ({ compactMode = false }: IRegisterCluster) => {
const redirectButton = (
<Button
id={"go-to-register"}
type="submit"
variant="contained"
variant="callAction"
color="primary"
onClick={() => navigate("/support/register")}
>

View File

@@ -146,7 +146,6 @@ const GroupsSelectors = ({
<div className={classes.searchBox}>
<SearchBox
placeholder="Start typing to search for Groups"
adornmentPosition="end"
onChange={setFilter}
value={filter}
/>

View File

@@ -15,7 +15,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { IEmbeddedCustomStyles } from "../common/types";
import { createTheme } from "@mui/material";
export const getOverrideColorVariants: (
customStyles: string
@@ -29,124 +28,250 @@ export const getOverrideColorVariants: (
};
export const generateOverrideTheme = (overrideVars: IEmbeddedCustomStyles) => {
const theme = createTheme({
palette: {
primary: {
light: overrideVars.buttonStyles.hoverColor || "#073052",
main: overrideVars.buttonStyles.backgroundColor || "#081C42",
dark: overrideVars.buttonStyles.activeColor || "#05122B",
contrastText: overrideVars.buttonStyles.textColor || "#fff",
},
secondary: {
light: "#ff7961",
main: "#f44336",
dark: "#ba000d",
contrastText: "#000",
},
background: {
default: overrideVars.backgroundColor,
},
success: {
main: "#4ccb92",
},
warning: {
main: "#FFBD62",
},
error: {
light: "#e03a48",
main: "#C83B51",
contrastText: "#fff",
},
},
typography: {
fontFamily: ["Inter", "sans-serif"].join(","),
h1: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
h2: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
h3: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
h4: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
h5: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
h6: {
fontWeight: "bold",
color: overrideVars.fontColor,
},
},
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: "none",
borderRadius: 3,
height: 40,
padding: "0 20px",
fontSize: 14,
fontWeight: 600,
boxShadow: "none",
"& .min-icon": {
maxHeight: 18,
},
"&.MuiButton-contained.Mui-disabled": {
backgroundColor: "#EAEDEE",
fontWeight: 600,
color: "#767676",
},
"& .MuiButton-iconSizeMedium > *:first-of-type": {
fontSize: 12,
},
},
},
},
MuiPaper: {
styleOverrides: {
root: {
backgroundColor: overrideVars.backgroundColor,
color: overrideVars.fontColor,
},
elevation1: {
boxShadow: "none",
border: "#EAEDEE 1px solid",
borderRadius: 3,
},
},
},
MuiListItem: {
styleOverrides: {
root: {
"&.MuiListItem-root.Mui-selected": {
background: "inherit",
"& .MuiTypography-root": {
fontWeight: "bold",
},
},
},
},
},
MuiTab: {
styleOverrides: {
root: {
textTransform: "none",
},
},
},
},
colors: {
link: "#2781B0",
},
});
let retVal = undefined;
return theme;
try {
retVal = {
bgColor: overrideVars.backgroundColor,
fontColor: overrideVars.fontColor,
borderColor: overrideVars.borderColor,
bulletColor: overrideVars.fontColor,
logoColor: "#C51B3F",
logoLabelColor: overrideVars.fontColor,
logoLabelInverse: "#FFF",
loaderColor: overrideVars.loaderColor,
boxBackground: overrideVars.boxBackground,
buttons: {
regular: {
enabled: {
border: overrideVars.regularButtonStyles.textColor,
text: overrideVars.regularButtonStyles.textColor,
background: "transparent",
iconColor: overrideVars.regularButtonStyles.textColor,
},
disabled: {
border: overrideVars.regularButtonStyles.disabledText,
text: overrideVars.regularButtonStyles.disabledText,
background: "transparent",
iconColor: overrideVars.regularButtonStyles.disabledText,
},
hover: {
border: overrideVars.regularButtonStyles.hoverText,
text: overrideVars.regularButtonStyles.hoverText,
background: "transparent",
iconColor: overrideVars.regularButtonStyles.hoverText,
},
pressed: {
border: overrideVars.regularButtonStyles.activeText,
text: overrideVars.regularButtonStyles.activeText,
background: "transparent",
iconColor: overrideVars.regularButtonStyles.activeText,
},
},
callAction: {
enabled: {
border: overrideVars.buttonStyles.backgroundColor,
text: overrideVars.buttonStyles.textColor,
background: overrideVars.buttonStyles.backgroundColor,
iconColor: overrideVars.buttonStyles.textColor,
},
disabled: {
border: overrideVars.buttonStyles.disabledColor,
text: overrideVars.buttonStyles.disabledText,
background: overrideVars.buttonStyles.disabledColor,
iconColor: overrideVars.buttonStyles.disabledText,
},
hover: {
border: overrideVars.buttonStyles.hoverColor,
text: overrideVars.buttonStyles.hoverText,
background: overrideVars.buttonStyles.hoverColor,
iconColor: overrideVars.buttonStyles.hoverText,
},
pressed: {
border: overrideVars.buttonStyles.activeColor,
text: overrideVars.buttonStyles.activeText,
background: overrideVars.buttonStyles.activeColor,
iconColor: overrideVars.buttonStyles.activeText,
},
},
secondary: {
enabled: {
border: overrideVars.secondaryButtonStyles.textColor,
text: overrideVars.secondaryButtonStyles.textColor,
background: "transparent",
iconColor: overrideVars.secondaryButtonStyles.textColor,
},
disabled: {
border: overrideVars.secondaryButtonStyles.disabledText,
text: overrideVars.secondaryButtonStyles.disabledText,
background: "transparent",
iconColor: overrideVars.secondaryButtonStyles.disabledText,
},
hover: {
border: overrideVars.secondaryButtonStyles.hoverText,
text: overrideVars.secondaryButtonStyles.hoverText,
background: "transparent",
iconColor: overrideVars.secondaryButtonStyles.hoverText,
},
pressed: {
border: overrideVars.secondaryButtonStyles.activeText,
text: overrideVars.secondaryButtonStyles.activeText,
background: "transparent",
iconColor: overrideVars.secondaryButtonStyles.activeText,
},
},
text: {
enabled: {
border: "transparent",
text: overrideVars.fontColor,
background: "transparent",
iconColor: overrideVars.fontColor,
},
disabled: {
border: "transparent",
text: overrideVars.fontColor,
background: "transparent",
iconColor: overrideVars.fontColor,
},
hover: {
border: "transparent",
text: overrideVars.fontColor,
background: "transparent",
iconColor: overrideVars.fontColor,
},
pressed: {
border: "transparent",
text: overrideVars.fontColor,
background: "transparent",
iconColor: overrideVars.fontColor,
},
},
},
login: {
formBG: "#fff",
bgFilter: "none",
promoBG: "#000110",
promoHeader: "#fff",
promoText: "#A6DFEF",
footerElements: "#2781B0",
footerDivider: "#F2F2F2",
},
pageHeader: {
background: overrideVars.boxBackground,
border: overrideVars.borderColor,
color: overrideVars.fontColor,
},
tooltip: {
background: overrideVars.boxBackground,
color: overrideVars.fontColor,
},
commonInput: {
labelColor: overrideVars.fontColor,
},
checkbox: {
checkBoxBorder: overrideVars.borderColor,
checkBoxColor: overrideVars.okColor,
disabledBorder: overrideVars.buttonStyles.disabledColor,
disabledColor: overrideVars.buttonStyles.disabledColor,
},
iconButton: {
buttonBG: overrideVars.buttonStyles.backgroundColor,
activeBG: overrideVars.buttonStyles.activeColor,
hoverBG: overrideVars.buttonStyles.hoverColor,
disabledBG: overrideVars.buttonStyles.disabledColor,
color: overrideVars.buttonStyles.textColor,
},
dataTable: {
border: overrideVars.tableColors.border,
disabledBorder: overrideVars.tableColors.disabledBorder,
disabledBG: overrideVars.tableColors.disabledBG,
selected: overrideVars.tableColors.selected,
deletedDisabled: overrideVars.tableColors.deletedDisabled,
hoverColor: overrideVars.tableColors.hoverColor,
},
backLink: {
color: overrideVars.linkColor,
arrow: overrideVars.linkColor,
hover: overrideVars.hoverLinkColor,
},
inputBox: {
border: overrideVars.inputBox.border,
hoverBorder: overrideVars.inputBox.hoverBorder,
color: overrideVars.inputBox.textColor,
backgroundColor: overrideVars.inputBox.backgroundColor,
error: overrideVars.errorColor,
placeholderColor: overrideVars.inputBox.textColor,
disabledBorder: overrideVars.buttonStyles.disabledColor,
disabledBackground: overrideVars.inputBox.backgroundColor,
disabledPlaceholder: overrideVars.buttonStyles.disabledColor,
disabledText: overrideVars.buttonStyles.disabledColor,
},
breadcrumbs: {
border: overrideVars.borderColor,
linksColor: overrideVars.linkColor,
textColor: overrideVars.fontColor,
backgroundColor: overrideVars.boxBackground,
backButton: {
border: overrideVars.borderColor,
backgroundColor: overrideVars.boxBackground,
},
},
actionsList: {
containerBorderColor: overrideVars.boxBackground,
backgroundColor: overrideVars.boxBackground,
disabledOptionsTextColor: overrideVars.disabledLinkColor,
optionsBorder: overrideVars.borderColor,
optionsHoverTextColor: overrideVars.hoverLinkColor,
optionsTextColor: overrideVars.linkColor,
titleColor: overrideVars.fontColor,
},
screenTitle: {
border: overrideVars.borderColor,
subtitleColor: overrideVars.secondaryFontColor,
iconColor: overrideVars.fontColor,
},
modalBox: {
closeColor: overrideVars.regularButtonStyles.textColor,
closeHoverBG: overrideVars.regularButtonStyles.hoverColor,
closeHoverColor: overrideVars.regularButtonStyles.hoverText,
containerColor: overrideVars.backgroundColor,
overlayColor: "#00000050",
titleColor: overrideVars.fontColor,
iconColor: {
default: overrideVars.fontColor,
accept: overrideVars.okColor,
delete: overrideVars.errorColor,
},
},
switchButton: {
bulletBGColor: overrideVars.switch.bulletBGColor,
bulletBorderColor: overrideVars.switch.bulletBorderColor,
disabledBulletBGColor: overrideVars.switch.disabledBulletBGColor,
disabledBulletBorderColor:
overrideVars.switch.disabledBulletBorderColor,
offLabelColor: overrideVars.secondaryFontColor,
onLabelColor: overrideVars.fontColor,
onBackgroundColor: overrideVars.okColor,
switchBackground: overrideVars.switch.switchBackground,
disabledBackground: overrideVars.switch.disabledBackground,
},
dropdownSelector: {
hoverText: overrideVars.buttonStyles.hoverText,
backgroundColor: overrideVars.boxBackground,
hoverBG: overrideVars.buttonStyles.hoverColor,
selectedBGColor: overrideVars.buttonStyles.hoverColor,
selectedTextColor: overrideVars.buttonStyles.hoverText,
optionTextColor: overrideVars.fontColor,
},
readBox: {
borderColor: overrideVars.borderColor,
backgroundColor: overrideVars.boxBackground,
textColor: overrideVars.fontColor,
},
};
} catch (e) {
console.warn("Invalid theme provided. Fallback to original theme.");
}
return retVal;
};

View File

@@ -21,6 +21,7 @@ import { bucketsElement } from "../utils/elements-menu";
import { testBucketBrowseButtonFor } from "../utils/functions";
import { Selector } from "testcafe";
import * as constants from "../utils/constants";
import { deleteAllVersions } from "../utils/elements";
fixture("For user with Bucket Read & Write permissions").page(
"http://localhost:9090"
@@ -52,7 +53,7 @@ test
"div.ReactVirtualized__Grid.ReactVirtualized__Table__Grid > div > div:nth-child(1)"
)
.click(elements.deleteButton)
.click(elements.switchInput)
.click(elements.deleteAllVersions)
.click(Selector("button:enabled").withExactText("Delete").nth(1))
.expect(
Selector(

View File

@@ -19,14 +19,10 @@ import { Selector } from "testcafe";
//----------------------------------------------------
// Buttons
//----------------------------------------------------
export const loginSubmitButton = Selector("form button");
export const closeAlertButton = Selector(
'button[class*="ModalError-closeButton"]'
export const uploadButton = Selector("button:enabled").withAttribute(
"id",
"upload-main"
);
export const uploadButton = Selector("span")
.withAttribute("aria-label", "Upload Files")
.child("button:enabled");
export const createPolicyButton =
Selector("button:enabled").withText("Create Policy");
export const saveButton = Selector("button:enabled").withText("Save");
@@ -55,6 +51,8 @@ export const assignPoliciesButton =
// Switches
//----------------------------------------------------
export const switchInput = Selector(".MuiSwitch-input");
export const deleteAllVersions =
Selector("#delete-versions").sibling("span.switchRail");
//----------------------------------------------------
// Inputs
@@ -109,11 +107,9 @@ export const groupStatusText = Selector("#group-status");
// Tables, table headers and content
//----------------------------------------------------
export const table = Selector(".ReactVirtualized__Table");
export const bucketsTableDisabled = Selector("#object-list-wrapper")
.find(".MuiPaper-root")
.withText(
"You require additional permissions in order to view Objects in this bucket. Please ask your MinIO administrator to grant you"
);
export const bucketsTableDisabled = Selector("#empty-results").withText(
"You require additional permissions in order to view Objects in this bucket. Please ask your MinIO administrator to grant you"
);
export const createGroupUserTable = Selector(
".MuiDialog-container .ReactVirtualized__Table"
);

View File

@@ -127,10 +127,6 @@ export const testBucketBrowseButtonFor = (modifier) => {
);
};
export const uploadFilesButton = () => {
return Selector("button").withText("Upload Files");
};
export const cleanUpNamedBucketAndUploads = (t, bucket) => {
return new Promise((resolve, reject) => {
const minioClient = new Minio.Client({

View File

@@ -50,12 +50,54 @@ type CustomButtonStyle struct {
HoverText *string `json:"hoverText"`
ActiveColor *string `json:"activeColor"`
ActiveText *string `json:"activeText"`
DisabledColor *string `json:"disabledColor"`
DisabledText *string `json:"disdabledText"`
}
type CustomTableStyle struct {
Border *string `json:"border"`
DisabledBorder *string `json:"disabledBorder"`
DisabledBG *string `json:"disabledBG"`
Selected *string `json:"selected"`
DeletedDisabled *string `json:"deletedDisabled"`
HoverColor *string `json:"hoverColor"`
}
type CustomInputStyle struct {
Border *string `json:"border"`
HoverBorder *string `json:"hoverBorder"`
TextColor *string `json:"textColor"`
BackgroundColor *string `json:"backgroundColor"`
}
type CustomSwitchStyle struct {
SwitchBackground *string `json:"switchBackground"`
BulletBorderColor *string `json:"bulletBorderColor"`
BulletBGColor *string `json:"bulletBGColor"`
DisabledBackground *string `json:"disabledBackground"`
DisabledBulletBorderColor *string `json:"disabledBulletBorderColor"`
DisabledBulletBGColor *string `json:"disabledBulletBGColor"`
}
type CustomStyles struct {
BackgroundColor *string `json:"backgroundColor"`
FontColor *string `json:"fontColor"`
ButtonStyles *CustomButtonStyle `json:"buttonStyles"`
BackgroundColor *string `json:"backgroundColor"`
FontColor *string `json:"fontColor"`
SecondaryFontColor *string `json:"secondaryFontColor"`
BorderColor *string `json:"borderColor"`
LoaderColor *string `json:"loaderColor"`
BoxBackground *string `json:"boxBackground"`
OkColor *string `json:"okColor"`
ErrorColor *string `json:"errorColor"`
WarnColor *string `json:"warnColor"`
LinkColor *string `json:"linkColor"`
DisabledLinkColor *string `json:"disabledLinkColor"`
HoverLinkColor *string `json:"hoverLinkColor"`
ButtonStyles *CustomButtonStyle `json:"buttonStyles"`
SecondaryButtonStyles *CustomButtonStyle `json:"secondaryButtonStyles"`
RegularButtonStyles *CustomButtonStyle `json:"regularButtonStyles"`
TableColors *CustomTableStyle `json:"tableColors"`
InputBox *CustomInputStyle `json:"inputBox"`
Switch *CustomSwitchStyle `json:"switch"`
}
func RandomCharStringWithAlphabet(n int, alphabet string) string {
@@ -163,7 +205,7 @@ func ValidateEncodedStyles(encodedStyles string) error {
return err
}
if styleElements.BackgroundColor == nil || styleElements.FontColor == nil || styleElements.ButtonStyles == nil {
if styleElements.BackgroundColor == nil || styleElements.FontColor == nil || styleElements.ButtonStyles == nil || styleElements.BorderColor == nil || styleElements.OkColor == nil {
return errors.New("specified style is not in the correct format")
}

View File

@@ -257,7 +257,7 @@ func TestValidateEncodedStyles(t *testing.T) {
{
name: "valid",
args: args{
encodedStyles: "ewogICJiYWNrZ3JvdW5kQ29sb3IiOiAiIzI3ODdjNiIsCiAgImZvbnRDb2xvciI6ICIjZmYwIiwKICAiYnV0dG9uU3R5bGVzIjogewogICAgImJhY2tncm91bmRDb2xvciI6ICIjZWRlYWE4IiwKICAgICJ0ZXh0Q29sb3IiOiAiIzJiMmEyYSIsCiAgICAiaG92ZXJDb2xvciI6ICIjZWRlYWE4IiwKICAgICJob3ZlclRleHQiOiAiIzJiMmEyYSIsCiAgICAiYWN0aXZlQ29sb3IiOiAiI2VkZWFhOCIsCiAgICAiYWN0aXZlVGV4dCI6ICIjMmIyYTJhIgogIH0KfQ==",
encodedStyles: "ewogICJiYWNrZ3JvdW5kQ29sb3IiOiAiIzFjMWMxYyIsCiAgImZvbnRDb2xvciI6ICJ3aGl0ZSIsCiAgInNlY29uZGFyeUZvbnRDb2xvciI6ICJncmV5IiwKICAiYm9yZGVyQ29sb3IiOiAieWVsbG93IiwKICAibG9hZGVyQ29sb3IiOiAicmVkIiwKICAiYm94QmFja2dyb3VuZCI6ICIjMDU3OWFmIiwKICAib2tDb2xvciI6ICIjMDhhZjA1IiwKICAiZXJyb3JDb2xvciI6ICIjYmYxZTQ2IiwKICAid2FybkNvbG9yIjogIiNiZmFjMWUiLAogICJsaW5rQ29sb3IiOiAiIzFlYmZiZiIsCiAgImRpc2FibGVkTGlua0NvbG9yIjogIiM5ZGEwYTAiLAogICJob3ZlckxpbmtDb2xvciI6ICIjMGY0ZWJjIiwKICAidGFibGVDb2xvcnMiOiB7CiAgICAiYm9yZGVyIjogIiM0YmJjMGYiLAogICAgImRpc2FibGVkQm9yZGVyIjogIiM3MjhlNjMiLAogICAgImRpc2FibGVkQkciOiAiIzcyOGU2MyIsCiAgICAic2VsZWN0ZWQiOiAiIzU1ZGIwZCIsCiAgICAiZGVsZXRlZERpc2FibGVkIjogIiNlYWI2ZDAiLAogICAgImhvdmVyQ29sb3IiOiAiIzAwZmZmNiIKICB9LAogICJidXR0b25TdHlsZXMiOiB7CiAgICAiYmFja2dyb3VuZENvbG9yIjogIiMwMDczZmYiLAogICAgInRleHRDb2xvciI6ICIjZmZmZmZmIiwKICAgICJob3ZlckNvbG9yIjogIiMyYjhlZmYiLAogICAgImhvdmVyVGV4dCI6ICIjZmZmIiwKICAgICJhY3RpdmVDb2xvciI6ICIjMzg4M2Q4IiwKICAgICJhY3RpdmVUZXh0IjogIiNmZmYiLAogICAgImRpc2FibGVkQ29sb3IiOiAiIzc1OGU4ZCIsCiAgICAiZGlzYWJsZWRUZXh0IjogIiNkOWRkZGQiCiAgfSwKICAic2Vjb25kYXJ5QnV0dG9uU3R5bGVzIjogewogICAgImJhY2tncm91bmRDb2xvciI6ICIjZWEzMzc5IiwKICAgICJ0ZXh0Q29sb3IiOiAiI2VhMzM3OSIsCiAgICAiaG92ZXJDb2xvciI6ICIjZWEzMzAwIiwKICAgICJob3ZlclRleHQiOiAiI2VhMzMwMCIsCiAgICAiYWN0aXZlQ29sb3IiOiAiI2VhMzM3OSIsCiAgICAiYWN0aXZlVGV4dCI6ICIjM2NlYTMzIiwKICAgICJkaXNhYmxlZENvbG9yIjogIiM3ODdjNzciLAogICAgImRpc2FibGVkVGV4dCI6ICIjNzg3Yzc3IgogIH0sCiAgInJlZ3VsYXJCdXR0b25TdHlsZXMiOiB7CiAgICAiYmFja2dyb3VuZENvbG9yIjogIiMwMDczZmYiLAogICAgInRleHRDb2xvciI6ICIjMDA3M2ZmIiwKICAgICJob3ZlckNvbG9yIjogIiMyYjhlZmYiLAogICAgImhvdmVyVGV4dCI6ICIjMDA3M2ZmIiwKICAgICJhY3RpdmVDb2xvciI6ICIjMzg4M2Q4IiwKICAgICJhY3RpdmVUZXh0IjogIiMwMDczZmYiLAogICAgImRpc2FibGVkQ29sb3IiOiAiIzc1OGU4ZCIsCiAgICAiZGlzYWJsZWRUZXh0IjogIiNkOWRkZGQiCiAgfSwKICAiaW5wdXRCb3giOiB7CiAgICAiYm9yZGVyIjogImdyZWVuIiwKICAgICJob3ZlckJvcmRlciI6ICJibHVlIiwKICAgICJ0ZXh0Q29sb3IiOiAid2hpdGUiLAogICAgImJhY2tncm91bmRDb2xvciI6ICIjMjhkNGZmIgogIH0sCiAgInN3aXRjaCI6IHsKICAgICJzd2l0Y2hCYWNrZ3JvdW5kIjogIiMyOGQ0ZmYiLAogICAgImJ1bGxldEJvcmRlckNvbG9yIjogIiNhNmFjYWQiLAogICAgImJ1bGxldEJHQ29sb3IiOiAiI2RjZTFlMiIsCiAgICAiZGlzYWJsZWRCYWNrZ3JvdW5kIjogIiM0NzQ5NDkiLAogICAgImRpc2FibGVkQnVsbGV0Qm9yZGVyQ29sb3IiOiAiIzQ3NDk0OSIsCiAgICAiZGlzYWJsZWRCdWxsZXRCR0NvbG9yIjogIiM3Mzk3YTAiCiAgfQp9",
},
wantErr: false,
},