Improved the Share File modal (#1083)
This commit is contained in:
@@ -9,3 +9,15 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
|
||||
/* Chrome, Safari, Edge, Opera */
|
||||
input.removeArrows::-webkit-outer-spin-button,
|
||||
input.removeArrows::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
input.removeArrows[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
@@ -32,8 +32,8 @@ import { AppState } from "../../../../../../store";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import api from "../../../../../../common/api";
|
||||
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
|
||||
import DateSelector from "../../../../Common/FormComponents/DateSelector/DateSelector";
|
||||
import PredefinedList from "../../../../Common/FormComponents/PredefinedList/PredefinedList";
|
||||
import DaysSelector from "../../../../Common/FormComponents/DaysSelector/DaysSelector";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -72,6 +72,8 @@ const ShareFile = ({
|
||||
const [selectedDate, setSelectedDate] = useState<string>("");
|
||||
const [dateValid, setDateValid] = useState<boolean>(true);
|
||||
|
||||
const initialDate = new Date();
|
||||
|
||||
const dateChanged = (newDate: string, isValid: boolean) => {
|
||||
setDateValid(isValid);
|
||||
if (isValid) {
|
||||
@@ -79,6 +81,7 @@ const ShareFile = ({
|
||||
return;
|
||||
}
|
||||
setSelectedDate("");
|
||||
setShareURL("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -86,54 +89,33 @@ const ShareFile = ({
|
||||
setIsLoadingFile(true);
|
||||
setShareURL("");
|
||||
|
||||
const slDate = new Date(`${selectedDate}T23:59:59`);
|
||||
const slDate = new Date(`${selectedDate}`);
|
||||
const currDate = new Date();
|
||||
|
||||
const diffDate = slDate.getTime() - currDate.getTime();
|
||||
|
||||
const versID = distributedSetup ? dataObject.version_id : "null";
|
||||
if (diffDate > 0) {
|
||||
const versID = distributedSetup ? dataObject.version_id : "null";
|
||||
|
||||
if (diffDate < 0) {
|
||||
setModalErrorSnackMessage({
|
||||
errorMessage: "Selected date must be greater than current time.",
|
||||
detailedError: "",
|
||||
});
|
||||
setShareURL("");
|
||||
setIsLoadingFile(false);
|
||||
|
||||
return;
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/buckets/${bucketName}/objects/share?prefix=${
|
||||
dataObject.name
|
||||
}&version_id=${versID || "null"}${
|
||||
selectedDate !== "" ? `&expires=${diffDate}ms` : ""
|
||||
}`
|
||||
)
|
||||
.then((res: string) => {
|
||||
setShareURL(res);
|
||||
setIsLoadingFile(false);
|
||||
})
|
||||
.catch((error: ErrorResponseHandler) => {
|
||||
setModalErrorSnackMessage(error);
|
||||
setShareURL("");
|
||||
setIsLoadingFile(false);
|
||||
});
|
||||
}
|
||||
|
||||
if (diffDate > 604800000) {
|
||||
setModalErrorSnackMessage({
|
||||
errorMessage: "You can share a file only for less than 7 days.",
|
||||
detailedError: "",
|
||||
});
|
||||
setShareURL("");
|
||||
setIsLoadingFile(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/buckets/${bucketName}/objects/share?prefix=${
|
||||
dataObject.name
|
||||
}&version_id=${versID}${
|
||||
selectedDate !== "" ? `&expires=${diffDate}ms` : ""
|
||||
}`
|
||||
)
|
||||
.then((res: string) => {
|
||||
setShareURL(res);
|
||||
setIsLoadingFile(false);
|
||||
})
|
||||
.catch((error: ErrorResponseHandler) => {
|
||||
setModalErrorSnackMessage(error);
|
||||
setShareURL("");
|
||||
setIsLoadingFile(false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
dataObject,
|
||||
@@ -155,13 +137,20 @@ const ShareFile = ({
|
||||
}}
|
||||
>
|
||||
<Grid container className={classes.modalContent}>
|
||||
<Grid item xs={12} className={classes.moduleDescription}>
|
||||
This module generates a temporary URL with integrated access
|
||||
credentials for sharing objects for up to 7 days.
|
||||
<br />
|
||||
The temporary URL expires after the configured time limit.
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.dateContainer}>
|
||||
<DateSelector
|
||||
<DaysSelector
|
||||
initialDate={initialDate}
|
||||
id="date"
|
||||
label="Active until"
|
||||
borderBottom={false}
|
||||
addSwitch={true}
|
||||
onDateChange={dateChanged}
|
||||
label="Active for"
|
||||
maxDays={7}
|
||||
onChange={dateChanged}
|
||||
entity="Link"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid container item xs={12}>
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
// 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, useEffect, Fragment } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import moment from "moment/moment";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
|
||||
import InputBoxWrapper from "../InputBoxWrapper/InputBoxWrapper";
|
||||
|
||||
interface IDaysSelector {
|
||||
classes: any;
|
||||
id: string;
|
||||
initialDate: Date;
|
||||
maxDays?: number;
|
||||
label: string;
|
||||
entity: string;
|
||||
onChange: (newDate: string, isValid: boolean) => void;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
dateInput: {
|
||||
"&:not(:last-child)": {
|
||||
marginRight: 22,
|
||||
},
|
||||
},
|
||||
...fieldBasic,
|
||||
...tooltipHelper,
|
||||
labelContainer: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
fieldContainer: {
|
||||
...fieldBasic.fieldContainer,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingBottom: 10,
|
||||
marginTop: 11,
|
||||
marginBottom: 6,
|
||||
},
|
||||
fieldContainerBorder: {
|
||||
borderBottom: "#9c9c9c 1px solid",
|
||||
marginBottom: 20,
|
||||
},
|
||||
dateContainer: {
|
||||
height: 20,
|
||||
textAlign: "right",
|
||||
color: "#848484",
|
||||
},
|
||||
});
|
||||
|
||||
const calculateNewTime = (
|
||||
initialDate: Date,
|
||||
days: number,
|
||||
hours: number,
|
||||
minutes: number
|
||||
) => {
|
||||
return moment(initialDate)
|
||||
.add(days, "days")
|
||||
.add(hours, "hours")
|
||||
.add(minutes, "minutes");
|
||||
};
|
||||
|
||||
const DaysSelector = ({
|
||||
classes,
|
||||
id,
|
||||
initialDate,
|
||||
label,
|
||||
maxDays,
|
||||
entity,
|
||||
onChange,
|
||||
}: IDaysSelector) => {
|
||||
const [selectedDays, setSelectedDays] = useState<number>(7);
|
||||
const [selectedHours, setSelectedHours] = useState<number>(0);
|
||||
const [selectedMinutes, setSelectedMinutes] = useState<number>(0);
|
||||
const [validDate, setValidDate] = useState<boolean>(true);
|
||||
const [dateSelected, setDateSelected] = useState<moment.Moment>(moment());
|
||||
|
||||
useEffect(() => {
|
||||
setDateSelected(
|
||||
calculateNewTime(
|
||||
initialDate,
|
||||
selectedDays,
|
||||
selectedHours,
|
||||
selectedMinutes
|
||||
)
|
||||
);
|
||||
}, [initialDate, selectedDays, selectedHours, selectedMinutes]);
|
||||
|
||||
useEffect(() => {
|
||||
if (validDate) {
|
||||
onChange(dateSelected.format("YYYY-MM-DDTHH:mm:ss"), true);
|
||||
} else {
|
||||
onChange("0000-00-00", false);
|
||||
}
|
||||
}, [dateSelected, onChange, validDate]);
|
||||
|
||||
// Basic validation for inputs
|
||||
useEffect(() => {
|
||||
let valid = true;
|
||||
if (
|
||||
selectedDays < 0 ||
|
||||
(maxDays && selectedDays > maxDays) ||
|
||||
isNaN(selectedDays)
|
||||
) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (selectedHours < 0 || selectedHours > 23 || isNaN(selectedHours)) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (selectedMinutes < 0 || selectedMinutes > 59 || isNaN(selectedMinutes)) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (
|
||||
maxDays &&
|
||||
selectedDays === maxDays &&
|
||||
(selectedHours !== 0 || selectedMinutes !== 0)
|
||||
) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
setValidDate(valid);
|
||||
}, [
|
||||
dateSelected,
|
||||
maxDays,
|
||||
onChange,
|
||||
selectedDays,
|
||||
selectedHours,
|
||||
selectedMinutes,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.fieldContainer}>
|
||||
<Grid container alignItems={"center"} justifyContent={"center"}>
|
||||
<Grid item xs={12} className={classes.labelContainer}>
|
||||
<InputLabel htmlFor={id} className={classes.inputLabel}>
|
||||
<span>{label}</span>
|
||||
</InputLabel>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<InputBoxWrapper
|
||||
id={id}
|
||||
type="number"
|
||||
min="0"
|
||||
max={maxDays ? maxDays.toString() : "999"}
|
||||
label="Days"
|
||||
name={id}
|
||||
onChange={(e) => {
|
||||
setSelectedDays(parseInt(e.target.value));
|
||||
}}
|
||||
value={selectedDays.toString()}
|
||||
extraInputProps={{
|
||||
style: {
|
||||
textAlign: "center",
|
||||
paddingRight: 5,
|
||||
},
|
||||
className: "removeArrows",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<InputBoxWrapper
|
||||
id={id}
|
||||
type="number"
|
||||
min="0"
|
||||
max="23"
|
||||
label="Hours"
|
||||
name={id}
|
||||
onChange={(e) => {
|
||||
setSelectedHours(parseInt(e.target.value));
|
||||
}}
|
||||
value={selectedHours.toString()}
|
||||
extraInputProps={{
|
||||
style: {
|
||||
textAlign: "center",
|
||||
paddingRight: 5,
|
||||
},
|
||||
className: "removeArrows",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<InputBoxWrapper
|
||||
id={id}
|
||||
type="number"
|
||||
min="0"
|
||||
max="59"
|
||||
label="Minutes"
|
||||
name={id}
|
||||
onChange={(e) => {
|
||||
setSelectedMinutes(parseInt(e.target.value));
|
||||
}}
|
||||
value={selectedMinutes.toString()}
|
||||
extraInputProps={{
|
||||
style: {
|
||||
textAlign: "center",
|
||||
paddingRight: 5,
|
||||
},
|
||||
className: "removeArrows",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.dateContainer}>
|
||||
{validDate && (
|
||||
<Fragment>
|
||||
<strong>{entity} will be available until:</strong>{" "}
|
||||
{dateSelected.format("MM/DD/YYYY HH:mm:ss")}
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<br />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(DaysSelector);
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
Tooltip,
|
||||
} from "@material-ui/core";
|
||||
import { OutlinedInputProps } from "@material-ui/core/OutlinedInput";
|
||||
import { InputProps as StandardInputProps } from "@material-ui/core/Input";
|
||||
import {
|
||||
createStyles,
|
||||
makeStyles,
|
||||
@@ -56,6 +57,7 @@ interface InputBoxProps {
|
||||
max?: string;
|
||||
overlayIcon?: any;
|
||||
overlayAction?: () => void;
|
||||
extraInputProps?: StandardInputProps['inputProps'];
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -125,10 +127,11 @@ const InputBoxWrapper = ({
|
||||
min,
|
||||
max,
|
||||
overlayIcon = null,
|
||||
extraInputProps = {},
|
||||
overlayAction,
|
||||
classes,
|
||||
}: InputBoxProps) => {
|
||||
let inputProps: any = { "data-index": index };
|
||||
let inputProps: any = { "data-index": index, ...extraInputProps };
|
||||
|
||||
if (type === "number" && min) {
|
||||
inputProps["min"] = min;
|
||||
|
||||
@@ -84,6 +84,11 @@ export const modalBasic = {
|
||||
height: 170,
|
||||
maxWidth: 840,
|
||||
},
|
||||
moduleDescription: {
|
||||
color: "#848484",
|
||||
fontSize: 12,
|
||||
fontStyle: "italic" as string,
|
||||
},
|
||||
};
|
||||
|
||||
export const tooltipHelper = {
|
||||
|
||||
Reference in New Issue
Block a user