mirror of
https://github.com/OpenMaxIO/openmaxio-object-browser
synced 2026-07-01 07:41:18 -07:00
Added support to restore versions in object details (#1181)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
25
portal-ui/build/agpl-logo.svg
Normal file
25
portal-ui/build/agpl-logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 14 KiB |
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.e33a67ba.chunk.css",
|
||||
"main.js": "./static/js/main.368c5d1e.chunk.js",
|
||||
"main.js.map": "./static/js/main.368c5d1e.chunk.js.map",
|
||||
"main.css": "./static/css/main.ed78990a.chunk.css",
|
||||
"main.js": "./static/js/main.a5d7537d.chunk.js",
|
||||
"main.js.map": "./static/js/main.a5d7537d.chunk.js.map",
|
||||
"runtime-main.js": "./static/js/runtime-main.30f8243a.js",
|
||||
"runtime-main.js.map": "./static/js/runtime-main.30f8243a.js.map",
|
||||
"static/css/2.f324abd6.chunk.css": "./static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.97faa37d.chunk.js": "./static/js/2.97faa37d.chunk.js",
|
||||
"static/js/2.97faa37d.chunk.js.map": "./static/js/2.97faa37d.chunk.js.map",
|
||||
"static/css/2.71021f35.chunk.css": "./static/css/2.71021f35.chunk.css",
|
||||
"static/js/2.050c5ce8.chunk.js": "./static/js/2.050c5ce8.chunk.js",
|
||||
"static/js/2.050c5ce8.chunk.js.map": "./static/js/2.050c5ce8.chunk.js.map",
|
||||
"index.html": "./index.html",
|
||||
"static/css/2.f324abd6.chunk.css.map": "./static/css/2.f324abd6.chunk.css.map",
|
||||
"static/css/main.e33a67ba.chunk.css.map": "./static/css/main.e33a67ba.chunk.css.map",
|
||||
"static/js/2.97faa37d.chunk.js.LICENSE.txt": "./static/js/2.97faa37d.chunk.js.LICENSE.txt"
|
||||
"static/css/2.71021f35.chunk.css.map": "./static/css/2.71021f35.chunk.css.map",
|
||||
"static/css/main.ed78990a.chunk.css.map": "./static/css/main.ed78990a.chunk.css.map",
|
||||
"static/js/2.050c5ce8.chunk.js.LICENSE.txt": "./static/js/2.050c5ce8.chunk.js.LICENSE.txt"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.30f8243a.js",
|
||||
"static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.97faa37d.chunk.js",
|
||||
"static/css/main.e33a67ba.chunk.css",
|
||||
"static/js/main.368c5d1e.chunk.js"
|
||||
"static/css/2.71021f35.chunk.css",
|
||||
"static/js/2.050c5ce8.chunk.js",
|
||||
"static/css/main.ed78990a.chunk.css",
|
||||
"static/js/main.a5d7537d.chunk.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: light)"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: dark)"/><meta name="description" content="MinIO Console"/><link href="./styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="./apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="./favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png"/><link rel="manifest" href="./manifest.json"/><link rel="mask-icon" href="./safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="./static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="./static/css/main.e33a67ba.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="./";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="./static/js/2.97faa37d.chunk.js"></script><script src="./static/js/main.368c5d1e.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: light)"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: dark)"/><meta name="description" content="MinIO Console"/><link href="./styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="./apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="./favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png"/><link rel="manifest" href="./manifest.json"/><link rel="mask-icon" href="./safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="./static/css/2.71021f35.chunk.css" rel="stylesheet"><link href="./static/css/main.ed78990a.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="./";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="./static/js/2.050c5ce8.chunk.js"></script><script src="./static/js/main.a5d7537d.chunk.js"></script></body></html>
|
||||
2
portal-ui/build/static/css/2.71021f35.chunk.css
Normal file
2
portal-ui/build/static/css/2.71021f35.chunk.css
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/css/2.71021f35.chunk.css.map
Normal file
1
portal-ui/build/static/css/2.71021f35.chunk.css.map
Normal file
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
.ReactVirtualized__Table__headerRow{font-weight:700;text-transform:uppercase}.ReactVirtualized__Table__headerRow,.ReactVirtualized__Table__row{display:flex;flex-direction:row;align-items:center}.ReactVirtualized__Table__headerTruncatedText{display:inline-block;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ReactVirtualized__Table__headerColumn,.ReactVirtualized__Table__rowColumn{margin-right:10px;min-width:0}.ReactVirtualized__Table__rowColumn{text-overflow:ellipsis;white-space:nowrap}.ReactVirtualized__Table__headerColumn:first-of-type,.ReactVirtualized__Table__rowColumn:first-of-type{margin-left:10px}.ReactVirtualized__Table__sortableHeaderColumn{cursor:pointer}.ReactVirtualized__Table__sortableHeaderIconContainer{display:flex;align-items:center}.ReactVirtualized__Table__sortableHeaderIcon{flex:0 0 24px;height:1em;width:1em;fill:currentColor}.react-grid-layout{position:relative;transition:height .2s ease}.react-grid-item{transition:all .2s ease;transition-property:left,top}.react-grid-item img{pointer-events:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.react-grid-item.cssTransforms{transition-property:transform}.react-grid-item.resizing{z-index:1;will-change:width,height}.react-grid-item.react-draggable-dragging{transition:none;z-index:3;will-change:transform}.react-grid-item.dropping{visibility:hidden}.react-grid-item.react-grid-placeholder{background:red;opacity:.2;transition-duration:.1s;z-index:2;-webkit-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.react-grid-item>.react-resizable-handle{position:absolute;width:20px;height:20px}.react-grid-item>.react-resizable-handle:after{content:"";position:absolute;right:3px;bottom:3px;width:5px;height:5px;border-right:2px solid rgba(0,0,0,.4);border-bottom:2px solid rgba(0,0,0,.4)}.react-resizable-hide>.react-resizable-handle{display:none}.react-grid-item>.react-resizable-handle.react-resizable-handle-sw{bottom:0;left:0;cursor:sw-resize;transform:rotate(90deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-se{bottom:0;right:0;cursor:se-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-nw{top:0;left:0;cursor:nw-resize;transform:rotate(180deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-ne{top:0;right:0;cursor:ne-resize;transform:rotate(270deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-e,.react-grid-item>.react-resizable-handle.react-resizable-handle-w{top:50%;margin-top:-10px;cursor:ew-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-w{left:0;transform:rotate(135deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-e{right:0;transform:rotate(315deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-n,.react-grid-item>.react-resizable-handle.react-resizable-handle-s{left:50%;margin-left:-10px;cursor:ns-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-n{top:0;transform:rotate(225deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-s{bottom:0;transform:rotate(45deg)}.react-resizable{position:relative}.react-resizable-handle{position:absolute;width:20px;height:20px;background-repeat:no-repeat;background-origin:content-box;box-sizing:border-box;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgd2lkdGg9IjYiIGhlaWdodD0iNiI+PHBhdGggZD0iTTYgNkgwVjQuMmg0LjJWMEg2djZ6IiBvcGFjaXR5PSIuMzAyIi8+PC9zdmc+");background-position:100% 100%;padding:0 3px 3px 0}.react-resizable-handle-sw{bottom:0;left:0;cursor:sw-resize;transform:rotate(90deg)}.react-resizable-handle-se{bottom:0;right:0;cursor:se-resize}.react-resizable-handle-nw{top:0;left:0;cursor:nw-resize;transform:rotate(180deg)}.react-resizable-handle-ne{top:0;right:0;cursor:ne-resize;transform:rotate(270deg)}.react-resizable-handle-e,.react-resizable-handle-w{top:50%;margin-top:-10px;cursor:ew-resize}.react-resizable-handle-w{left:0;transform:rotate(135deg)}.react-resizable-handle-e{right:0;transform:rotate(315deg)}.react-resizable-handle-n,.react-resizable-handle-s{left:50%;margin-left:-10px;cursor:ns-resize}.react-resizable-handle-n{top:0;transform:rotate(225deg)}.react-resizable-handle-s{bottom:0;transform:rotate(45deg)}
|
||||
/*# sourceMappingURL=2.f324abd6.chunk.css.map */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/css/main.ed78990a.chunk.css
Normal file
2
portal-ui/build/static/css/main.ed78990a.chunk.css
Normal file
@@ -0,0 +1,2 @@
|
||||
body{margin:0;font-family:"Lato",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}input.removeArrows::-webkit-inner-spin-button,input.removeArrows::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input.removeArrows[type=number]{-moz-appearance:textfield}
|
||||
/*# sourceMappingURL=main.ed78990a.chunk.css.map */
|
||||
1
portal-ui/build/static/css/main.ed78990a.chunk.css.map
Normal file
1
portal-ui/build/static/css/main.ed78990a.chunk.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack://src/index.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,6BAA+B,CAC/B,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CAGA,4FAEE,uBAAwB,CACxB,QACF,CAGA,gCACE,yBACF","file":"main.ed78990a.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: \"Lato\", sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\n/* Chrome, Safari, Edge, Opera */\ninput.removeArrows::-webkit-outer-spin-button,\ninput.removeArrows::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n/* Firefox */\ninput.removeArrows[type=\"number\"] {\n -moz-appearance: textfield;\n}\n"]}
|
||||
3
portal-ui/build/static/js/2.050c5ce8.chunk.js
Normal file
3
portal-ui/build/static/js/2.050c5ce8.chunk.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/main.a5d7537d.chunk.js
Normal file
2
portal-ui/build/static/js/main.a5d7537d.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/main.a5d7537d.chunk.js.map
Normal file
1
portal-ui/build/static/js/main.a5d7537d.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 6.1 KiB |
@@ -16,7 +16,7 @@
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon, SvgIconProps } from "@mui/material";
|
||||
import { IIcon } from "./props";
|
||||
|
||||
const RefreshIcon = (props: SvgIconProps) => {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
|
||||
@@ -308,6 +308,7 @@ const AddBucket = ({
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/installation/deploy-minio-distributed.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Distributed Mode
|
||||
</a>{" "}
|
||||
|
||||
@@ -68,17 +68,6 @@ import {
|
||||
setErrorSnackMessage,
|
||||
setSnackBarMessage,
|
||||
} from "../../../../../../actions";
|
||||
import SetRetention from "./SetRetention";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
import DeleteObject from "../ListObjects/DeleteObject";
|
||||
import AddTagModal from "./AddTagModal";
|
||||
import DeleteTagModal from "./DeleteTagModal";
|
||||
import SetLegalHoldModal from "./SetLegalHoldModal";
|
||||
import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle";
|
||||
import EditIcon from "../../../../../../icons/EditIcon";
|
||||
import SearchIcon from "../../../../../../icons/SearchIcon";
|
||||
import ObjectBrowserIcon from "../../../../../../icons/ObjectBrowserIcon";
|
||||
import PreviewFileContent from "../Preview/PreviewFileContent";
|
||||
import { decodeFileName, encodeFileName } from "../../../../../../common/utils";
|
||||
import { BucketInfo } from "../../../types";
|
||||
import { displayComponent } from "../../../../../../utils/permissions";
|
||||
@@ -93,6 +82,18 @@ import {
|
||||
S3_PUT_OBJECT_RETENTION,
|
||||
S3_PUT_OBJECT_TAGGING,
|
||||
} from "../../../../../../types";
|
||||
import SetRetention from "./SetRetention";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
import DeleteObject from "../ListObjects/DeleteObject";
|
||||
import AddTagModal from "./AddTagModal";
|
||||
import DeleteTagModal from "./DeleteTagModal";
|
||||
import SetLegalHoldModal from "./SetLegalHoldModal";
|
||||
import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle";
|
||||
import EditIcon from "../../../../../../icons/EditIcon";
|
||||
import SearchIcon from "../../../../../../icons/SearchIcon";
|
||||
import ObjectBrowserIcon from "../../../../../../icons/ObjectBrowserIcon";
|
||||
import PreviewFileContent from "../Preview/PreviewFileContent";
|
||||
import RestoreFileVersion from "./RestoreFileVersion";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -272,6 +273,8 @@ const ObjectDetails = ({
|
||||
const [selectedTab, setSelectedTab] = useState<number>(0);
|
||||
const [loadingBucket, setLoadingBucket] = useState<boolean>(false);
|
||||
const [bucketInfo, setBucketInfo] = useState<any>(null);
|
||||
const [restoreVersionOpen, setRestoreVersionOpen] = useState<boolean>(false);
|
||||
const [restoreVersion, setRestoreVersion] = useState<string>("");
|
||||
|
||||
const internalPaths = get(match.params, "subpaths", "");
|
||||
const internalPathsDecoded = decodeFileName(internalPaths) || "";
|
||||
@@ -470,6 +473,14 @@ const ObjectDetails = ({
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "restore",
|
||||
onClick: (item: IFileInfo) => {
|
||||
setRestoreVersion(item.version_id || "");
|
||||
setRestoreVersionOpen(true);
|
||||
},
|
||||
disableButtonFunction: (_: any) => !distributedSetup,
|
||||
},
|
||||
];
|
||||
|
||||
const filteredRecords = versions.filter((version) => {
|
||||
@@ -520,6 +531,16 @@ const ObjectDetails = ({
|
||||
}
|
||||
};
|
||||
|
||||
const closeRestoreModal = (reloadObjectData: boolean) => {
|
||||
setRestoreVersionOpen(false);
|
||||
setRestoreVersion("");
|
||||
|
||||
if (reloadObjectData) {
|
||||
setLoadObjectData(true);
|
||||
setMetadataLoad(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{shareFileModalOpen && actualInfo && (
|
||||
@@ -577,6 +598,16 @@ const ObjectDetails = ({
|
||||
actualInfo={actualInfo}
|
||||
/>
|
||||
)}
|
||||
{restoreVersionOpen && actualInfo && (
|
||||
<RestoreFileVersion
|
||||
restoreOpen={restoreVersionOpen}
|
||||
bucketName={bucketName}
|
||||
versionID={restoreVersion}
|
||||
objectPath={actualInfo.name}
|
||||
onCloseAndUpdate={closeRestoreModal}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Grid container>
|
||||
{!actualInfo && (
|
||||
<Grid item xs={12}>
|
||||
@@ -911,7 +942,7 @@ const ObjectDetails = ({
|
||||
columns={[
|
||||
{
|
||||
label: "",
|
||||
width: 20,
|
||||
width: 40,
|
||||
renderFullObject: true,
|
||||
renderFunction: (r) => {
|
||||
const versOrd =
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// 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 React, { useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
} from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { connect } from "react-redux";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import { setErrorSnackMessage } from "../../../../../../actions";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import { encodeFileName } from "../../../../../../common/utils";
|
||||
import api from "../../../../../../common/api";
|
||||
|
||||
interface IRestoreFileVersion {
|
||||
classes: any;
|
||||
restoreOpen: boolean;
|
||||
bucketName: string;
|
||||
versionID: string;
|
||||
objectPath: string;
|
||||
onCloseAndUpdate: (refresh: boolean) => void;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
pathLabel: {
|
||||
marginTop: 0,
|
||||
marginBottom: 32,
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const RestoreFileVersion = ({
|
||||
classes,
|
||||
versionID,
|
||||
bucketName,
|
||||
objectPath,
|
||||
restoreOpen,
|
||||
onCloseAndUpdate,
|
||||
}: IRestoreFileVersion) => {
|
||||
const [restoreLoading, setRestoreLoading] = useState<boolean>(false);
|
||||
|
||||
const restoreVersion = () => {
|
||||
setRestoreLoading(true);
|
||||
|
||||
api
|
||||
.invoke(
|
||||
"PUT",
|
||||
`/api/v1/buckets/${bucketName}/objects/restore?prefix=${encodeFileName(
|
||||
objectPath
|
||||
)}&version_id=${versionID}`
|
||||
)
|
||||
.then((res: any) => {
|
||||
setRestoreLoading(false);
|
||||
onCloseAndUpdate(true);
|
||||
})
|
||||
.catch((error: ErrorResponseHandler) => {
|
||||
setErrorSnackMessage(error);
|
||||
setRestoreLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={restoreOpen}
|
||||
onClose={() => {
|
||||
onCloseAndUpdate(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Restore File Version</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to restore <b>{objectPath}</b> <br /> with
|
||||
Version ID: <b className={classes.wrapText}>{versionID}</b>?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onCloseAndUpdate(false);
|
||||
}}
|
||||
color="primary"
|
||||
disabled={restoreLoading}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={restoreVersion}
|
||||
color="primary"
|
||||
autoFocus
|
||||
disabled={restoreLoading}
|
||||
>
|
||||
Restore
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = null;
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setErrorSnackMessage,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
export default withStyles(styles)(connector(RestoreFileVersion));
|
||||
@@ -25,7 +25,12 @@ import DisableIcon from "./TableActionIcons/DisableIcon";
|
||||
import FormatDriveIcon from "./TableActionIcons/FormatDriveIcon";
|
||||
import EditIcon from "../../../../icons/EditIcon";
|
||||
import TrashIcon from "../../../../icons/TrashIcon";
|
||||
import { IAMPoliciesIcon, PreviewIcon, ShareIcon } from "../../../../icons";
|
||||
import {
|
||||
IAMPoliciesIcon,
|
||||
PreviewIcon,
|
||||
ShareIcon,
|
||||
HistoryIcon,
|
||||
} from "../../../../icons";
|
||||
import DownloadIcon from "../../../../icons/DownloadIcon";
|
||||
|
||||
const styles = () =>
|
||||
@@ -78,6 +83,8 @@ const defineIcon = (type: string, selected: boolean) => {
|
||||
return <FormatDriveIcon active={selected} />;
|
||||
case "preview":
|
||||
return <PreviewIcon />;
|
||||
case "restore":
|
||||
return <HistoryIcon />;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -483,7 +483,7 @@ const elementActions = (
|
||||
// Function to calculate the options column width according elements inside
|
||||
const calculateOptionsSize = (containerWidth: number, totalOptions: number) => {
|
||||
const minContainerSize = 80;
|
||||
const sizeOptions = totalOptions * 45;
|
||||
const sizeOptions = totalOptions * 45 + 15;
|
||||
|
||||
if (sizeOptions < minContainerSize) {
|
||||
return minContainerSize;
|
||||
|
||||
@@ -31,5 +31,5 @@ export interface ISessionResponse {
|
||||
features: string[];
|
||||
operator: boolean;
|
||||
distributedMode: boolean;
|
||||
policy: ISessionPolicy,
|
||||
policy: ISessionPolicy;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ type MinioClient interface {
|
||||
getObjectLockConfig(ctx context.Context, bucketName string) (lock string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
getLifecycleRules(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error)
|
||||
setBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error
|
||||
copyObject(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error)
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
@@ -195,6 +196,10 @@ func (c minioClient) setBucketLifecycle(ctx context.Context, bucketName string,
|
||||
return c.client.SetBucketLifecycle(ctx, bucketName, config)
|
||||
}
|
||||
|
||||
func (c minioClient) copyObject(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error) {
|
||||
return c.client.CopyObject(ctx, dst, src)
|
||||
}
|
||||
|
||||
// MCClient interface with all functions to be implemented
|
||||
// by mock when testing, it should include all mc/S3Client respective api calls
|
||||
// that are used within this project.
|
||||
|
||||
@@ -1295,6 +1295,46 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/buckets/{bucket_name}/objects/restore": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"UserAPI"
|
||||
],
|
||||
"summary": "Restore Object to a selected version",
|
||||
"operationId": "PutObjectRestore",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "bucket_name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "prefix",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "version_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/buckets/{bucket_name}/objects/retention": {
|
||||
"put": {
|
||||
"tags": [
|
||||
@@ -6956,6 +6996,46 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/buckets/{bucket_name}/objects/restore": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"UserAPI"
|
||||
],
|
||||
"summary": "Restore Object to a selected version",
|
||||
"operationId": "PutObjectRestore",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "bucket_name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "prefix",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "version_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/buckets/{bucket_name}/objects/retention": {
|
||||
"put": {
|
||||
"tags": [
|
||||
|
||||
@@ -290,6 +290,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
||||
UserAPIPutObjectLegalHoldHandler: user_api.PutObjectLegalHoldHandlerFunc(func(params user_api.PutObjectLegalHoldParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation user_api.PutObjectLegalHold has not yet been implemented")
|
||||
}),
|
||||
UserAPIPutObjectRestoreHandler: user_api.PutObjectRestoreHandlerFunc(func(params user_api.PutObjectRestoreParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation user_api.PutObjectRestore has not yet been implemented")
|
||||
}),
|
||||
UserAPIPutObjectRetentionHandler: user_api.PutObjectRetentionHandlerFunc(func(params user_api.PutObjectRetentionParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation user_api.PutObjectRetention has not yet been implemented")
|
||||
}),
|
||||
@@ -564,6 +567,8 @@ type ConsoleAPI struct {
|
||||
AdminAPIProfilingStopHandler admin_api.ProfilingStopHandler
|
||||
// UserAPIPutObjectLegalHoldHandler sets the operation handler for the put object legal hold operation
|
||||
UserAPIPutObjectLegalHoldHandler user_api.PutObjectLegalHoldHandler
|
||||
// UserAPIPutObjectRestoreHandler sets the operation handler for the put object restore operation
|
||||
UserAPIPutObjectRestoreHandler user_api.PutObjectRestoreHandler
|
||||
// UserAPIPutObjectRetentionHandler sets the operation handler for the put object retention operation
|
||||
UserAPIPutObjectRetentionHandler user_api.PutObjectRetentionHandler
|
||||
// UserAPIPutObjectTagsHandler sets the operation handler for the put object tags operation
|
||||
@@ -922,6 +927,9 @@ func (o *ConsoleAPI) Validate() error {
|
||||
if o.UserAPIPutObjectLegalHoldHandler == nil {
|
||||
unregistered = append(unregistered, "user_api.PutObjectLegalHoldHandler")
|
||||
}
|
||||
if o.UserAPIPutObjectRestoreHandler == nil {
|
||||
unregistered = append(unregistered, "user_api.PutObjectRestoreHandler")
|
||||
}
|
||||
if o.UserAPIPutObjectRetentionHandler == nil {
|
||||
unregistered = append(unregistered, "user_api.PutObjectRetentionHandler")
|
||||
}
|
||||
@@ -1396,6 +1404,10 @@ func (o *ConsoleAPI) initHandlerCache() {
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/buckets/{bucket_name}/objects/restore"] = user_api.NewPutObjectRestore(o.context, o.UserAPIPutObjectRestoreHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/buckets/{bucket_name}/objects/retention"] = user_api.NewPutObjectRetention(o.context, o.UserAPIPutObjectRetentionHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
|
||||
88
restapi/operations/user_api/put_object_restore.go
Normal file
88
restapi/operations/user_api/put_object_restore.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
package user_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// PutObjectRestoreHandlerFunc turns a function with the right signature into a put object restore handler
|
||||
type PutObjectRestoreHandlerFunc func(PutObjectRestoreParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn PutObjectRestoreHandlerFunc) Handle(params PutObjectRestoreParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// PutObjectRestoreHandler interface for that can handle valid put object restore params
|
||||
type PutObjectRestoreHandler interface {
|
||||
Handle(PutObjectRestoreParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewPutObjectRestore creates a new http.Handler for the put object restore operation
|
||||
func NewPutObjectRestore(ctx *middleware.Context, handler PutObjectRestoreHandler) *PutObjectRestore {
|
||||
return &PutObjectRestore{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/* PutObjectRestore swagger:route PUT /buckets/{bucket_name}/objects/restore UserAPI putObjectRestore
|
||||
|
||||
Restore Object to a selected version
|
||||
|
||||
*/
|
||||
type PutObjectRestore struct {
|
||||
Context *middleware.Context
|
||||
Handler PutObjectRestoreHandler
|
||||
}
|
||||
|
||||
func (o *PutObjectRestore) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewPutObjectRestoreParams()
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
if aCtx != nil {
|
||||
*r = *aCtx
|
||||
}
|
||||
var principal *models.Principal
|
||||
if uprinc != nil {
|
||||
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||
}
|
||||
|
||||
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||
|
||||
}
|
||||
154
restapi/operations/user_api/put_object_restore_parameters.go
Normal file
154
restapi/operations/user_api/put_object_restore_parameters.go
Normal file
@@ -0,0 +1,154 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
package user_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// NewPutObjectRestoreParams creates a new PutObjectRestoreParams object
|
||||
//
|
||||
// There are no default values defined in the spec.
|
||||
func NewPutObjectRestoreParams() PutObjectRestoreParams {
|
||||
|
||||
return PutObjectRestoreParams{}
|
||||
}
|
||||
|
||||
// PutObjectRestoreParams contains all the bound params for the put object restore operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters PutObjectRestore
|
||||
type PutObjectRestoreParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
BucketName string
|
||||
/*
|
||||
Required: true
|
||||
In: query
|
||||
*/
|
||||
Prefix string
|
||||
/*
|
||||
Required: true
|
||||
In: query
|
||||
*/
|
||||
VersionID string
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewPutObjectRestoreParams() beforehand.
|
||||
func (o *PutObjectRestoreParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
qs := runtime.Values(r.URL.Query())
|
||||
|
||||
rBucketName, rhkBucketName, _ := route.Params.GetOK("bucket_name")
|
||||
if err := o.bindBucketName(rBucketName, rhkBucketName, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qPrefix, qhkPrefix, _ := qs.GetOK("prefix")
|
||||
if err := o.bindPrefix(qPrefix, qhkPrefix, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qVersionID, qhkVersionID, _ := qs.GetOK("version_id")
|
||||
if err := o.bindVersionID(qVersionID, qhkVersionID, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindBucketName binds and validates parameter BucketName from path.
|
||||
func (o *PutObjectRestoreParams) bindBucketName(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
o.BucketName = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindPrefix binds and validates parameter Prefix from query.
|
||||
func (o *PutObjectRestoreParams) bindPrefix(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
if !hasKey {
|
||||
return errors.Required("prefix", "query", rawData)
|
||||
}
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if err := validate.RequiredString("prefix", "query", raw); err != nil {
|
||||
return err
|
||||
}
|
||||
o.Prefix = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindVersionID binds and validates parameter VersionID from query.
|
||||
func (o *PutObjectRestoreParams) bindVersionID(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
if !hasKey {
|
||||
return errors.Required("version_id", "query", rawData)
|
||||
}
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if err := validate.RequiredString("version_id", "query", raw); err != nil {
|
||||
return err
|
||||
}
|
||||
o.VersionID = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
113
restapi/operations/user_api/put_object_restore_responses.go
Normal file
113
restapi/operations/user_api/put_object_restore_responses.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
package user_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// PutObjectRestoreOKCode is the HTTP code returned for type PutObjectRestoreOK
|
||||
const PutObjectRestoreOKCode int = 200
|
||||
|
||||
/*PutObjectRestoreOK A successful response.
|
||||
|
||||
swagger:response putObjectRestoreOK
|
||||
*/
|
||||
type PutObjectRestoreOK struct {
|
||||
}
|
||||
|
||||
// NewPutObjectRestoreOK creates PutObjectRestoreOK with default headers values
|
||||
func NewPutObjectRestoreOK() *PutObjectRestoreOK {
|
||||
|
||||
return &PutObjectRestoreOK{}
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *PutObjectRestoreOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||
|
||||
rw.WriteHeader(200)
|
||||
}
|
||||
|
||||
/*PutObjectRestoreDefault Generic error response.
|
||||
|
||||
swagger:response putObjectRestoreDefault
|
||||
*/
|
||||
type PutObjectRestoreDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewPutObjectRestoreDefault creates PutObjectRestoreDefault with default headers values
|
||||
func NewPutObjectRestoreDefault(code int) *PutObjectRestoreDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &PutObjectRestoreDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the put object restore default response
|
||||
func (o *PutObjectRestoreDefault) WithStatusCode(code int) *PutObjectRestoreDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the put object restore default response
|
||||
func (o *PutObjectRestoreDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the put object restore default response
|
||||
func (o *PutObjectRestoreDefault) WithPayload(payload *models.Error) *PutObjectRestoreDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the put object restore default response
|
||||
func (o *PutObjectRestoreDefault) SetPayload(payload *models.Error) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *PutObjectRestoreDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
133
restapi/operations/user_api/put_object_restore_urlbuilder.go
Normal file
133
restapi/operations/user_api/put_object_restore_urlbuilder.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
package user_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
golangswaggerpaths "path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PutObjectRestoreURL generates an URL for the put object restore operation
|
||||
type PutObjectRestoreURL struct {
|
||||
BucketName string
|
||||
|
||||
Prefix string
|
||||
VersionID string
|
||||
|
||||
_basePath string
|
||||
// avoid unkeyed usage
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *PutObjectRestoreURL) WithBasePath(bp string) *PutObjectRestoreURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *PutObjectRestoreURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *PutObjectRestoreURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/buckets/{bucket_name}/objects/restore"
|
||||
|
||||
bucketName := o.BucketName
|
||||
if bucketName != "" {
|
||||
_path = strings.Replace(_path, "{bucket_name}", bucketName, -1)
|
||||
} else {
|
||||
return nil, errors.New("bucketName is required on PutObjectRestoreURL")
|
||||
}
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
_basePath = "/api/v1"
|
||||
}
|
||||
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||
|
||||
qs := make(url.Values)
|
||||
|
||||
prefixQ := o.Prefix
|
||||
if prefixQ != "" {
|
||||
qs.Set("prefix", prefixQ)
|
||||
}
|
||||
|
||||
versionIDQ := o.VersionID
|
||||
if versionIDQ != "" {
|
||||
qs.Set("version_id", versionIDQ)
|
||||
}
|
||||
|
||||
_result.RawQuery = qs.Encode()
|
||||
|
||||
return &_result, nil
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *PutObjectRestoreURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if u == nil {
|
||||
panic("url can't be nil")
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *PutObjectRestoreURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *PutObjectRestoreURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on PutObjectRestoreURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on PutObjectRestoreURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base.Scheme = scheme
|
||||
base.Host = host
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *PutObjectRestoreURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
@@ -47,6 +47,7 @@ var minioSetObjectLockConfigMock func(ctx context.Context, bucketName string, mo
|
||||
var minioGetBucketObjectLockConfigMock func(ctx context.Context, bucketName string) (mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
var minioGetObjectLockConfigMock func(ctx context.Context, bucketName string) (lock string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
var minioSetVersioningMock func(ctx context.Context, state string) *probe.Error
|
||||
var minioCopyObjectMock func(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error)
|
||||
|
||||
// Define a mock struct of minio Client interface implementation
|
||||
type minioClientMock struct {
|
||||
@@ -100,6 +101,10 @@ func (mc minioClientMock) getObjectLockConfig(ctx context.Context, bucketName st
|
||||
return minioGetObjectLockConfigMock(ctx, bucketName)
|
||||
}
|
||||
|
||||
func (mc minioClientMock) copyObject(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error) {
|
||||
return minioCopyObjectMock(ctx, dst, src)
|
||||
}
|
||||
|
||||
func (c s3ClientMock) setVersioning(ctx context.Context, state string) *probe.Error {
|
||||
return minioSetVersioningMock(ctx, state)
|
||||
}
|
||||
|
||||
@@ -178,6 +178,13 @@ func registerObjectsHandlers(api *operations.ConsoleAPI) {
|
||||
}
|
||||
return user_api.NewPutObjectTagsOK()
|
||||
})
|
||||
//Restore file version
|
||||
api.UserAPIPutObjectRestoreHandler = user_api.PutObjectRestoreHandlerFunc(func(params user_api.PutObjectRestoreParams, session *models.Principal) middleware.Responder {
|
||||
if err := getPutObjectRestoreResponse(session, params); err != nil {
|
||||
return user_api.NewPutObjectRestoreDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
return user_api.NewPutObjectRestoreOK()
|
||||
})
|
||||
}
|
||||
|
||||
// getListObjectsResponse returns a list of objects
|
||||
@@ -762,6 +769,63 @@ func putObjectTags(ctx context.Context, client MinioClient, bucketName, prefix,
|
||||
return client.putObjectTagging(ctx, bucketName, prefix, otags, opt)
|
||||
}
|
||||
|
||||
// Restore Object Version
|
||||
func getPutObjectRestoreResponse(session *models.Principal, params user_api.PutObjectRestoreParams) *models.Error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||
defer cancel()
|
||||
mClient, err := newMinioClient(session)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
}
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
minioClient := minioClient{client: mClient}
|
||||
|
||||
var prefix string
|
||||
if params.Prefix != "" {
|
||||
encodedPrefix := SanitizeEncodedPrefix(params.Prefix)
|
||||
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
}
|
||||
prefix = string(decodedPrefix)
|
||||
}
|
||||
|
||||
err = restoreObject(ctx, minioClient, params.BucketName, prefix, params.VersionID)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func restoreObject(ctx context.Context, client MinioClient, bucketName, prefix, versionID string) error {
|
||||
// Select required version
|
||||
srcOpts := minio.CopySrcOptions{
|
||||
Bucket: bucketName,
|
||||
Object: prefix,
|
||||
VersionID: versionID,
|
||||
}
|
||||
|
||||
// Destination object, same as current bucket
|
||||
replaceMetadata := make(map[string]string)
|
||||
replaceMetadata["copy-source"] = versionID
|
||||
|
||||
dstOpts := minio.CopyDestOptions{
|
||||
Bucket: bucketName,
|
||||
Object: prefix,
|
||||
UserMetadata: replaceMetadata,
|
||||
}
|
||||
|
||||
// Copy object call
|
||||
_, err := client.copyObject(ctx, dstOpts, srcOpts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newClientURL returns an abstracted URL for filesystems and object storage.
|
||||
func newClientURL(urlStr string) *mc.ClientURL {
|
||||
scheme, rest := getScheme(urlStr)
|
||||
|
||||
@@ -613,6 +613,33 @@ paths:
|
||||
tags:
|
||||
- UserAPI
|
||||
|
||||
/buckets/{bucket_name}/objects/restore:
|
||||
put:
|
||||
summary: Restore Object to a selected version
|
||||
operationId: PutObjectRestore
|
||||
parameters:
|
||||
- name: bucket_name
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
- name: prefix
|
||||
in: query
|
||||
required: true
|
||||
type: string
|
||||
- name: version_id
|
||||
in: query
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: A successful response.
|
||||
default:
|
||||
description: Generic error response.
|
||||
schema:
|
||||
$ref: "#/definitions/error"
|
||||
tags:
|
||||
- UserAPI
|
||||
|
||||
/buckets/{name}/set-policy:
|
||||
put:
|
||||
summary: Bucket Set Policy
|
||||
|
||||
Reference in New Issue
Block a user