Changed breadcrumbs styles (#1610)
- Added onKey press support to input boxes - Added enter key support to create path modal - Replaced bucket icon Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
37
portal-ui/src/icons/BackCaretIcon.tsx
Normal file
37
portal-ui/src/icons/BackCaretIcon.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 * as React from "react";
|
||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const BackCaretIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className={`min-icon`}
|
||||||
|
fill={"currentcolor"}
|
||||||
|
viewBox="0 0 256 256"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<g id="noun_chevron_2320228" transform="translate(5.595 10) rotate(180)">
|
||||||
|
<path id="Path_6842" d="M-178.01,7.8c-3.9-0.03-7.62-1.63-10.34-4.43c-5.81-5.68-5.92-15-0.25-20.81
|
||||||
|
c0.08-0.08,0.16-0.16,0.25-0.25l100.13-100.13l-100.13-100.48c-5.81-5.68-5.92-15-0.25-20.81c0.08-0.08,0.16-0.16,0.25-0.25
|
||||||
|
c5.68-5.81,15-5.92,20.81-0.25c0.08,0.08,0.16,0.16,0.25,0.25l110.82,110.82c2.8,2.72,4.39,6.44,4.43,10.34
|
||||||
|
c0.11,3.93-1.51,7.71-4.43,10.34L-167.29,2.99C-170.07,5.97-173.93,7.71-178.01,7.8z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default BackCaretIcon;
|
||||||
@@ -25,19 +25,12 @@ const BucketsIcon = (props: SVGProps<SVGSVGElement>) => (
|
|||||||
viewBox="0 0 256 256"
|
viewBox="0 0 256 256"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<defs>
|
<g>
|
||||||
<clipPath id="prefix__a">
|
|
||||||
<path d="M0 0h256v256H0z" />
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
<g clipPath="url(#prefix__a)">
|
|
||||||
<path fill="none" d="M0 0h256v256H0z" />
|
|
||||||
<path data-name="Rect\xE1ngulo 884" fill="none" d="M0 0h256v256H0z" />
|
|
||||||
<path
|
<path
|
||||||
data-name="buckets-icn"
|
d="M244.1,8.4c-3.9-5.3-10.1-8.5-16.7-8.5H21.6C15,0,8.8,3.1,4.9,8.4C0.8,14-0.9,21,0.3,27.9
|
||||||
d="m244.998 90.474.049-.243 10.563-61.472a25.8 25.8 0 0 0-4.748-19.986A21.518 21.518 0 0 0 233.739 0H22.255A21.507 21.507 0 0 0 5.138 8.773 25.862 25.862 0 0 0 .384 28.759c5.223 30.384 16.209 94.421 25 145.533l.014.1c4.457 26 8.338 48.644 10.617 61.787 1.965 11.487 11.148 19.819 21.854 19.819h140.264c10.713 0 19.875-8.332 21.861-19.819l10.592-61.711.076-.375Zm-203.928 72.5c-3.6-20.981-7.479-43.648-11.148-65.015H226.09l-11.168 65.015Zm197.482-137.7-9.2 53.735h-202.7c-3.7-21.626-7-40.758-9.221-53.735a5.736 5.736 0 0 1 1.041-4.394 4.738 4.738 0 0 1 3.764-1.934h211.5a4.732 4.732 0 0 1 3.775 1.939 5.691 5.691 0 0 1 1.042 4.387Zm-26.893 156.649-8.709 50.763a5.048 5.048 0 0 1-4.824 4.37H57.862a5.047 5.047 0 0 1-4.816-4.361c-1.93-11.25-5.066-29.464-8.717-50.771Z"
|
c5.1,29.6,15.8,91.9,24.3,141.7v0.1C29,195,32.8,217.1,35,229.9c1.4,10.8,10.4,18.9,21.3,19.3h136.5
|
||||||
stroke="#000"
|
c10.9-0.4,19.9-8.5,21.3-19.3l10.3-60.1l0.1-0.4L238.4,88v-0.2l10.3-59.9C249.9,21,248.3,14,244.1,8.4 M206.1,177h-163
|
||||||
strokeWidth={0.2}
|
l-3.2-18.6h169.3L206.1,177z M220,95.3H28.9l-3.2-18.6h197.4L220,95.3z"
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This file is part of MinIO Console Server
|
// This file is part of MinIO Console Server
|
||||||
// Copyright (c) 2021 MinIO, Inc.
|
// Copyright (c) 2022 MinIO, Inc.
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -25,17 +25,11 @@ const FolderIcon = (props: SVGProps<SVGSVGElement>) => (
|
|||||||
viewBox="0 0 256 256"
|
viewBox="0 0 256 256"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<defs>
|
<g>
|
||||||
<clipPath id="prefix__a">
|
<path d="M235.3,72.5c-0.2-15.5-12.8-27.9-28.3-27.9h-78l-1.1-1.5c-5.1-9.3-14.5-15.5-25.1-16.6h-50c-15.6,0-28.3,12.6-28.3,28.3
|
||||||
<path d="M0 0h256v256H0z" />
|
c0,1,0.1,2,0.2,3v12.9c-11.6,3.9-19.4,14.8-19.4,27c0,0.6,0,1.2,0.1,1.7L14.8,202c0.6,15.4,13.2,27.5,28.6,27.5h168.9
|
||||||
</clipPath>
|
c15.4,0,28-12.1,28.6-27.5l9.5-102.5c0-0.6,0.1-1.2,0.1-1.8C250.6,87.1,244.7,77.4,235.3,72.5z M32.5,88.4c11.7-3.3,12-11,12-11
|
||||||
</defs>
|
h172c0.2,4.6,2.9,8.8,6.9,11H32.5z"/>
|
||||||
<g clipPath="url(#prefix__a)">
|
|
||||||
<path fill="none" d="M0 0h256v256H0z" />
|
|
||||||
<g data-name="folder-icn{">
|
|
||||||
<path d="M101.729 42.952c6.612 0 13.7 18.758 20.78 18.758h88.049a9.441 9.441 0 0 1 9.444 9.379v4.689H40.349V52.33h-.236a9.441 9.441 0 0 1 9.448-9.378h52.168m124.4 44.255a9.778 9.778 0 0 1 9.774 9.725L225.885 204.09a9.788 9.788 0 0 1-9.794 9.716H39.679a9.781 9.781 0 0 1-9.786-9.716l-9.79-107.158a9.781 9.781 0 0 1 9.79-9.725h196.236M101.729 23H49.561a29.469 29.469 0 0 0-29.544 29.33 20.109 20.109 0 0 0 .236 3.063v13.438A29.758 29.758 0 0 0 0 96.931c0 .6.031 1.2.09 1.8l9.723 106.5a29.827 29.827 0 0 0 29.862 28.532h176.412a29.833 29.833 0 0 0 29.862-28.5l9.959-106.484a17.091 17.091 0 0 0 .091-1.847 29.673 29.673 0 0 0-15.911-26.229 29.477 29.477 0 0 0-29.532-28.949h-81.5c-.4-.529-.787-1.05-1.117-1.5-5.1-6.87-12.815-17.248-26.208-17.248Z" />
|
|
||||||
<path data-name="Rect\xE1ngulo 874" fill="none" d="M0 0h256v256H0z" />
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -166,3 +166,4 @@ export { default as ConsoleIcon } from "./ConsoleIcon";
|
|||||||
export { default as FileVideoIcon } from "./FileVideoIcon";
|
export { default as FileVideoIcon } from "./FileVideoIcon";
|
||||||
export { default as ChangePasswordIcon } from "./ChangePasswordIcon";
|
export { default as ChangePasswordIcon } from "./ChangePasswordIcon";
|
||||||
export { default as LockIcon } from "./LockIcon";
|
export { default as LockIcon } from "./LockIcon";
|
||||||
|
export { default as BackCaretIcon } from "./BackCaretIcon";
|
||||||
|
|||||||
@@ -102,6 +102,16 @@ const CreateFolderModal = ({
|
|||||||
setIsFormValid(valid);
|
setIsFormValid(valid);
|
||||||
}, [pathUrl]);
|
}, [pathUrl]);
|
||||||
|
|
||||||
|
const inputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPathUrl(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyPressed = (e: any) => {
|
||||||
|
if(e.code === "Enter" && pathUrl !== "") {
|
||||||
|
createProcess();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<ModalWrapper
|
<ModalWrapper
|
||||||
@@ -121,9 +131,8 @@ const CreateFolderModal = ({
|
|||||||
id={"folderPath"}
|
id={"folderPath"}
|
||||||
name={"folderPath"}
|
name={"folderPath"}
|
||||||
placeholder={"Enter the new Folder Path"}
|
placeholder={"Enter the new Folder Path"}
|
||||||
onChange={(e) => {
|
onChange={inputChange}
|
||||||
setPathUrl(e.target.value);
|
onKeyPress={keyPressed}
|
||||||
}}
|
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -102,9 +102,6 @@ import ObjectDetailPanel from "./ObjectDetailPanel";
|
|||||||
import RBIconButton from "../../../BucketDetails/SummaryItems/RBIconButton";
|
import RBIconButton from "../../../BucketDetails/SummaryItems/RBIconButton";
|
||||||
import MultiSelectionPanel from "./MultiSelectionPanel";
|
import MultiSelectionPanel from "./MultiSelectionPanel";
|
||||||
|
|
||||||
const AddFolderIcon = React.lazy(
|
|
||||||
() => import("../../../../../../icons/AddFolderIcon")
|
|
||||||
);
|
|
||||||
const HistoryIcon = React.lazy(
|
const HistoryIcon = React.lazy(
|
||||||
() => import("../../../../../../icons/HistoryIcon")
|
() => import("../../../../../../icons/HistoryIcon")
|
||||||
);
|
);
|
||||||
@@ -115,9 +112,7 @@ const RefreshIcon = React.lazy(
|
|||||||
const DeleteIcon = React.lazy(
|
const DeleteIcon = React.lazy(
|
||||||
() => import("../../../../../../icons/DeleteIcon")
|
() => import("../../../../../../icons/DeleteIcon")
|
||||||
);
|
);
|
||||||
const CreateFolderModal = withSuspense(
|
|
||||||
React.lazy(() => import("./CreateFolderModal"))
|
|
||||||
);
|
|
||||||
const DeleteMultipleObjects = withSuspense(
|
const DeleteMultipleObjects = withSuspense(
|
||||||
React.lazy(() => import("./DeleteMultipleObjects"))
|
React.lazy(() => import("./DeleteMultipleObjects"))
|
||||||
);
|
);
|
||||||
@@ -169,6 +164,22 @@ const styles = (theme: Theme) =>
|
|||||||
...searchField.searchField,
|
...searchField.searchField,
|
||||||
maxWidth: 380,
|
maxWidth: 380,
|
||||||
},
|
},
|
||||||
|
screenTitleContainer: {
|
||||||
|
border: "#EAEDEE 1px solid",
|
||||||
|
borderBottom: 0,
|
||||||
|
padding: "0.8rem 15px 0",
|
||||||
|
},
|
||||||
|
titleSpacer: {
|
||||||
|
marginLeft: 10,
|
||||||
|
},
|
||||||
|
listIcon: {
|
||||||
|
display: "block",
|
||||||
|
marginTop: "-10px",
|
||||||
|
"& .min-icon": {
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
}
|
||||||
|
},
|
||||||
...objectBrowserCommon,
|
...objectBrowserCommon,
|
||||||
...containerForHeader(theme.spacing(4)),
|
...containerForHeader(theme.spacing(4)),
|
||||||
});
|
});
|
||||||
@@ -269,7 +280,6 @@ const ListObjects = ({
|
|||||||
const [rewind, setRewind] = useState<RewindObject[]>([]);
|
const [rewind, setRewind] = useState<RewindObject[]>([]);
|
||||||
const [loadingRewind, setLoadingRewind] = useState<boolean>(false);
|
const [loadingRewind, setLoadingRewind] = useState<boolean>(false);
|
||||||
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
|
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
|
||||||
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
|
|
||||||
const [loadingStartTime, setLoadingStartTime] = useState<number>(0);
|
const [loadingStartTime, setLoadingStartTime] = useState<number>(0);
|
||||||
const [loadingMessage, setLoadingMessage] =
|
const [loadingMessage, setLoadingMessage] =
|
||||||
useState<React.ReactNode>(defLoading);
|
useState<React.ReactNode>(defLoading);
|
||||||
@@ -372,12 +382,12 @@ const ListObjects = ({
|
|||||||
|
|
||||||
if (timeDelta / 1000 >= 6) {
|
if (timeDelta / 1000 >= 6) {
|
||||||
setLoadingMessage(
|
setLoadingMessage(
|
||||||
<React.Fragment>
|
<Fragment>
|
||||||
<Typography component="h3">
|
<Typography component="h3">
|
||||||
This operation is taking longer than expected... (
|
This operation is taking longer than expected... (
|
||||||
{Math.ceil(timeDelta / 1000)}s)
|
{Math.ceil(timeDelta / 1000)}s)
|
||||||
</Typography>
|
</Typography>
|
||||||
</React.Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
} else if (timeDelta / 1000 >= 3) {
|
} else if (timeDelta / 1000 >= 3) {
|
||||||
setLoadingMessage(
|
setLoadingMessage(
|
||||||
@@ -656,9 +666,7 @@ const ListObjects = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeAddFolderModal = () => {
|
|
||||||
setCreateFolderOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUploadButton = (e: any) => {
|
const handleUploadButton = (e: any) => {
|
||||||
if (
|
if (
|
||||||
@@ -1167,7 +1175,7 @@ const ListObjects = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<Fragment>
|
||||||
{shareFileModalOpen && selectedPreview && (
|
{shareFileModalOpen && selectedPreview && (
|
||||||
<ShareFile
|
<ShareFile
|
||||||
open={shareFileModalOpen}
|
open={shareFileModalOpen}
|
||||||
@@ -1189,15 +1197,6 @@ const ListObjects = ({
|
|||||||
versioning={isVersioned}
|
versioning={isVersioned}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{createFolderOpen && (
|
|
||||||
<CreateFolderModal
|
|
||||||
modalOpen={createFolderOpen}
|
|
||||||
bucketName={bucketName}
|
|
||||||
folderName={internalPaths}
|
|
||||||
onClose={closeAddFolderModal}
|
|
||||||
existingFiles={records}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{rewindSelect && (
|
{rewindSelect && (
|
||||||
<RewindEnable
|
<RewindEnable
|
||||||
open={rewindSelect}
|
open={rewindSelect}
|
||||||
@@ -1214,21 +1213,15 @@ const ListObjects = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12} className={classes.screenTitleContainer}>
|
||||||
<ScreenTitle
|
<ScreenTitle
|
||||||
className={classes.screenTitle}
|
className={classes.screenTitle}
|
||||||
icon={
|
icon={
|
||||||
<Fragment>
|
<span className={classes.listIcon}>
|
||||||
<BucketsIcon width={40} />
|
<BucketsIcon />
|
||||||
</Fragment>
|
</span>
|
||||||
}
|
|
||||||
title={
|
|
||||||
<BrowserBreadcrumbs
|
|
||||||
bucketName={bucketName}
|
|
||||||
internalPaths={pageTitle}
|
|
||||||
fullSizeBreadcrumbs
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
title={<span className={classes.titleSpacer}>{bucketName}</span>}
|
||||||
subTitle={
|
subTitle={
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Grid item xs={12} className={classes.bucketDetails}>
|
<Grid item xs={12} className={classes.bucketDetails}>
|
||||||
@@ -1266,21 +1259,6 @@ const ListObjects = ({
|
|||||||
}
|
}
|
||||||
actions={
|
actions={
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<RBIconButton
|
|
||||||
id={"new-path"}
|
|
||||||
tooltip={"Choose or create a new path"}
|
|
||||||
text={"New Path"}
|
|
||||||
icon={<AddFolderIcon />}
|
|
||||||
color="primary"
|
|
||||||
variant={"outlined"}
|
|
||||||
onClick={() => {
|
|
||||||
setCreateFolderOpen(true);
|
|
||||||
}}
|
|
||||||
disabled={
|
|
||||||
rewindEnabled ||
|
|
||||||
!hasPermission(bucketName, [IAM_SCOPES.S3_PUT_OBJECT])
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<RBIconButton
|
<RBIconButton
|
||||||
id={"rewind-objects-list"}
|
id={"rewind-objects-list"}
|
||||||
tooltip={"Rewind Bucket"}
|
tooltip={"Rewind Bucket"}
|
||||||
@@ -1292,6 +1270,7 @@ const ListObjects = ({
|
|||||||
variant="dot"
|
variant="dot"
|
||||||
invisible={!rewindEnabled}
|
invisible={!rewindEnabled}
|
||||||
className={classes.badgeOverlap}
|
className={classes.badgeOverlap}
|
||||||
|
sx={{height: 12}}
|
||||||
>
|
>
|
||||||
<HistoryIcon />
|
<HistoryIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -1355,6 +1334,13 @@ const ListObjects = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<BrowserBreadcrumbs
|
||||||
|
bucketName={bucketName}
|
||||||
|
internalPaths={pageTitle}
|
||||||
|
existingFiles={records || []}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
<div
|
<div
|
||||||
id="object-list-wrapper"
|
id="object-list-wrapper"
|
||||||
{...getRootProps({ style: { ...dndStyles } })}
|
{...getRootProps({ style: { ...dndStyles } })}
|
||||||
@@ -1414,7 +1400,7 @@ const ListObjects = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</React.Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import {
|
|||||||
import { decodeFileName, encodeFileName } from "../../../../../../common/utils";
|
import { decodeFileName, encodeFileName } from "../../../../../../common/utils";
|
||||||
import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
|
import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
|
||||||
import SetRetention from "./SetRetention";
|
import SetRetention from "./SetRetention";
|
||||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
|
||||||
import DeleteObject from "../ListObjects/DeleteObject";
|
import DeleteObject from "../ListObjects/DeleteObject";
|
||||||
import AddTagModal from "./AddTagModal";
|
import AddTagModal from "./AddTagModal";
|
||||||
import DeleteTagModal from "./DeleteTagModal";
|
import DeleteTagModal from "./DeleteTagModal";
|
||||||
@@ -518,14 +517,6 @@ const ObjectDetails = ({
|
|||||||
? objectNameArray[objectNameArray.length - 1]
|
? objectNameArray[objectNameArray.length - 1]
|
||||||
: actualInfo.name
|
: actualInfo.name
|
||||||
}
|
}
|
||||||
subTitle={
|
|
||||||
<Fragment>
|
|
||||||
<BrowserBreadcrumbs
|
|
||||||
bucketName={bucketName}
|
|
||||||
internalPaths={actualInfo.name}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
}
|
|
||||||
actions={
|
actions={
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<SecureComponent
|
<SecureComponent
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ interface InputBoxProps {
|
|||||||
label: string;
|
label: string;
|
||||||
classes: any;
|
classes: any;
|
||||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
onKeyPress?: (e: any) => void;
|
||||||
value: string | boolean;
|
value: string | boolean;
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -133,6 +134,7 @@ const InputBoxWrapper = ({
|
|||||||
autoFocus = false,
|
autoFocus = false,
|
||||||
classes,
|
classes,
|
||||||
className = "",
|
className = "",
|
||||||
|
onKeyPress,
|
||||||
}: InputBoxProps) => {
|
}: InputBoxProps) => {
|
||||||
let inputProps: any = { "data-index": index, ...extraInputProps };
|
let inputProps: any = { "data-index": index, ...extraInputProps };
|
||||||
|
|
||||||
@@ -197,6 +199,7 @@ const InputBoxWrapper = ({
|
|||||||
helperText={error}
|
helperText={error}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className={classes.inputRebase}
|
className={classes.inputRebase}
|
||||||
|
onKeyPress={onKeyPress}
|
||||||
/>
|
/>
|
||||||
{overlayIcon && (
|
{overlayIcon && (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -361,20 +361,27 @@ export const objectBrowserCommon = {
|
|||||||
lineHeight: "40px",
|
lineHeight: "40px",
|
||||||
},
|
},
|
||||||
breadcrumbs: {
|
breadcrumbs: {
|
||||||
fontSize: 10,
|
fontSize: 12,
|
||||||
color: "#000",
|
color: "#969FA8",
|
||||||
|
fontWeight: "bold",
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
|
border: "#EAEDEE 1px solid",
|
||||||
|
borderBottom: 0,
|
||||||
|
height: 38,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
backgroundColor: "#FCFCFD",
|
||||||
"& a": {
|
"& a": {
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
color: "#000",
|
color: "#969FA8",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
textDecoration: "underline",
|
textDecoration: "underline",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"&.fullSize": {
|
"& .min-icon": {
|
||||||
fontSize: 18,
|
width: 14,
|
||||||
marginLeft: 10,
|
minWidth: 14,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
smallLabel: {
|
smallLabel: {
|
||||||
color: "#9C9C9C",
|
color: "#9C9C9C",
|
||||||
@@ -388,6 +395,17 @@ export const objectBrowserCommon = {
|
|||||||
detailsSpacer: {
|
detailsSpacer: {
|
||||||
marginRight: 18,
|
marginRight: 18,
|
||||||
},
|
},
|
||||||
|
breadcrumbsList: {
|
||||||
|
textOverflow: "ellipsis" as const,
|
||||||
|
overflow: "hidden" as const,
|
||||||
|
whiteSpace: "nowrap" as const,
|
||||||
|
display: "inline-block" as const,
|
||||||
|
flexGrow: 1,
|
||||||
|
textAlign: "left" as const,
|
||||||
|
marginLeft: 15,
|
||||||
|
marginRight: 10,
|
||||||
|
lineHeight: 35,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectorsCommon = {
|
export const selectorsCommon = {
|
||||||
|
|||||||
@@ -14,10 +14,9 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React from "react";
|
import React, { Fragment, useState } from "react";
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import Moment from "react-moment";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import withStyles from "@mui/styles/withStyles";
|
import withStyles from "@mui/styles/withStyles";
|
||||||
import { Theme } from "@mui/material/styles";
|
import { Theme } from "@mui/material/styles";
|
||||||
@@ -26,6 +25,19 @@ import { ObjectBrowserState } from "./reducers";
|
|||||||
import { objectBrowserCommon } from "../Common/FormComponents/common/styleLibrary";
|
import { objectBrowserCommon } from "../Common/FormComponents/common/styleLibrary";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { encodeFileName } from "../../../common/utils";
|
import { encodeFileName } from "../../../common/utils";
|
||||||
|
import { BackCaretIcon, FolderIcon } from "../../../icons";
|
||||||
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
|
import history from "../../../history";
|
||||||
|
import { hasPermission } from "../../../common/SecureComponent";
|
||||||
|
import { IAM_SCOPES } from "../../../common/SecureComponent/permissions";
|
||||||
|
import withSuspense from "../Common/Components/withSuspense";
|
||||||
|
import { BucketObject } from "../Buckets/ListBuckets/Objects/ListObjects/types";
|
||||||
|
|
||||||
|
const CreateFolderModal = withSuspense(
|
||||||
|
React.lazy(
|
||||||
|
() => import("../Buckets/ListBuckets/Objects/ListObjects/CreateFolderModal")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
interface ObjectBrowserReducer {
|
interface ObjectBrowserReducer {
|
||||||
objectBrowser: ObjectBrowserState;
|
objectBrowser: ObjectBrowserState;
|
||||||
@@ -37,7 +49,7 @@ interface IObjectBrowser {
|
|||||||
internalPaths: string;
|
internalPaths: string;
|
||||||
rewindEnabled?: boolean;
|
rewindEnabled?: boolean;
|
||||||
rewindDate?: any;
|
rewindDate?: any;
|
||||||
fullSizeBreadcrumbs?: boolean;
|
existingFiles: BucketObject[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
const styles = (theme: Theme) =>
|
||||||
@@ -51,8 +63,10 @@ const BrowserBreadcrumbs = ({
|
|||||||
internalPaths,
|
internalPaths,
|
||||||
rewindEnabled,
|
rewindEnabled,
|
||||||
rewindDate,
|
rewindDate,
|
||||||
fullSizeBreadcrumbs,
|
existingFiles,
|
||||||
}: IObjectBrowser) => {
|
}: IObjectBrowser) => {
|
||||||
|
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
let paths = internalPaths;
|
let paths = internalPaths;
|
||||||
|
|
||||||
if (internalPaths !== "") {
|
if (internalPaths !== "") {
|
||||||
@@ -60,52 +74,83 @@ const BrowserBreadcrumbs = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const splitPaths = paths.split("/").filter((path) => path !== "");
|
const splitPaths = paths.split("/").filter((path) => path !== "");
|
||||||
const listBreadcrumbs = splitPaths.map(
|
let breadcrumbsMap = splitPaths.map((objectItem: string, index: number) => {
|
||||||
(objectItem: string, index: number) => {
|
const subSplit = splitPaths.slice(0, index + 1).join("/");
|
||||||
const subSplit = splitPaths.slice(0, index + 1).join("/");
|
const route = `/buckets/${bucketName}/browse/${
|
||||||
const route = `/buckets/${bucketName}/browse/${
|
subSplit ? `${encodeFileName(subSplit)}` : ``
|
||||||
subSplit ? `${encodeFileName(subSplit)}` : ``
|
}`;
|
||||||
}`;
|
return (
|
||||||
return (
|
<Fragment key={`breadcrumbs-${index.toString()}`}>
|
||||||
<React.Fragment key={`breadcrumbs-${index.toString()}`}>
|
<span> / </span>
|
||||||
<Link to={route}>{objectItem}</Link>
|
<Link to={route}>{objectItem}</Link>
|
||||||
{index < splitPaths.length - 1 && <span> / </span>}
|
</Fragment>
|
||||||
</React.Fragment>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
);
|
const listBreadcrumbs: any[] = [
|
||||||
|
<Fragment key={`breadcrumbs-root-path`}>
|
||||||
|
<Link to={`/buckets/${bucketName}/browse`}>{bucketName}</Link>
|
||||||
|
</Fragment>,
|
||||||
|
...breadcrumbsMap,
|
||||||
|
];
|
||||||
|
|
||||||
|
const closeAddFolderModal = () => {
|
||||||
|
setCreateFolderOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const title = false;
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{title && (
|
{createFolderOpen && (
|
||||||
<Grid item xs={12}>
|
<CreateFolderModal
|
||||||
<div className={classes.sectionTitle}>
|
modalOpen={createFolderOpen}
|
||||||
{splitPaths && splitPaths.length > 0
|
bucketName={bucketName}
|
||||||
? splitPaths[splitPaths.length - 1]
|
folderName={internalPaths}
|
||||||
: ""}
|
onClose={closeAddFolderModal}
|
||||||
{rewindEnabled && splitPaths.length > 1 && (
|
existingFiles={existingFiles}
|
||||||
<small className={classes.smallLabel}>
|
/>
|
||||||
(Rewind:{" "}
|
|
||||||
<Moment date={rewindDate} format="MMMM Do YYYY, h:mm a" /> )
|
|
||||||
</small>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
)}
|
)}
|
||||||
|
<Grid item xs={12} className={`${classes.breadcrumbs}`}>
|
||||||
<Grid
|
<IconButton
|
||||||
item
|
onClick={() => {
|
||||||
xs={12}
|
history.goBack();
|
||||||
className={`${classes.breadcrumbs} ${
|
}}
|
||||||
fullSizeBreadcrumbs ? "fullSize" : ""
|
sx={{
|
||||||
}`}
|
border: "#EAEDEE 1px solid",
|
||||||
>
|
backgroundColor: "#fff",
|
||||||
<React.Fragment>
|
borderLeft: 0,
|
||||||
<Link to={`/buckets/${bucketName}/browse`}>{bucketName}</Link>
|
borderBottom: 0,
|
||||||
{listBreadcrumbs.length > 0 && <span> / </span>}
|
borderRadius: 0,
|
||||||
</React.Fragment>
|
width: 39,
|
||||||
{listBreadcrumbs}
|
height: 39,
|
||||||
|
marginRight: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BackCaretIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Tooltip title={"Choose or create a new path"}>
|
||||||
|
<IconButton
|
||||||
|
id={"new-path"}
|
||||||
|
onClick={() => {
|
||||||
|
setCreateFolderOpen(true);
|
||||||
|
}}
|
||||||
|
disabled={
|
||||||
|
rewindEnabled ||
|
||||||
|
!hasPermission(bucketName, [IAM_SCOPES.S3_PUT_OBJECT])
|
||||||
|
}
|
||||||
|
disableTouchRipple
|
||||||
|
disableRipple
|
||||||
|
focusRipple={false}
|
||||||
|
sx={{
|
||||||
|
padding: 0,
|
||||||
|
paddingLeft: "6px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FolderIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<div className={classes.breadcrumbsList} dir="rtl">
|
||||||
|
{listBreadcrumbs}
|
||||||
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user