Improvements for download / upload manager (#1933)
- Changed styles on progress bars & items - Fixed some issues in error state & handling - Added cancel capability to objects - Added visual indicators when new objects are added to pool Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
32
portal-ui/src/icons/CancelledIcon.tsx
Normal file
32
portal-ui/src/icons/CancelledIcon.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 CancelledIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={`min-icon`}
|
||||
fill={"currentcolor"}
|
||||
viewBox="0 0 256 256"
|
||||
{...props}
|
||||
>
|
||||
<path d="M126.09,0C56.45,0,0,56.45,0,126.09s56.45,126.09,126.09,126.09,126.09-56.45,126.09-126.09S195.72,0,126.09,0Zm79.61,146.23H46.48c-11.08,0-20.14-9.07-20.14-20.14h0c0-11.08,9.07-20.14,20.14-20.14H205.7c11.08,0,20.14,9.07,20.14,20.14h0c0,11.08-9.07,20.14-20.14,20.14Z"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default CancelledIcon;
|
||||
@@ -25,37 +25,12 @@ const DisabledIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
viewBox="0 0 16 16"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<clipPath id="disabled-clip-path">
|
||||
<rect
|
||||
id="Rectángulo_1068"
|
||||
data-name="Rectángulo 1068"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect
|
||||
id="Rectángulo_1065"
|
||||
data-name="Rectángulo 1065"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
/>
|
||||
<g id="Grupo_2455" data-name="Grupo 2455">
|
||||
<g
|
||||
id="Grupo_2454"
|
||||
data-name="Grupo 2454"
|
||||
clipPath="url(#disabled-clip-path)"
|
||||
>
|
||||
<path
|
||||
id="Trazado_7232"
|
||||
data-name="Trazado 7232"
|
||||
d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0m3.235,5.4L8.965,8.174,10.949,10.6a.857.857,0,0,1-1.327,1.086h0L7.857,9.528,6.092,11.686A.857.857,0,0,1,4.765,10.6L6.749,8.174,4.479,5.4A.857.857,0,0,1,5.806,4.314L7.857,6.821l2.05-2.506A.857.857,0,1,1,11.235,5.4"
|
||||
fill="#969fa8"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
id="Trazado_7232"
|
||||
data-name="Trazado 7232"
|
||||
d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0m3.235,5.4L8.965,8.174,10.949,10.6a.857.857,0,0,1-1.327,1.086h0L7.857,9.528,6.092,11.686A.857.857,0,0,1,4.765,10.6L6.749,8.174,4.479,5.4A.857.857,0,0,1,5.806,4.314L7.857,6.821l2.05-2.506A.857.857,0,1,1,11.235,5.4"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -25,21 +25,7 @@ const DownloadStatIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
viewBox="0 0 256 256"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path d="M0 0h256v256H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<path fill="none" d="M0 0h256v256H0z" />
|
||||
<g data-name="DownloadStatIcon">
|
||||
<path
|
||||
data-name="Uni\xF3n 24"
|
||||
d="M0 127.996a128 128 0 0 1 128.008-128 128 128 0 0 1 128 128 128 128 0 0 1-128 128.009A128 128 0 0 1 0 127.996Zm20.484 0A107.643 107.643 0 0 0 128 235.52a107.633 107.633 0 0 0 107.512-107.523A107.631 107.631 0 0 0 128 20.487 107.641 107.641 0 0 0 20.48 127.996Zm98.063 71.518-32.336-32.338a13.192 13.192 0 0 1-3.172-14.743 14.934 14.934 0 0 1 13.3-9.235 13.542 13.542 0 0 1 9.637 4.224l8.563 8.554v-89.16c0-9.069 7.016-13.818 13.953-13.818 6.961 0 13.977 4.749 13.977 13.818v89.16l8.555-8.544a13.481 13.481 0 0 1 9.625-4.233 14.887 14.887 0 0 1 13.3 9.235 13.182 13.182 0 0 1-3.164 14.743l-32.348 32.348a14 14 0 0 1-9.906 4.155 14.085 14.085 0 0 1-9.988-4.166Z"
|
||||
/>
|
||||
<path data-name="Rect\xE1ngulo 893" fill="none" d="M0 0h256v256H0z" />
|
||||
</g>
|
||||
</g>
|
||||
<path d="M125.65,0h0C56.26,0,0,56.26,0,125.65H0c0,69.4,56.26,125.65,125.65,125.65h0c69.4,0,125.65-56.26,125.65-125.65S195.05,0,125.65,0m41.51,163.77l-31.76,31.76c-5.32,5.39-14,5.45-19.39,.13-.04-.04-.09-.09-.13-.13h0l-31.74-31.76c-3.97-3.69-5.22-9.46-3.14-14.47,2.19-5.32,7.3-8.87,13.05-9.06,3.57,.06,6.97,1.55,9.42,4.15l8.4,8.4V65.26c0-7.57,6.15-13.71,13.72-13.7,7.57,0,13.7,6.14,13.7,13.7v87.52l8.4-8.39c2.45-2.6,5.85-4.1,9.42-4.16,5.76,.18,10.87,3.73,13.05,9.06,2.09,5,.83,10.78-3.14,14.47" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
|
||||
@@ -25,37 +25,8 @@ const EnabledIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
viewBox="0 0 16 16"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<clipPath id="enabled-clip-path">
|
||||
<rect
|
||||
id="Rectángulo_1067"
|
||||
data-name="Rectángulo 1067"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect
|
||||
id="Rectángulo_1066"
|
||||
data-name="Rectángulo 1066"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
/>
|
||||
<g id="Grupo_2453" data-name="Grupo 2453">
|
||||
<g
|
||||
id="Grupo_2452"
|
||||
data-name="Grupo 2452"
|
||||
clipPath="url(#enabled-clip-path)"
|
||||
>
|
||||
<path
|
||||
id="Trazado_7231"
|
||||
data-name="Trazado 7231"
|
||||
d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0m4.575,5.769-.005.005L7.837,11.69a.89.89,0,0,1-.635.284H7.185a.889.889,0,0,1-.628-.26h0L3.421,8.577a.889.889,0,1,1,1.2-1.31q.028.025.053.053L7.16,9.8l4.117-5.246.024-.026h0a.889.889,0,0,1,1.275,1.24"
|
||||
fill="#969fa8"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0m4.575,5.769-.005.005L7.837,11.69a.89.89,0,0,1-.635.284H7.185a.889.889,0,0,1-.628-.26h0L3.421,8.577a.889.889,0,1,1,1.2-1.31q.028.025.053.053L7.16,9.8l4.117-5.246.024-.026h0a.889.889,0,0,1,1.275,1.24" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -26,19 +26,24 @@ const ObjectManagerIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<g id="Layer 1">
|
||||
<path
|
||||
d="M217.452+193.452L217.452+224.458L38.4601+224.458L38.4601+193.452L0.104767+193.452L0.104767+255.464L255.807+255.464L255.807+193.452L217.452+193.452Z"
|
||||
opacity="1"
|
||||
/>
|
||||
<path
|
||||
d="M70.1156+194.746L98.6658+194.746L98.6658+97.0605L120.994+97.0605L84.3907+51.995L47.7878+97.0605L70.1156+97.0605L70.1156+194.746Z"
|
||||
opacity="1"
|
||||
/>
|
||||
<path
|
||||
d="M183.757+52.6023L155.207+52.6922L155.515+150.377L133.187+150.448L169.932+195.398L206.392+150.217L184.065+150.288L183.757+52.6023Z"
|
||||
opacity="1"
|
||||
/>
|
||||
<g>
|
||||
<g x="2.7" y="36.8">
|
||||
<path
|
||||
d="M77.2,168.6c4,4.1,10.6,4.3,14.7,0.3c0,0,0,0,0.1-0.1l0.2-0.2l29.7-29.9
|
||||
c3.9-4.3,3.6-10.9-0.7-14.9c-4-3.7-10.1-3.7-14.1-0.1l-12,12V47.3h0.1c0-5.8-4.7-10.5-10.5-10.5s-10.5,4.7-10.5,10.5v88.3
|
||||
l-11.9-12c-4.3-4-10.9-3.7-14.9,0.5c-3.8,4.1-3.8,10.4,0.1,14.4L77.2,168.6z"
|
||||
/>
|
||||
<path
|
||||
d="M148.3,84.9l11.9-12v88.3h-0.1c0,5.8,4.7,10.5,10.5,10.5s10.5-4.7,10.5-10.5V72.9l11.9,12
|
||||
c4.3,4,10.9,3.7,14.9-0.5c3.8-4.1,3.8-10.4-0.1-14.4l-29.7-30c-4-4.1-10.6-4.2-14.7-0.2l-0.2,0.2l-29.7,29.9
|
||||
c-4,4.2-3.8,10.9,0.4,14.9C138.1,88.6,144.3,88.7,148.3,84.9"
|
||||
/>
|
||||
<path
|
||||
d="M242.1,154.9c-6.2,0-11.2,5-11.2,11.1l0,0v27.4c0,1.9-1.6,3.5-3.5,3.5H28.5
|
||||
c-1.9,0-3.5-1.6-3.5-3.5v-27.3c0.2-6.2-4.7-11.3-10.8-11.5s-11.3,4.7-11.5,10.8c0,0.2,0,0.4,0,0.7v27.4
|
||||
c0,14.2,11.6,25.7,25.8,25.8h198.8c14.2,0,25.8-11.6,25.8-25.8v-27.4C253.1,159.9,248.1,154.9,242.1,154.9L242.1,154.9"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
37
portal-ui/src/icons/RemoveAllIcon.tsx
Normal file
37
portal-ui/src/icons/RemoveAllIcon.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 ObjectManagerIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
className={`min-icon`}
|
||||
fill={"currentcolor"}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<g>
|
||||
<path d="M216,169H83.14a34,34,0,0,1-24.09-10.15L9.56,108A33.56,33.56,0,0,1,9.56,61L59,10.1A33.91,33.91,0,0,1,83.13,0H216a33.68,33.68,0,0,1,33.65,33.65V135.37A33.68,33.68,0,0,1,216,169M83.14,9A24.93,24.93,0,0,0,65.5,16.42L16,67.36a24.54,24.54,0,0,0,0,34.29l49.5,50.92A24.91,24.91,0,0,0,83.12,160H216a24.64,24.64,0,0,0,24.66-24.62V33.65A24.64,24.64,0,0,0,216,9H83.14Z" />
|
||||
<path d="M162.57,96h0a7.23,7.23,0,1,1-10,10.46l-.2-.24L138.78,92.68l-13.54,13.57a7.21,7.21,0,1,1-10.79-9.58c.12-.14.25-.27.38-.4l.24-.24,13.56-13.55L115.09,68.94a7.22,7.22,0,0,1,10.17-10.21l13.59,13.58,13.54-13.58a7.22,7.22,0,0,1,10.18,10.21L149,82.48Z" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default ObjectManagerIcon;
|
||||
@@ -25,21 +25,9 @@ const UploadStatIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
viewBox="0 0 256 256"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path d="M0 0h256v256H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<path fill="none" d="M0 0h256v256H0z" />
|
||||
<g data-name="UploadStatIcon">
|
||||
<path
|
||||
data-name="Uni\xF3n 27"
|
||||
d="M256 127.997a128.006 128.006 0 0 1-128 128.006A128.008 128.008 0 0 1 0 127.997a128.007 128.007 0 0 1 128.008-128 128 128 0 0 1 127.992 128Zm-20.477 0a107.649 107.649 0 0 0-107.52-107.52 107.641 107.641 0 0 0-107.52 107.52A107.635 107.635 0 0 0 128 235.513a107.642 107.642 0 0 0 107.523-107.516Zm-97.082-77.788 32.332 32.331a13.2 13.2 0 0 1 3.184 14.751 14.916 14.916 0 0 1-13.316 9.225 13.45 13.45 0 0 1-9.617-4.216l-8.559-8.565v89.178c0 9.072-7.035 13.8-13.977 13.8s-13.965-4.731-13.965-13.8V93.738l-8.547 8.565a13.5 13.5 0 0 1-9.637 4.216 14.917 14.917 0 0 1-13.3-9.225 13.216 13.216 0 0 1 3.18-14.751l32.344-32.331a13.916 13.916 0 0 1 9.9-4.168 14.021 14.021 0 0 1 9.978 4.169Z"
|
||||
/>
|
||||
<path data-name="Rect\xE1ngulo 894" fill="none" d="M0 0h256v256H0z" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
d="M125.65,251.3h0c69.4,0,125.65-56.26,125.65-125.65h0C251.3,56.26,195.05,0,125.65,0h0C56.26,0,0,56.26,0,125.65s56.26,125.65,125.65,125.65M84.14,87.53l31.76-31.76c5.32-5.39,14-5.45,19.39-.13,.04,.04,.09,.09,.13,.13h0l31.74,31.76c3.97,3.69,5.22,9.46,3.14,14.47-2.19,5.32-7.3,8.87-13.05,9.06-3.57-.06-6.97-1.55-9.42-4.15l-8.4-8.4v87.53c0,7.57-6.15,13.71-13.72,13.7-7.57,0-13.7-6.14-13.7-13.7V98.53l-8.4,8.39c-2.45,2.6-5.85,4.1-9.42,4.16-5.76-.18-10.87-3.73-13.05-9.06-2.09-5-.83-10.78,3.14-14.47"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
|
||||
@@ -186,3 +186,5 @@ export { default as EditTenantIcon } from "./EditTenantIcon";
|
||||
export { default as SuccessIcon } from "./SuccessIcon";
|
||||
export { default as NetworkGetIcon } from "./NetworkGetIcon";
|
||||
export { default as NetworkPutIcon } from "./NetworkPutIcon";
|
||||
export { default as RemoveAllIcon } from "./RemoveAllIcon";
|
||||
export { default as CancelledIcon } from "./CancelledIcon";
|
||||
|
||||
@@ -52,7 +52,9 @@ import {
|
||||
import { Badge, Typography } from "@mui/material";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
import {
|
||||
cancelObjectInList,
|
||||
completeObject,
|
||||
failObject,
|
||||
openList,
|
||||
resetRewind,
|
||||
setLoadingObjectInfo,
|
||||
@@ -241,6 +243,8 @@ interface IListObjectsProps {
|
||||
setSelectedObjectView: typeof setSelectedObjectView;
|
||||
setLoadingObjectInfo: typeof setLoadingObjectInfo;
|
||||
setLoadingObjectsList: typeof setLoadingObjectsList;
|
||||
failObject: typeof failObject;
|
||||
cancelObjectInList: typeof cancelObjectInList;
|
||||
}
|
||||
|
||||
function useInterval(callback: any, delay: number) {
|
||||
@@ -300,6 +304,8 @@ const ListObjects = ({
|
||||
setSelectedObjectView,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingObjectsList,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
}: IListObjectsProps) => {
|
||||
const [records, setRecords] = useState<BucketObjectItem[]>([]);
|
||||
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
|
||||
@@ -738,17 +744,7 @@ const ListObjects = ({
|
||||
`${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}`
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
});
|
||||
|
||||
download(
|
||||
const downloadCall = download(
|
||||
bucketName,
|
||||
encodeFileName(object.name),
|
||||
object.version_id,
|
||||
@@ -758,8 +754,29 @@ const ListObjects = ({
|
||||
},
|
||||
() => {
|
||||
completeObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
failObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
cancelObjectInList(identityDownload);
|
||||
}
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
failed: false,
|
||||
cancelled: false,
|
||||
call: downloadCall,
|
||||
});
|
||||
|
||||
downloadCall.send();
|
||||
};
|
||||
|
||||
const openPath = (idElement: string) => {
|
||||
@@ -824,16 +841,6 @@ const ListObjects = ({
|
||||
`${bucketName}-${encodedPath}-${new Date().getTime()}-${Math.random()}`
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identity,
|
||||
percentage: 0,
|
||||
prefix: `${decodeFileName(encodedPath)}${fileName}`,
|
||||
type: "upload",
|
||||
waitingForFile: false,
|
||||
});
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", uploadUrl, true);
|
||||
|
||||
@@ -864,12 +871,14 @@ const ListObjects = ({
|
||||
errorMessage = "something went wrong";
|
||||
}
|
||||
}
|
||||
failObject(identity);
|
||||
reject({ status: xhr.status, message: errorMessage });
|
||||
}
|
||||
};
|
||||
|
||||
xhr.upload.addEventListener("error", (event) => {
|
||||
reject(errorMessage);
|
||||
failObject(identity);
|
||||
return;
|
||||
});
|
||||
|
||||
@@ -881,6 +890,7 @@ const ListObjects = ({
|
||||
|
||||
xhr.onerror = () => {
|
||||
reject(errorMessage);
|
||||
failObject(identity);
|
||||
return;
|
||||
};
|
||||
xhr.onloadend = () => {
|
||||
@@ -888,10 +898,27 @@ const ListObjects = ({
|
||||
setLoadingObjectsList(true);
|
||||
}
|
||||
};
|
||||
xhr.onabort = () => {
|
||||
cancelObjectInList(identity);
|
||||
};
|
||||
|
||||
const formData = new FormData();
|
||||
if (file.size !== undefined) {
|
||||
formData.append(file.size.toString(), blobFile, fileName);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identity,
|
||||
percentage: 0,
|
||||
prefix: `${decodeFileName(encodedPath)}${fileName}`,
|
||||
type: "upload",
|
||||
waitingForFile: false,
|
||||
failed: false,
|
||||
cancelled: false,
|
||||
call: xhr,
|
||||
});
|
||||
|
||||
xhr.send(formData);
|
||||
}
|
||||
});
|
||||
@@ -934,6 +961,8 @@ const ListObjects = ({
|
||||
setErrorSnackMessage,
|
||||
updateProgress,
|
||||
setLoadingObjectsList,
|
||||
cancelObjectInList,
|
||||
failObject,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1485,6 +1514,7 @@ const mapDispatchToProps = {
|
||||
updateProgress,
|
||||
completeObject,
|
||||
openList,
|
||||
failObject,
|
||||
setSearchObjects,
|
||||
setVersionsModeEnabled,
|
||||
setShowDeletedObjects,
|
||||
@@ -1493,6 +1523,7 @@ const mapDispatchToProps = {
|
||||
setSelectedObjectView,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingObjectsList,
|
||||
cancelObjectInList,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
@@ -44,7 +44,9 @@ import {
|
||||
} from "../../../../../../common/utils";
|
||||
import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
|
||||
import {
|
||||
cancelObjectInList,
|
||||
completeObject,
|
||||
failObject,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingVersions,
|
||||
setNewObject,
|
||||
@@ -137,6 +139,8 @@ interface IObjectDetailPanelProps {
|
||||
setLoadingObjectInfo: typeof setLoadingObjectInfo;
|
||||
setLoadingVersions: typeof setLoadingVersions;
|
||||
setSelectedVersion: typeof setSelectedVersion;
|
||||
failObject: typeof failObject;
|
||||
cancelObjectInList: typeof cancelObjectInList;
|
||||
}
|
||||
|
||||
const emptyFile: IFileInfo = {
|
||||
@@ -170,6 +174,8 @@ const ObjectDetailPanel = ({
|
||||
setLoadingObjectInfo,
|
||||
setLoadingVersions,
|
||||
setSelectedVersion,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
}: IObjectDetailPanelProps) => {
|
||||
const [shareFileModalOpen, setShareFileModalOpen] = useState<boolean>(false);
|
||||
const [retentionModalOpen, setRetentionModalOpen] = useState<boolean>(false);
|
||||
@@ -294,17 +300,7 @@ const ObjectDetailPanel = ({
|
||||
`${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}`
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
});
|
||||
|
||||
download(
|
||||
const downloadCall = download(
|
||||
bucketName,
|
||||
internalPaths,
|
||||
object.version_id,
|
||||
@@ -314,8 +310,29 @@ const ObjectDetailPanel = ({
|
||||
},
|
||||
() => {
|
||||
completeObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
failObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
cancelObjectInList(identityDownload);
|
||||
}
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
failed: false,
|
||||
cancelled: false,
|
||||
call: downloadCall,
|
||||
});
|
||||
|
||||
downloadCall.send();
|
||||
};
|
||||
|
||||
const closeDeleteModal = (closeAndReload: boolean) => {
|
||||
@@ -731,6 +748,8 @@ const mapDispatchToProps = {
|
||||
setLoadingObjectInfo,
|
||||
setLoadingVersions,
|
||||
setSelectedVersion,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
@@ -50,7 +50,9 @@ import {
|
||||
import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle";
|
||||
import RestoreFileVersion from "./RestoreFileVersion";
|
||||
import {
|
||||
cancelObjectInList,
|
||||
completeObject,
|
||||
failObject,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingVersions,
|
||||
setNewObject,
|
||||
@@ -128,6 +130,8 @@ interface IVersionsNavigatorProps {
|
||||
setSelectedVersion: typeof setSelectedVersion;
|
||||
setLoadingVersions: typeof setLoadingVersions;
|
||||
setLoadingObjectInfo: typeof setLoadingObjectInfo;
|
||||
failObject: typeof failObject;
|
||||
cancelObjectInList: typeof cancelObjectInList;
|
||||
}
|
||||
|
||||
const emptyFile: IFileInfo = {
|
||||
@@ -157,6 +161,8 @@ const VersionsNavigator = ({
|
||||
setSelectedVersion,
|
||||
setLoadingVersions,
|
||||
setLoadingObjectInfo,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
}: IVersionsNavigatorProps) => {
|
||||
const [shareFileModalOpen, setShareFileModalOpen] = useState<boolean>(false);
|
||||
const [actualInfo, setActualInfo] = useState<IFileInfo | null>(null);
|
||||
@@ -227,17 +233,7 @@ const VersionsNavigator = ({
|
||||
`${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}`
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
});
|
||||
|
||||
download(
|
||||
const downloadCall = download(
|
||||
bucketName,
|
||||
internalPaths,
|
||||
object.version_id,
|
||||
@@ -247,8 +243,29 @@ const VersionsNavigator = ({
|
||||
},
|
||||
() => {
|
||||
completeObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
failObject(identityDownload);
|
||||
},
|
||||
() => {
|
||||
cancelObjectInList(identityDownload);
|
||||
}
|
||||
);
|
||||
|
||||
setNewObject({
|
||||
bucketName,
|
||||
done: false,
|
||||
instanceID: identityDownload,
|
||||
percentage: 0,
|
||||
prefix: object.name,
|
||||
type: "download",
|
||||
waitingForFile: true,
|
||||
failed: false,
|
||||
cancelled: false,
|
||||
call: downloadCall,
|
||||
});
|
||||
|
||||
downloadCall.send();
|
||||
};
|
||||
|
||||
const onShareItem = (item: IFileInfo) => {
|
||||
@@ -517,6 +534,8 @@ const mapDispatchToProps = {
|
||||
setSelectedVersion,
|
||||
setLoadingVersions,
|
||||
setLoadingObjectInfo,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
@@ -22,7 +22,9 @@ export const download = (
|
||||
versionID: any,
|
||||
fileSize: number,
|
||||
progressCallback: (progress: number) => void,
|
||||
completeCallback: () => void
|
||||
completeCallback: () => void,
|
||||
errorCallback: () => void,
|
||||
abortCallback: () => void,
|
||||
) => {
|
||||
const anchor = document.createElement("a");
|
||||
document.body.appendChild(anchor);
|
||||
@@ -68,7 +70,19 @@ export const download = (
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
};
|
||||
req.send();
|
||||
req.onerror = () => {
|
||||
if(errorCallback) {
|
||||
errorCallback();
|
||||
}
|
||||
};
|
||||
req.onabort = () => {
|
||||
if(abortCallback) {
|
||||
abortCallback();
|
||||
}
|
||||
};
|
||||
//req.send();
|
||||
|
||||
return req;
|
||||
};
|
||||
|
||||
// Review file extension by name & returns the type of preview browser that can be used
|
||||
|
||||
@@ -235,6 +235,12 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
|
||||
CallHomeFeatureIcon
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3} sm={2} md={1}>
|
||||
<cicons.CancelledIcon />
|
||||
<br />
|
||||
CancelledIcon
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3} sm={2} md={1}>
|
||||
<cicons.ChangeAccessPolicyIcon />
|
||||
<br />
|
||||
@@ -847,6 +853,12 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
|
||||
RefreshIcon
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3} sm={2} md={1}>
|
||||
<cicons.RemoveAllIcon />
|
||||
<br />
|
||||
RemoveAllIcon
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3} sm={2} md={1}>
|
||||
<cicons.RemoveIcon />
|
||||
<br />
|
||||
|
||||
@@ -21,7 +21,13 @@ import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IFileItem } from "../../ObjectBrowser/types";
|
||||
import ProgressBarWrapper from "../ProgressBarWrapper/ProgressBarWrapper";
|
||||
import { DownloadStatIcon, UploadStatIcon } from "../../../../icons";
|
||||
import {
|
||||
DisabledIcon,
|
||||
DownloadStatIcon,
|
||||
EnabledIcon,
|
||||
UploadStatIcon,
|
||||
CancelledIcon,
|
||||
} from "../../../../icons";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface IObjectHandled {
|
||||
@@ -35,15 +41,15 @@ const styles = (theme: Theme) =>
|
||||
container: {
|
||||
borderBottom: "#E2E2E2 1px solid",
|
||||
padding: "15px 5px",
|
||||
margin: "0 15px",
|
||||
margin: "0 30px",
|
||||
position: "relative",
|
||||
"& .showOnHover": {
|
||||
opacity: 0,
|
||||
opacity: 1,
|
||||
transitionDuration: "0.2s",
|
||||
},
|
||||
"&.inProgress": {
|
||||
"& .hideOnProgress": {
|
||||
visibility: "hidden",
|
||||
//visibility: "hidden",
|
||||
},
|
||||
},
|
||||
"&:hover": {
|
||||
@@ -53,13 +59,19 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
},
|
||||
headItem: {
|
||||
color: "#868686",
|
||||
fontSize: 12,
|
||||
color: "#000",
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
width: "100%",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
},
|
||||
downloadHeader: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
},
|
||||
progressContainer: {
|
||||
marginTop: 5,
|
||||
},
|
||||
@@ -71,42 +83,65 @@ const styles = (theme: Theme) =>
|
||||
paddingTop: 5,
|
||||
marginRight: 5,
|
||||
"& svg": {
|
||||
width: 20,
|
||||
height: 20,
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
},
|
||||
download: {
|
||||
color: "rgb(113,200,150)",
|
||||
completedSuccess: {
|
||||
color: "#4CCB92",
|
||||
},
|
||||
upload: {
|
||||
color: "rgb(66,127,172)",
|
||||
inProgress: {
|
||||
color: "#2781B0",
|
||||
},
|
||||
completedError: {
|
||||
color: "#C83B51",
|
||||
},
|
||||
cancelledAction: {
|
||||
color: "#FFBD62",
|
||||
},
|
||||
closeIcon: {
|
||||
backgroundColor: "#E9EDEE",
|
||||
display: "block",
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: "100%",
|
||||
"&:hover": {
|
||||
backgroundColor: "#cecbcb",
|
||||
},
|
||||
"&::before": {
|
||||
width: 1,
|
||||
height: 12,
|
||||
height: 9,
|
||||
top: "50%",
|
||||
content: "' '",
|
||||
position: "absolute",
|
||||
transform: "rotate(45deg)",
|
||||
borderLeft: "#9c9c9c 2px solid",
|
||||
transform: "translate(-50%, -50%) rotate(45deg)",
|
||||
borderLeft: "#000 2px solid",
|
||||
},
|
||||
"&::after": {
|
||||
width: 1,
|
||||
height: 12,
|
||||
height: 9,
|
||||
top: "50%",
|
||||
content: "' '",
|
||||
position: "absolute",
|
||||
transform: "rotate(-45deg)",
|
||||
borderLeft: "#9c9c9c 2px solid",
|
||||
transform: "translate(-50%, -50%) rotate(-45deg)",
|
||||
borderLeft: "#000 2px solid",
|
||||
},
|
||||
},
|
||||
closeButton: {
|
||||
backgroundColor: "transparent",
|
||||
border: 0,
|
||||
right: 0,
|
||||
top: 5,
|
||||
marginTop: 15,
|
||||
position: "absolute",
|
||||
},
|
||||
fileName: {
|
||||
width: 230,
|
||||
width: 295,
|
||||
},
|
||||
bucketName: {
|
||||
fontSize: 12,
|
||||
color: "#696969",
|
||||
fontWeight: "normal",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -126,35 +161,74 @@ const ObjectHandled = ({
|
||||
<div className={classes.clearListIcon}>
|
||||
<button
|
||||
onClick={() => {
|
||||
deleteFromList(objectToDisplay.instanceID);
|
||||
if (!objectToDisplay.done) {
|
||||
console.log("//abort");
|
||||
|
||||
objectToDisplay.call?.abort();
|
||||
} else {
|
||||
deleteFromList(objectToDisplay.instanceID);
|
||||
}
|
||||
}}
|
||||
className={`${classes.closeButton} hideOnProgress showOnHover`}
|
||||
disabled={objectToDisplay.percentage !== 100}
|
||||
className={`${classes.closeButton} hideOnProgress`}
|
||||
>
|
||||
<span className={classes.closeIcon} />
|
||||
</button>
|
||||
</div>
|
||||
<div className={classes.objectDetails}>
|
||||
<div
|
||||
className={clsx(classes.iconContainer, {
|
||||
[classes.download]: objectToDisplay.type === "download",
|
||||
[classes.upload]: objectToDisplay.type !== "download",
|
||||
})}
|
||||
>
|
||||
{objectToDisplay.type === "download" ? (
|
||||
<DownloadStatIcon />
|
||||
) : (
|
||||
<UploadStatIcon />
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.fileName}>
|
||||
<div className={classes.headItem}>
|
||||
<Tooltip title={prefix} placement="top-start">
|
||||
<div className={classes.downloadHeader}>
|
||||
<span
|
||||
className={clsx(classes.iconContainer, {
|
||||
[classes.inProgress]:
|
||||
!objectToDisplay.done &&
|
||||
!objectToDisplay.failed &&
|
||||
!objectToDisplay.cancelled,
|
||||
[classes.completedSuccess]:
|
||||
objectToDisplay.done &&
|
||||
!objectToDisplay.failed &&
|
||||
!objectToDisplay.cancelled,
|
||||
[classes.completedError]: objectToDisplay.failed,
|
||||
[classes.cancelledAction]: objectToDisplay.cancelled,
|
||||
})}
|
||||
>
|
||||
{objectToDisplay.cancelled ? (
|
||||
<CancelledIcon />
|
||||
) : (
|
||||
<Fragment>
|
||||
{objectToDisplay.failed ? (
|
||||
<DisabledIcon />
|
||||
) : (
|
||||
<Fragment>
|
||||
{objectToDisplay.done ? (
|
||||
<EnabledIcon />
|
||||
) : (
|
||||
<Fragment>
|
||||
{objectToDisplay.type === "download" ? (
|
||||
<DownloadStatIcon />
|
||||
) : (
|
||||
<UploadStatIcon />
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</span>
|
||||
<span
|
||||
className={clsx(classes.headItem, {
|
||||
[classes.completedError]: objectToDisplay.failed,
|
||||
})}
|
||||
>
|
||||
{prefix}
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<span className={classes.bucketName}>
|
||||
<strong>Bucket: </strong>
|
||||
{objectToDisplay.bucketName}
|
||||
</div>
|
||||
<Tooltip title={prefix} placement="top-start">
|
||||
<div className={classes.headItem}>{prefix}</div>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.progressContainer}>
|
||||
@@ -164,6 +238,8 @@ const ObjectHandled = ({
|
||||
<ProgressBarWrapper
|
||||
value={objectToDisplay.percentage}
|
||||
ready={objectToDisplay.done}
|
||||
error={objectToDisplay.failed}
|
||||
cancelled={objectToDisplay.cancelled}
|
||||
withLabel
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -23,7 +23,7 @@ import { Tooltip, IconButton } from "@mui/material";
|
||||
import { AppState } from "../../../../store";
|
||||
import { IFileItem } from "../../ObjectBrowser/types";
|
||||
import { deleteFromList, cleanList } from "../../ObjectBrowser/actions";
|
||||
import { TrashIcon } from "../../../../icons";
|
||||
import { RemoveAllIcon } from "../../../../icons";
|
||||
import ObjectHandled from "./ObjectHandled";
|
||||
|
||||
interface IObjectManager {
|
||||
@@ -38,12 +38,12 @@ const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
downloadContainer: {
|
||||
border: "#EAEDEE 1px solid",
|
||||
boxShadow: "rgba(0, 0, 0, 0.08) 0 3px 10px",
|
||||
boxShadow: "rgba(0, 0, 0, 0.08) 0 2px 10px",
|
||||
backgroundColor: "#fff",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: 80,
|
||||
width: 300,
|
||||
right: 20,
|
||||
top: 60,
|
||||
width: 400,
|
||||
overflowY: "hidden",
|
||||
overflowX: "hidden",
|
||||
borderRadius: 3,
|
||||
@@ -58,13 +58,13 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 5,
|
||||
paddingBottom: 12,
|
||||
textAlign: "left",
|
||||
paddingBottom: 20,
|
||||
borderBottom: "#E2E2E2 1px solid",
|
||||
margin: "15px 15px 5px 15px",
|
||||
margin: "25px 30px 5px 30px",
|
||||
color: "#000",
|
||||
},
|
||||
actionsContainer: {
|
||||
overflowY: "auto",
|
||||
@@ -77,12 +77,12 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
cleanIcon: {
|
||||
position: "absolute",
|
||||
right: 14,
|
||||
top: 12,
|
||||
right: 28,
|
||||
top: 25,
|
||||
},
|
||||
cleanButton: {
|
||||
"& svg": {
|
||||
width: 20,
|
||||
width: 25,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -110,7 +110,7 @@ const ObjectManager = ({
|
||||
onClick={cleanList}
|
||||
className={classes.cleanButton}
|
||||
>
|
||||
<TrashIcon />
|
||||
<RemoveAllIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 React, { Fragment, useEffect, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { connect } from "react-redux";
|
||||
import Grid from "@mui/material/Grid";
|
||||
@@ -26,7 +26,7 @@ import OperatorLogo from "../../../../icons/OperatorLogo";
|
||||
import ConsoleLogo from "../../../../icons/ConsoleLogo";
|
||||
import { IFileItem } from "../../ObjectBrowser/types";
|
||||
import { toggleList } from "../../ObjectBrowser/actions";
|
||||
import { ObjectManagerIcon } from "../../../../icons";
|
||||
import { CircleIcon, ObjectManagerIcon } from "../../../../icons";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
interface IPageHeader {
|
||||
@@ -35,10 +35,12 @@ interface IPageHeader {
|
||||
operatorMode?: boolean;
|
||||
label: any;
|
||||
actions?: any;
|
||||
managerObjects?: IFileItem[];
|
||||
managerObjects: IFileItem[];
|
||||
toggleList: typeof toggleList;
|
||||
middleComponent?: React.ReactNode;
|
||||
features: string[];
|
||||
managerOpen: boolean;
|
||||
newItems: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -71,6 +73,31 @@ const styles = (theme: Theme) =>
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
indicator: {
|
||||
position: "absolute",
|
||||
display: "block",
|
||||
width: 15,
|
||||
height: 15,
|
||||
top: 0,
|
||||
right: 2,
|
||||
marginTop: -16,
|
||||
transitionDuration: "0.2s",
|
||||
color: "#32C787",
|
||||
"& svg": {
|
||||
width: 10,
|
||||
height: 10,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transitionDuration: "0.2s",
|
||||
},
|
||||
"&.newItem": {
|
||||
color: "#2781B0",
|
||||
"& svg": {
|
||||
width: 15,
|
||||
height: 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PageHeader = ({
|
||||
@@ -83,7 +110,20 @@ const PageHeader = ({
|
||||
toggleList,
|
||||
middleComponent,
|
||||
features,
|
||||
managerOpen,
|
||||
newItems,
|
||||
}: IPageHeader) => {
|
||||
const [newObject, setNewObject] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (managerObjects.length > 0 && !managerOpen) {
|
||||
setNewObject(true);
|
||||
setTimeout(() => {
|
||||
setNewObject(false);
|
||||
}, 300);
|
||||
}
|
||||
}, [managerObjects.length, managerOpen]);
|
||||
|
||||
if (features.includes("hide-menu")) {
|
||||
return <Fragment />;
|
||||
}
|
||||
@@ -151,7 +191,29 @@ const PageHeader = ({
|
||||
}}
|
||||
id="object-manager-toggle"
|
||||
size="large"
|
||||
sx={{
|
||||
marginRight: "20px",
|
||||
color: "#5E5E5E",
|
||||
position: "relative",
|
||||
border: "#E2E2E2 1px solid",
|
||||
borderRadius: "3px",
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
backgroundColor: "#F8F8F8",
|
||||
padding: 0,
|
||||
"&>svg": {
|
||||
width: "25px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`${classes.indicator} ${newObject ? "newItem" : ""}`}
|
||||
style={{
|
||||
opacity: managerObjects.length > 0 && newItems ? 1 : 0,
|
||||
}}
|
||||
>
|
||||
<CircleIcon />
|
||||
</div>
|
||||
<ObjectManagerIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
@@ -165,6 +227,8 @@ const mapState = (state: AppState) => ({
|
||||
operatorMode: state.system.operatorMode,
|
||||
managerObjects: state.objectBrowser.objectManager.objectsToManage,
|
||||
features: state.console.session.features,
|
||||
managerOpen: state.objectBrowser.objectManager.managerOpen,
|
||||
newItems: state.objectBrowser.objectManager.newItems,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import LinearProgress, {
|
||||
linearProgressClasses,
|
||||
@@ -28,6 +28,8 @@ interface IProgressBarWrapper {
|
||||
indeterminate?: boolean;
|
||||
withLabel?: boolean;
|
||||
size?: string;
|
||||
error?: boolean;
|
||||
cancelled?: boolean;
|
||||
}
|
||||
|
||||
const BorderLinearProgress = styled(LinearProgress)(() => ({
|
||||
@@ -48,14 +50,42 @@ const SmallBorderLinearProgress = styled(BorderLinearProgress)(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
function LinearProgressWithLabel(props: LinearProgressProps) {
|
||||
function LinearProgressWithLabel(
|
||||
props: { error: boolean; cancelled: boolean } & LinearProgressProps
|
||||
) {
|
||||
let color = "#000";
|
||||
let size = 18;
|
||||
|
||||
if(props.error) {
|
||||
color = "#C83B51"
|
||||
size = 14
|
||||
}
|
||||
|
||||
else if(props.cancelled) {
|
||||
color = "#FFBD62"
|
||||
size = 14
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Box sx={{ width: "100%", mr: 1 }}>
|
||||
<Box sx={{ width: "100%", mr: 3 }}>
|
||||
<BorderLinearProgress variant="determinate" {...props} />
|
||||
</Box>
|
||||
<Box sx={{ minWidth: 35, fontSize: 14 }} className={"value"}>
|
||||
{`${Math.round(props.value || 0)}%`}
|
||||
<Box
|
||||
sx={{
|
||||
minWidth: 35,
|
||||
fontSize: size,
|
||||
color: color,
|
||||
}}
|
||||
className={"value"}
|
||||
>
|
||||
{props.cancelled ? (
|
||||
"Cancelled"
|
||||
) : (
|
||||
<Fragment>
|
||||
{props.error ? "Failed" : `${Math.round(props.value || 0)}%`}
|
||||
</Fragment>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
@@ -67,22 +97,32 @@ const ProgressBarWrapper = ({
|
||||
indeterminate,
|
||||
withLabel,
|
||||
size = "regular",
|
||||
error,
|
||||
cancelled,
|
||||
}: IProgressBarWrapper) => {
|
||||
let color: any;
|
||||
if (value === 100 && ready) {
|
||||
color = "success";
|
||||
} else if (value === 100 && !ready) {
|
||||
if (error) {
|
||||
color = "error";
|
||||
} else if (cancelled) {
|
||||
color = "warning";
|
||||
}else if (value === 100 && ready) {
|
||||
color = "success";
|
||||
} else {
|
||||
color = "primary";
|
||||
}
|
||||
const propsComponent: LinearProgressProps = {
|
||||
variant: indeterminate && !ready ? "indeterminate" : "determinate",
|
||||
variant: indeterminate && !ready && !cancelled ? "indeterminate" : "determinate",
|
||||
value: ready ? 100 : value,
|
||||
color: color,
|
||||
};
|
||||
if (withLabel) {
|
||||
return <LinearProgressWithLabel {...propsComponent} />;
|
||||
return (
|
||||
<LinearProgressWithLabel
|
||||
{...propsComponent}
|
||||
error={!!error}
|
||||
cancelled={!!cancelled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (size === "small") {
|
||||
return <SmallBorderLinearProgress {...propsComponent} />;
|
||||
|
||||
@@ -31,11 +31,13 @@ import {
|
||||
OBJECT_MANAGER_SET_SEARCH_OBJECT,
|
||||
OBJECT_MANAGER_TOGGLE_LIST,
|
||||
OBJECT_MANAGER_UPDATE_PROGRESS_OBJECT,
|
||||
OBJECT_MANAGER_SET_LOADING,
|
||||
OBJECT_MANAGER_ERROR_IN_OBJECT,
|
||||
OBJECT_MANAGER_CANCEL_OBJECT,
|
||||
REWIND_RESET_REWIND,
|
||||
REWIND_SET_ENABLE,
|
||||
IFileItem,
|
||||
BUCKET_BROWSER_SET_SELECTED_OBJECT,
|
||||
OBJECT_MANAGER_SET_LOADING,
|
||||
IFileItem,
|
||||
} from "./types";
|
||||
|
||||
export const setRewindEnable = (
|
||||
@@ -90,6 +92,13 @@ export const completeObject = (instanceID: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const failObject = (instanceID: string) => {
|
||||
return {
|
||||
type: OBJECT_MANAGER_ERROR_IN_OBJECT,
|
||||
instanceID,
|
||||
};
|
||||
};
|
||||
|
||||
export const deleteFromList = (instanceID: string) => {
|
||||
return {
|
||||
type: OBJECT_MANAGER_DELETE_FROM_OBJECT_LIST,
|
||||
@@ -128,6 +137,20 @@ export const setSearchObjects = (searchString: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const setLoadingObjectsList = (status: boolean) => {
|
||||
return {
|
||||
type: OBJECT_MANAGER_SET_LOADING,
|
||||
status,
|
||||
};
|
||||
};
|
||||
|
||||
export const cancelObjectInList = (instanceID: string) => {
|
||||
return {
|
||||
type: OBJECT_MANAGER_CANCEL_OBJECT,
|
||||
instanceID,
|
||||
};
|
||||
};
|
||||
|
||||
export const setSearchVersions = (searchString: string) => {
|
||||
return {
|
||||
type: BUCKET_BROWSER_VERSIONS_SET_SEARCH,
|
||||
@@ -176,10 +199,3 @@ export const setSelectedObjectView = (object: string | null) => {
|
||||
object,
|
||||
};
|
||||
};
|
||||
|
||||
export const setLoadingObjectsList = (status: boolean) => {
|
||||
return {
|
||||
type: OBJECT_MANAGER_SET_LOADING,
|
||||
status,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,6 +37,8 @@ import {
|
||||
ObjectBrowserActionTypes,
|
||||
BUCKET_BROWSER_SET_SELECTED_OBJECT,
|
||||
OBJECT_MANAGER_SET_LOADING,
|
||||
OBJECT_MANAGER_ERROR_IN_OBJECT,
|
||||
OBJECT_MANAGER_CANCEL_OBJECT,
|
||||
} from "./types";
|
||||
|
||||
const defaultRewind = {
|
||||
@@ -57,6 +59,7 @@ const initialState: ObjectBrowserState = {
|
||||
objectManager: {
|
||||
objectsToManage: [],
|
||||
managerOpen: false,
|
||||
newItems: false,
|
||||
},
|
||||
searchObjects: "",
|
||||
versionedFile: "",
|
||||
@@ -106,6 +109,7 @@ export function objectBrowserReducer(
|
||||
objectManager: {
|
||||
objectsToManage: cloneObjects,
|
||||
managerOpen: state.objectManager.managerOpen,
|
||||
newItems: true,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_UPDATE_PROGRESS_OBJECT:
|
||||
@@ -127,6 +131,7 @@ export function objectBrowserReducer(
|
||||
objectManager: {
|
||||
objectsToManage: copyManager,
|
||||
managerOpen: state.objectManager.managerOpen,
|
||||
newItems: state.objectManager.newItems,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_COMPLETE_OBJECT:
|
||||
@@ -149,6 +154,51 @@ export function objectBrowserReducer(
|
||||
objectManager: {
|
||||
objectsToManage: copyObject,
|
||||
managerOpen: state.objectManager.managerOpen,
|
||||
newItems: state.objectManager.newItems,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_ERROR_IN_OBJECT:
|
||||
const objectItems = [...state.objectManager.objectsToManage];
|
||||
|
||||
const objectToFail = state.objectManager.objectsToManage.findIndex(
|
||||
(item) => item.instanceID === action.instanceID
|
||||
);
|
||||
|
||||
if (objectToFail === -1) {
|
||||
return { ...state };
|
||||
}
|
||||
|
||||
objectItems[objectToFail].failed = true;
|
||||
|
||||
return {
|
||||
...state,
|
||||
objectManager: {
|
||||
objectsToManage: objectItems,
|
||||
managerOpen: state.objectManager.managerOpen,
|
||||
newItems: state.objectManager.newItems,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_CANCEL_OBJECT:
|
||||
const objectsListFind = [...state.objectManager.objectsToManage];
|
||||
|
||||
const objectToCancel = state.objectManager.objectsToManage.findIndex(
|
||||
(item) => item.instanceID === action.instanceID
|
||||
);
|
||||
|
||||
if (objectToCancel === -1) {
|
||||
return { ...state };
|
||||
}
|
||||
|
||||
objectsListFind[objectToCancel].cancelled = true;
|
||||
objectsListFind[objectToCancel].done = true;
|
||||
objectsListFind[objectToCancel].percentage = 0;
|
||||
|
||||
return {
|
||||
...state,
|
||||
objectManager: {
|
||||
objectsToManage: objectsListFind,
|
||||
managerOpen: state.objectManager.managerOpen,
|
||||
newItems: state.objectManager.newItems,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_DELETE_FROM_OBJECT_LIST:
|
||||
@@ -162,6 +212,7 @@ export function objectBrowserReducer(
|
||||
objectsToManage: notObject,
|
||||
managerOpen:
|
||||
notObject.length === 0 ? false : state.objectManager.managerOpen,
|
||||
newItems: state.objectManager.newItems,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_CLEAN_LIST:
|
||||
@@ -177,6 +228,7 @@ export function objectBrowserReducer(
|
||||
nonCompletedList.length === 0
|
||||
? false
|
||||
: state.objectManager.managerOpen,
|
||||
newItems: false,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_TOGGLE_LIST:
|
||||
@@ -185,6 +237,7 @@ export function objectBrowserReducer(
|
||||
objectManager: {
|
||||
...state.objectManager,
|
||||
managerOpen: !state.objectManager.managerOpen,
|
||||
newItems: false,
|
||||
},
|
||||
};
|
||||
case OBJECT_MANAGER_OPEN_LIST:
|
||||
|
||||
@@ -22,6 +22,7 @@ export const OBJECT_MANAGER_NEW_OBJECT = "OBJECT_MANAGER/NEW_OBJECT";
|
||||
export const OBJECT_MANAGER_UPDATE_PROGRESS_OBJECT =
|
||||
"OBJECT_MANAGER/UPDATE_PROGRESS_OBJECT";
|
||||
export const OBJECT_MANAGER_COMPLETE_OBJECT = "OBJECT_MANAGER/COMPLETE_OBJECT";
|
||||
export const OBJECT_MANAGER_ERROR_IN_OBJECT = "OBJECT_MANAGER/ERROR_IN_OBJECT";
|
||||
export const OBJECT_MANAGER_DELETE_FROM_OBJECT_LIST =
|
||||
"OBJECT_MANAGER/DELETE_FROM_OBJECT_LIST";
|
||||
export const OBJECT_MANAGER_CLEAN_LIST = "OBJECT_MANAGER/CLEAN_LIST";
|
||||
@@ -30,6 +31,7 @@ export const OBJECT_MANAGER_OPEN_LIST = "OBJECT_MANAGER/OPEN_LIST";
|
||||
export const OBJECT_MANAGER_CLOSE_LIST = "OBJECT_MANAGER/CLOSE_LIST";
|
||||
export const OBJECT_MANAGER_SET_SEARCH_OBJECT =
|
||||
"OBJECT_MANAGER/SET_SEARCH_OBJECT";
|
||||
export const OBJECT_MANAGER_CANCEL_OBJECT = "OBJECT_MANAGER/CANCEL_OBJECT";
|
||||
|
||||
export const BUCKET_BROWSER_VERSIONS_MODE_ENABLED =
|
||||
"BUCKET_BROWSER/VERSIONS_MODE_ENABLED";
|
||||
@@ -81,6 +83,7 @@ export interface ObjectBrowserReducer {
|
||||
export interface ObjectManager {
|
||||
objectsToManage: IFileItem[];
|
||||
managerOpen: boolean;
|
||||
newItems: boolean;
|
||||
}
|
||||
|
||||
export interface IFileItem {
|
||||
@@ -91,6 +94,9 @@ export interface IFileItem {
|
||||
percentage: number;
|
||||
done: boolean;
|
||||
waitingForFile: boolean;
|
||||
failed: boolean;
|
||||
cancelled: boolean;
|
||||
call?: XMLHttpRequest;
|
||||
}
|
||||
|
||||
interface RewindSetEnabled {
|
||||
@@ -147,6 +153,12 @@ interface OMCloseList {
|
||||
type: typeof OBJECT_MANAGER_CLOSE_LIST;
|
||||
}
|
||||
|
||||
interface OMSetObjectError {
|
||||
type: typeof OBJECT_MANAGER_ERROR_IN_OBJECT;
|
||||
status: boolean;
|
||||
instanceID: string;
|
||||
}
|
||||
|
||||
interface SetSearchObjects {
|
||||
type: typeof OBJECT_MANAGER_SET_SEARCH_OBJECT;
|
||||
searchString: string;
|
||||
@@ -192,6 +204,11 @@ interface SetObjectManagerLoading {
|
||||
status: boolean;
|
||||
}
|
||||
|
||||
interface CancelObjectInManager {
|
||||
type: typeof OBJECT_MANAGER_CANCEL_OBJECT;
|
||||
instanceID: string;
|
||||
}
|
||||
|
||||
export type ObjectBrowserActionTypes =
|
||||
| RewindSetEnabled
|
||||
| RewindReset
|
||||
@@ -204,6 +221,7 @@ export type ObjectBrowserActionTypes =
|
||||
| OMToggleList
|
||||
| OMOpenList
|
||||
| OMCloseList
|
||||
| OMSetObjectError
|
||||
| SetSearchObjects
|
||||
| SetSearchVersions
|
||||
| SetSelectedversion
|
||||
@@ -212,4 +230,5 @@ export type ObjectBrowserActionTypes =
|
||||
| SetLoadingObjectInfo
|
||||
| SetObjectDetailsState
|
||||
| SetSelectedObject
|
||||
| SetObjectManagerLoading;
|
||||
| SetObjectManagerLoading
|
||||
| CancelObjectInManager;
|
||||
|
||||
Reference in New Issue
Block a user