Connected Share object modal (#440)

This commit is contained in:
Alex
2020-11-24 20:56:32 -06:00
committed by GitHub
parent 2caad9964f
commit 114bc364e3
7 changed files with 391 additions and 171 deletions

File diff suppressed because one or more lines are too long

View File

@@ -282,6 +282,8 @@ const ObjectDetails = ({
<ShareFile
open={shareFileModalOpen}
closeModalAndRefresh={closeShareModal}
bucketName={bucketName}
dataObject={actualInfo}
/>
)}
{retentionModalOpen && (

View File

@@ -115,6 +115,7 @@ const SetRetention = ({
disableOptions={dateFieldDisabled()}
ref={dateElement}
borderBottom={true}
onDateChange={() => {}}
/>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>

View File

@@ -1,6 +1,8 @@
import React, { useState } from "react";
import CopyToClipboard from "react-copy-to-clipboard";
import React, { useState, useEffect } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import CopyToClipboard from "react-copy-to-clipboard";
import Typography from "@material-ui/core/Typography";
import Snackbar from "@material-ui/core/Snackbar";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import {
@@ -10,6 +12,9 @@ import {
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import DateSelector from "../../../../Common/FormComponents/DateSelector/DateSelector";
import { CopyIcon } from "../../../../../../icons";
import api from "../../../../../../common/api";
import get from "lodash/get";
import { IFileInfo } from "./types";
const styles = (theme: Theme) =>
createStyles({
@@ -19,6 +24,9 @@ const styles = (theme: Theme) =>
modalContent: {
paddingBottom: 53,
},
errorBlock: {
color: "red",
},
...modalBasic,
...predefinedList,
});
@@ -26,6 +34,8 @@ const styles = (theme: Theme) =>
interface IShareFileProps {
classes: any;
open: boolean;
bucketName: string;
dataObject: IFileInfo;
closeModalAndRefresh: () => void;
}
@@ -33,45 +43,159 @@ const ShareFile = ({
classes,
open,
closeModalAndRefresh,
bucketName,
dataObject,
}: IShareFileProps) => {
return (
<ModalWrapper
title="Share File"
modalOpen={open}
onClose={() => {
closeModalAndRefresh();
const [shareURL, setShareURL] = useState("");
const [isLoadingFile, setIsLoadingFile] = useState(false);
const [error, setError] = useState("");
const [selectedDate, setSelectedDate] = useState("");
const [dateValid, setDateValid] = useState(true);
const [openSnack, setOpenSnack] = useState(false);
const [snackBarMessage, setSnackbarMessage] = useState("");
const showSnackBarMessage = (text: string) => {
setSnackbarMessage(text);
setOpenSnack(true);
};
const closeSnackBar = () => {
setSnackbarMessage("");
setOpenSnack(false);
};
const dateChanged = (newDate: string, isValid: boolean) => {
setDateValid(isValid);
if (isValid) {
setSelectedDate(newDate);
return;
}
setShareURL("");
setSelectedDate("");
};
useEffect(() => {
if (dateValid) {
setIsLoadingFile(true);
const slDate = new Date(`${selectedDate}T23:59:59`);
const currDate = new Date();
const diffDate = slDate.getTime() - currDate.getTime();
if (diffDate < 0) {
setError("Selected date must be greater than current time.");
setShareURL("");
setIsLoadingFile(false);
return;
}
if (diffDate > 604800000) {
setError("You can share a file only for less than 7 days.");
setShareURL("");
setIsLoadingFile(false);
return;
}
api
.invoke(
"GET",
`/api/v1/buckets/${bucketName}/objects/share?prefix=${
dataObject.name
}&version_id=${dataObject.version_id}${
selectedDate !== "" ? `&expires=${diffDate}ms` : ""
}`
)
.then((res: string) => {
setShareURL(res);
setError("");
setIsLoadingFile(false);
})
.catch((error) => {
setError(error);
setShareURL("");
setIsLoadingFile(false);
});
return;
}
setShareURL("");
}, [dataObject, selectedDate]);
const snackBarAction = (
<Button
color="secondary"
size="small"
onClick={() => {
closeSnackBar();
}}
>
<Grid container className={classes.modalContent}>
<Grid item xs={12} className={classes.dateContainer}>
<DateSelector
id="date"
label="Active until"
borderBottom={false}
addSwitch={true}
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={10} className={classes.predefinedList}>
{"https://somelink.will/go/here"}
</Grid>
<Grid item xs={2} className={classes.copyButtonContainer}>
<CopyToClipboard text={"https://somelink.will/go/here"}>
<Button
variant="contained"
color="primary"
startIcon={<CopyIcon />}
onClick={() => {
console.log("copied!");
}}
Dismiss
</Button>
);
return (
<React.Fragment>
{openSnack && (
<Snackbar
open={openSnack}
message={snackBarMessage}
action={snackBarAction}
/>
)}
<ModalWrapper
title="Share File"
modalOpen={open}
onClose={() => {
closeModalAndRefresh();
}}
>
<Grid container className={classes.modalContent}>
{error !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Copy
</Button>
</CopyToClipboard>
{error}
</Typography>
</Grid>
)}
<Grid item xs={12} className={classes.dateContainer}>
<DateSelector
id="date"
label="Active until"
borderBottom={false}
addSwitch={true}
onDateChange={dateChanged}
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={10} className={classes.predefinedList}>
{shareURL}
</Grid>
<Grid item xs={2} className={classes.copyButtonContainer}>
<CopyToClipboard text={shareURL}>
<Button
variant="contained"
color="primary"
startIcon={<CopyIcon />}
onClick={() => {
showSnackBarMessage("Share URL Copied to clipboard");
}}
disabled={shareURL === "" || isLoadingFile}
>
Copy
</Button>
</CopyToClipboard>
</Grid>
</Grid>
</Grid>
</Grid>
</ModalWrapper>
</ModalWrapper>
</React.Fragment>
);
};

View File

@@ -1,4 +1,25 @@
import React, { useState, forwardRef, useImperativeHandle } from "react";
// This file is part of MinIO Console Server
// Copyright (c) 2020 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,
forwardRef,
useImperativeHandle,
useEffect,
} from "react";
import clsx from "clsx";
import Grid from "@material-ui/core/Grid";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
@@ -11,6 +32,7 @@ import MenuItem from "@material-ui/core/MenuItem";
import InputBase from "@material-ui/core/InputBase";
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
import FormSwitchWrapper from "../FormSwitchWrapper/FormSwitchWrapper";
import { days, months, validDate, years } from "./utils";
const styles = (theme: Theme) =>
createStyles({
@@ -64,6 +86,7 @@ interface IDateSelectorProps {
addSwitch?: boolean;
tooltip?: string;
borderBottom?: boolean;
onDateChange: (date: string, isValid: boolean) => any;
}
const DateSelector = forwardRef(
@@ -76,6 +99,7 @@ const DateSelector = forwardRef(
addSwitch = false,
tooltip = "",
borderBottom = false,
onDateChange,
}: IDateSelectorProps,
ref: any
) => {
@@ -86,6 +110,11 @@ const DateSelector = forwardRef(
const [day, setDay] = useState<string>("");
const [year, setYear] = useState<string>("");
useEffect(() => {
const [isValid, dateString] = validDate(year, month, day);
onDateChange(dateString, isValid);
}, [month, day, year]);
const resetDate = () => {
setMonth("");
setDay("");
@@ -142,13 +171,16 @@ const DateSelector = forwardRef(
</InputLabel>
{addSwitch && (
<FormSwitchWrapper
indicatorLabels={["Specific Date", "Always active"]}
indicatorLabels={["Specific Date", "Default (7 Days)"]}
checked={dateEnabled}
value={"date_enabled"}
id="date-status"
name="date-status"
onChange={(e) => {
setDateEnabled(e.target.checked);
if (!e.target.checked) {
onDateChange("", true);
}
}}
switchOnly
/>
@@ -171,15 +203,14 @@ const DateSelector = forwardRef(
<MenuItem value="" disabled>
{"<Month>"}
</MenuItem>
<MenuItem value={"1"}>January</MenuItem>
{/* {options.map((option) => (
<MenuItem
value={option.value}
key={`select-${name}-${option.label}`}
>
{option.label}
</MenuItem>
))} */}
{months.map((option) => (
<MenuItem
value={option.value}
key={`select-${id}-monthOP-${option.label}`}
>
{option.label}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
@@ -197,16 +228,14 @@ const DateSelector = forwardRef(
<MenuItem value="" disabled>
{"<Day>"}
</MenuItem>
<MenuItem value={"1"}>1</MenuItem>
<MenuItem value={"2"}>2</MenuItem>
{/* {options.map((option) => (
<MenuItem
value={option.value}
key={`select-${name}-${option.label}`}
>
{option.label}
</MenuItem>
))} */}
{days.map((dayNumber) => (
<MenuItem
value={dayNumber}
key={`select-${id}-dayOP-${dayNumber}`}
>
{dayNumber}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
@@ -224,16 +253,11 @@ const DateSelector = forwardRef(
<MenuItem value="" disabled>
{"<Year>"}
</MenuItem>
<MenuItem value={"2020"}>2020</MenuItem>
<MenuItem value={"2021"}>2021</MenuItem>
{/* {options.map((option) => (
<MenuItem
value={option.value}
key={`select-${name}-${option.label}`}
>
{option.label}
</MenuItem>
))} */}
{years.map((year) => (
<MenuItem value={year} key={`select-${id}-yearOP-${year}`}>
{year}
</MenuItem>
))}
</Select>
</FormControl>
</div>

View File

@@ -0,0 +1,62 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 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/>.
export const months = [
{ value: "01", label: "January" },
{ value: "02", label: "February" },
{ value: "03", label: "March" },
{ value: "04", label: "April" },
{ value: "05", label: "May" },
{ value: "06", label: "June" },
{ value: "07", label: "July" },
{ value: "08", label: "August" },
{ value: "09", label: "September" },
{ value: "10", label: "October" },
{ value: "11", label: "November" },
{ value: "12", label: "December" },
];
export const days = Array.from(Array(31), (_, num) => num + 1);
const currentYear = new Date().getFullYear();
export const years = Array.from(
Array(25),
(_, numYear) => numYear + currentYear
);
export const validDate = (
year: string,
month: string,
day: string
): [boolean, string] => {
const currentDate = Date.parse(`${year}-${month}-${day}`);
if (isNaN(currentDate)) {
return [false, ""];
}
const parsedMonth = parseInt(month);
const parsedDay = parseInt(day);
const monthForString = parsedMonth < 10 ? `0${parsedMonth}` : parsedMonth;
const dayForString = parsedDay < 10 ? `0${parsedDay}` : parsedDay;
const parsedDate = new Date(currentDate).toISOString().split("T")[0];
const dateString = `${year}-${monthForString}-${dayForString}`;
return [parsedDate === dateString, dateString];
};

View File

@@ -184,6 +184,13 @@ export const predefinedList = {
fontSize: 12,
fontWeight: 600,
minHeight: 41,
height: 41,
overflowX: "auto" as const,
whiteSpace: "nowrap" as const,
scrollbarWidth: "none" as const,
"&::-webkit-scrollbar": {
display: "none",
},
},
};