resource links component
parent
25a2ff95e4
commit
1e45226205
|
@ -42,7 +42,10 @@
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"More": "More",
|
"More": "More",
|
||||||
"OpenInNewTab": "Open in new tab",
|
"OpenInNewTab": "Open in new tab",
|
||||||
"Delete": "Delete"
|
"Delete": "Delete",
|
||||||
|
"Deleting": "Deleting",
|
||||||
|
"Save": "Save",
|
||||||
|
"Saving": "Saving"
|
||||||
},
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
|
@ -75,6 +78,10 @@
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Category": "Category",
|
"Category": "Category",
|
||||||
"Secured": "Secured",
|
"Secured": "Secured",
|
||||||
|
"PathOnDisk": "Path on disk",
|
||||||
|
"MimeType": "MIME type",
|
||||||
|
"AutomaticMimeType": "Automatic MIME type",
|
||||||
|
"Description": "Description",
|
||||||
"List": {
|
"List": {
|
||||||
"Title": "Resource management",
|
"Title": "Resource management",
|
||||||
"SubTitle": "Resources",
|
"SubTitle": "Resources",
|
||||||
|
@ -87,6 +94,10 @@
|
||||||
"CopyUrl": "Copy resource URL",
|
"CopyUrl": "Copy resource URL",
|
||||||
"LinkCopiedToClipboard": "The link has been copied to the clipboard."
|
"LinkCopiedToClipboard": "The link has been copied to the clipboard."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Links": {
|
||||||
|
"Title": "Links",
|
||||||
|
"SubTitle": "Different forms of the URL at which a resource can be accessed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ServerAvailability": {
|
"ServerAvailability": {
|
||||||
|
|
|
@ -33,7 +33,10 @@
|
||||||
"Edit": "Editează",
|
"Edit": "Editează",
|
||||||
"More": "Mai mult",
|
"More": "Mai mult",
|
||||||
"OpenInNewTab": "Deschide într-un tab nou",
|
"OpenInNewTab": "Deschide într-un tab nou",
|
||||||
"Delete": "Șterge"
|
"Delete": "Șterge",
|
||||||
|
"Deleting": "Se şterge",
|
||||||
|
"Save": "Salvează",
|
||||||
|
"Saving": "Se salvează"
|
||||||
},
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
|
@ -66,6 +69,10 @@
|
||||||
"Name": "Nume",
|
"Name": "Nume",
|
||||||
"Category": "Categorie",
|
"Category": "Categorie",
|
||||||
"Secured": "Securizat",
|
"Secured": "Securizat",
|
||||||
|
"PathOnDisk": "Cale pe disc",
|
||||||
|
"MimeType": "Tip MIME",
|
||||||
|
"AutomaticMimeType": "Tip MIME automat",
|
||||||
|
"Description": "Descriere",
|
||||||
"List": {
|
"List": {
|
||||||
"Title": "Managementul resurselor",
|
"Title": "Managementul resurselor",
|
||||||
"SubTitle": "Resurse",
|
"SubTitle": "Resurse",
|
||||||
|
@ -78,6 +85,10 @@
|
||||||
"CopyUrl": "Copiați adresa URL a resursei",
|
"CopyUrl": "Copiați adresa URL a resursei",
|
||||||
"LinkCopiedToClipboard": "Linkul a fost copiat în clipboard."
|
"LinkCopiedToClipboard": "Linkul a fost copiat în clipboard."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Links": {
|
||||||
|
"Title": "Legături",
|
||||||
|
"SubTitle": "Diferite forme ale URL-ului la care poate fi accesată o resursă"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ServerAvailability": {
|
"ServerAvailability": {
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardContent,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemText,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemIcon,
|
||||||
|
IconButton,
|
||||||
|
Link,
|
||||||
|
Tooltip
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import style from "../styles";
|
||||||
|
import { LinkOutlined, FileCopyOutlined } from "@material-ui/icons";
|
||||||
|
import { useToast, useResourceSecurity } from "../../../../hooks";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(style);
|
||||||
|
|
||||||
|
const LinksComponent = ({ urls, secured }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { info } = useToast();
|
||||||
|
const { secureUrl } = useResourceSecurity();
|
||||||
|
|
||||||
|
const handleToggle = (url) => () => {
|
||||||
|
const urlMustBeSecured = secured || url.includes("id=");
|
||||||
|
const link = urlMustBeSecured ? secureUrl(url) : url;
|
||||||
|
navigator.clipboard.writeText(link);
|
||||||
|
info(t("Resource.List.Actions.LinkCopiedToClipboard"));
|
||||||
|
};
|
||||||
|
const preventDefault = (event) => event.preventDefault();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={classes.linksCard}>
|
||||||
|
<CardHeader
|
||||||
|
className={classes.linksHeader}
|
||||||
|
title={t("Resource.Links.Title")}
|
||||||
|
subheader={t("Resource.Links.SubTitle")}
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<List>
|
||||||
|
{urls.map((value, index) => {
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
key={`url-${index}`}
|
||||||
|
dense
|
||||||
|
button
|
||||||
|
onClick={handleToggle(value)}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<LinkOutlined />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
<Link href={value} onClick={preventDefault}>
|
||||||
|
{value}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<Tooltip title={"Copy"}>
|
||||||
|
<IconButton
|
||||||
|
edge="end"
|
||||||
|
aria-label="comments"
|
||||||
|
size="small"
|
||||||
|
onClick={handleToggle(value)}
|
||||||
|
>
|
||||||
|
<FileCopyOutlined />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LinksComponent.propTypes = {
|
||||||
|
urls: PropTypes.array.isRequired,
|
||||||
|
secured: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LinksComponent;
|
|
@ -2,12 +2,15 @@ import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Grid, TextField, FormControlLabel, Checkbox } from "@material-ui/core";
|
import { Grid, TextField, FormControlLabel, Checkbox } from "@material-ui/core";
|
||||||
import Autocomplete from "@material-ui/lab/Autocomplete";
|
import Autocomplete from "@material-ui/lab/Autocomplete";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
|
const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
|
||||||
const [isAutomaticMimeType, setIsAutomaticMimeType] = useState(
|
const [isAutomaticMimeType, setIsAutomaticMimeType] = useState(
|
||||||
mimeType.mimeTypeId === null
|
mimeType.mimeTypeId === null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleChangeAutomaticMimeType = (event) => {
|
const handleChangeAutomaticMimeType = (event) => {
|
||||||
const checked = event.target.checked;
|
const checked = event.target.checked;
|
||||||
setIsAutomaticMimeType(checked);
|
setIsAutomaticMimeType(checked);
|
||||||
|
@ -20,7 +23,7 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
|
||||||
{isAutomaticMimeType ? (
|
{isAutomaticMimeType ? (
|
||||||
<TextField
|
<TextField
|
||||||
id="automatic-resource-mime-type"
|
id="automatic-resource-mime-type"
|
||||||
label="Automatic MIME type"
|
label={t("Resource.AutomaticMimeType")}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled
|
disabled
|
||||||
value={mimeType.mimeTypeName}
|
value={mimeType.mimeTypeName}
|
||||||
|
@ -43,7 +46,7 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
|
||||||
}}
|
}}
|
||||||
getOptionSelected={(option, value) => option.mimeTypeId === value}
|
getOptionSelected={(option, value) => option.mimeTypeId === value}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField {...params} label="Mime type" />
|
<TextField {...params} label={t("Resource.MimeType")} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -58,7 +61,7 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label="Auto MIME type"
|
label={t("Resource.AutomaticMimeType")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -18,6 +18,8 @@ import MimeTypeComponent from "./MimeTypeComponent";
|
||||||
import useResourceDeleteDialog from "../../hooks/useResourceDeleteDialog";
|
import useResourceDeleteDialog from "../../hooks/useResourceDeleteDialog";
|
||||||
import { onTextFieldChange } from "../../../../utils/adapters";
|
import { onTextFieldChange } from "../../../../utils/adapters";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import LinksComponent from "./LinksComponent";
|
||||||
|
|
||||||
const useStyles = makeStyles(style);
|
const useStyles = makeStyles(style);
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ const ResourceComponent = ({
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
component: ResourceDeleteDialog,
|
component: ResourceDeleteDialog,
|
||||||
handleOpen: handleOpenDeleteDialog
|
handleOpen: handleOpenDeleteDialog
|
||||||
|
@ -40,7 +43,7 @@ const ResourceComponent = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Paper className={classes.paper}>
|
<Paper className={classes.resourceData}>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} sm={5}>
|
<Grid item xs={12} sm={5}>
|
||||||
<ButtonBase>
|
<ButtonBase>
|
||||||
|
@ -52,7 +55,7 @@ const ResourceComponent = ({
|
||||||
<Grid item xs={12} sm={6}>
|
<Grid item xs={12} sm={6}>
|
||||||
<TextField
|
<TextField
|
||||||
id="resource-code"
|
id="resource-code"
|
||||||
label="Code"
|
label={t("Resource.Code")}
|
||||||
fullWidth
|
fullWidth
|
||||||
required
|
required
|
||||||
value={resource.resourceCode}
|
value={resource.resourceCode}
|
||||||
|
@ -62,7 +65,7 @@ const ResourceComponent = ({
|
||||||
<Grid item xs={12} sm={6}>
|
<Grid item xs={12} sm={6}>
|
||||||
<TextField
|
<TextField
|
||||||
id="resource-name"
|
id="resource-name"
|
||||||
label="Name"
|
label={t("Resource.Name")}
|
||||||
fullWidth
|
fullWidth
|
||||||
required
|
required
|
||||||
value={resource.resourceName}
|
value={resource.resourceName}
|
||||||
|
@ -72,7 +75,7 @@ const ResourceComponent = ({
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<TextField
|
<TextField
|
||||||
id="resource-path"
|
id="resource-path"
|
||||||
label="Path on disk"
|
label={t("Resource.PathOnDisk")}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled
|
disabled
|
||||||
value={resource.resourcePath}
|
value={resource.resourcePath}
|
||||||
|
@ -108,7 +111,7 @@ const ResourceComponent = ({
|
||||||
option.categoryId === value
|
option.categoryId === value
|
||||||
}
|
}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField {...params} label="Category" />
|
<TextField {...params} label={t("Resource.Category")} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -124,7 +127,7 @@ const ResourceComponent = ({
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label="Secured"
|
label={t("Resource.Secured")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -135,7 +138,7 @@ const ResourceComponent = ({
|
||||||
multiline
|
multiline
|
||||||
rows={12}
|
rows={12}
|
||||||
id="resource-description"
|
id="resource-description"
|
||||||
label="Description"
|
label={t("Resource.Description")}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -149,7 +152,9 @@ const ResourceComponent = ({
|
||||||
onClick={handleOpenDeleteDialog}
|
onClick={handleOpenDeleteDialog}
|
||||||
disabled={!!processing}
|
disabled={!!processing}
|
||||||
>
|
>
|
||||||
{processing === "delete" ? "Deleting" : "Delete"}
|
{processing === "delete"
|
||||||
|
? t("Generic.Deleting")
|
||||||
|
: t("Generic.Delete")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -158,13 +163,16 @@ const ResourceComponent = ({
|
||||||
startIcon={<SaveIcon />}
|
startIcon={<SaveIcon />}
|
||||||
disabled={!!processing}
|
disabled={!!processing}
|
||||||
>
|
>
|
||||||
{processing === "delete" ? "Saving" : "Save"}
|
{processing === "delete"
|
||||||
|
? t("Generic.Saving")
|
||||||
|
: t("Generic.Save")}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
{ResourceDeleteDialog}
|
{ResourceDeleteDialog}
|
||||||
|
<LinksComponent urls={resource.urls} secured={resource.secured} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,10 +3,16 @@ const style = (theme) => {
|
||||||
root: {
|
root: {
|
||||||
flexGrow: 1
|
flexGrow: 1
|
||||||
},
|
},
|
||||||
paper: {
|
resourceData: {
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
margin: "auto"
|
margin: "auto"
|
||||||
},
|
},
|
||||||
|
linksCard: {
|
||||||
|
marginTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
linksHeader: {
|
||||||
|
paddingBottom: 0
|
||||||
|
},
|
||||||
resourceImage: {
|
resourceImage: {
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
display: "block",
|
display: "block",
|
||||||
|
|
|
@ -93,7 +93,7 @@ const ResourcesContainer = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secure) {
|
if (secure) {
|
||||||
url = secureUrl(url, download);
|
url = secureUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { useCallback } from "react";
|
||||||
const useResourceSecurity = () => {
|
const useResourceSecurity = () => {
|
||||||
const { token } = useUserState();
|
const { token } = useUserState();
|
||||||
const secureUrl = useCallback(
|
const secureUrl = useCallback(
|
||||||
(url, join) => {
|
(url) => {
|
||||||
const separator = join ? "&" : "?";
|
const separator = url.includes("?") ? "&" : "?";
|
||||||
const securedUrl = `${url}${separator}token=${token.raw}`;
|
const securedUrl = `${url}${separator}token=${token.raw}`;
|
||||||
return securedUrl;
|
return securedUrl;
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue