diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index 5f65ede..4eb42c5 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -42,7 +42,10 @@ "Edit": "Edit", "More": "More", "OpenInNewTab": "Open in new tab", - "Delete": "Delete" + "Delete": "Delete", + "Deleting": "Deleting", + "Save": "Save", + "Saving": "Saving" }, "Menu": { "Dashboard": "Dashboard", @@ -75,6 +78,10 @@ "Name": "Name", "Category": "Category", "Secured": "Secured", + "PathOnDisk": "Path on disk", + "MimeType": "MIME type", + "AutomaticMimeType": "Automatic MIME type", + "Description": "Description", "List": { "Title": "Resource management", "SubTitle": "Resources", @@ -87,6 +94,10 @@ "CopyUrl": "Copy resource URL", "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": { diff --git a/public/locales/ro/translations.json b/public/locales/ro/translations.json index 8b22adb..66451ac 100644 --- a/public/locales/ro/translations.json +++ b/public/locales/ro/translations.json @@ -33,7 +33,10 @@ "Edit": "Editează", "More": "Mai mult", "OpenInNewTab": "Deschide într-un tab nou", - "Delete": "Șterge" + "Delete": "Șterge", + "Deleting": "Se şterge", + "Save": "Salvează", + "Saving": "Se salvează" }, "Menu": { "Dashboard": "Dashboard", @@ -66,6 +69,10 @@ "Name": "Nume", "Category": "Categorie", "Secured": "Securizat", + "PathOnDisk": "Cale pe disc", + "MimeType": "Tip MIME", + "AutomaticMimeType": "Tip MIME automat", + "Description": "Descriere", "List": { "Title": "Managementul resurselor", "SubTitle": "Resurse", @@ -78,6 +85,10 @@ "CopyUrl": "Copiați adresa URL a resursei", "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": { diff --git a/src/features/resources/edit/components/LinksComponent.js b/src/features/resources/edit/components/LinksComponent.js new file mode 100644 index 0000000..fc8d81b --- /dev/null +++ b/src/features/resources/edit/components/LinksComponent.js @@ -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 ( + + + + + {urls.map((value, index) => { + return ( + + + + + + {value} + + } + /> + + + + + + + + + ); + })} + + + + ); +}; + +LinksComponent.propTypes = { + urls: PropTypes.array.isRequired, + secured: PropTypes.bool.isRequired +}; + +export default LinksComponent; diff --git a/src/features/resources/edit/components/MimeTypeComponent.js b/src/features/resources/edit/components/MimeTypeComponent.js index 157778a..9e74e78 100644 --- a/src/features/resources/edit/components/MimeTypeComponent.js +++ b/src/features/resources/edit/components/MimeTypeComponent.js @@ -2,12 +2,15 @@ import React, { useState } from "react"; import PropTypes from "prop-types"; import { Grid, TextField, FormControlLabel, Checkbox } from "@material-ui/core"; import Autocomplete from "@material-ui/lab/Autocomplete"; +import { useTranslation } from "react-i18next"; const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => { const [isAutomaticMimeType, setIsAutomaticMimeType] = useState( mimeType.mimeTypeId === null ); + const { t } = useTranslation(); + const handleChangeAutomaticMimeType = (event) => { const checked = event.target.checked; setIsAutomaticMimeType(checked); @@ -20,7 +23,7 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => { {isAutomaticMimeType ? ( { }} getOptionSelected={(option, value) => option.mimeTypeId === value} renderInput={(params) => ( - + )} /> )} @@ -58,7 +61,7 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => { color="primary" /> } - label="Auto MIME type" + label={t("Resource.AutomaticMimeType")} /> diff --git a/src/features/resources/edit/components/ResourceComponent.js b/src/features/resources/edit/components/ResourceComponent.js index 01c483c..8c7d219 100644 --- a/src/features/resources/edit/components/ResourceComponent.js +++ b/src/features/resources/edit/components/ResourceComponent.js @@ -18,6 +18,8 @@ import MimeTypeComponent from "./MimeTypeComponent"; import useResourceDeleteDialog from "../../hooks/useResourceDeleteDialog"; import { onTextFieldChange } from "../../../../utils/adapters"; import { useHistory } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import LinksComponent from "./LinksComponent"; const useStyles = makeStyles(style); @@ -31,6 +33,7 @@ const ResourceComponent = ({ }) => { const classes = useStyles(); const history = useHistory(); + const { t } = useTranslation(); const { component: ResourceDeleteDialog, handleOpen: handleOpenDeleteDialog @@ -40,7 +43,7 @@ const ResourceComponent = ({ return ( <> - + @@ -52,7 +55,7 @@ const ResourceComponent = ({ ( - + )} /> @@ -124,7 +127,7 @@ const ResourceComponent = ({ color="primary" /> } - label="Secured" + label={t("Resource.Secured")} /> @@ -135,7 +138,7 @@ const ResourceComponent = ({ multiline rows={12} id="resource-description" - label="Description" + label={t("Resource.Description")} variant="outlined" /> @@ -149,7 +152,9 @@ const ResourceComponent = ({ onClick={handleOpenDeleteDialog} disabled={!!processing} > - {processing === "delete" ? "Deleting" : "Delete"} + {processing === "delete" + ? t("Generic.Deleting") + : t("Generic.Delete")} {ResourceDeleteDialog} + ); }; diff --git a/src/features/resources/edit/styles.js b/src/features/resources/edit/styles.js index 4a7d6e2..d5ba96d 100644 --- a/src/features/resources/edit/styles.js +++ b/src/features/resources/edit/styles.js @@ -3,10 +3,16 @@ const style = (theme) => { root: { flexGrow: 1 }, - paper: { + resourceData: { padding: theme.spacing(2), margin: "auto" }, + linksCard: { + marginTop: theme.spacing(2) + }, + linksHeader: { + paddingBottom: 0 + }, resourceImage: { margin: "auto", display: "block", diff --git a/src/features/resources/list/components/ResourcesContainer.js b/src/features/resources/list/components/ResourcesContainer.js index ac7085d..7bff2b9 100644 --- a/src/features/resources/list/components/ResourcesContainer.js +++ b/src/features/resources/list/components/ResourcesContainer.js @@ -93,7 +93,7 @@ const ResourcesContainer = () => { } if (secure) { - url = secureUrl(url, download); + url = secureUrl(url); } return url; diff --git a/src/hooks/useResourceSecurity.js b/src/hooks/useResourceSecurity.js index 548e7ed..369dc03 100644 --- a/src/hooks/useResourceSecurity.js +++ b/src/hooks/useResourceSecurity.js @@ -4,8 +4,8 @@ import { useCallback } from "react"; const useResourceSecurity = () => { const { token } = useUserState(); const secureUrl = useCallback( - (url, join) => { - const separator = join ? "&" : "?"; + (url) => { + const separator = url.includes("?") ? "&" : "?"; const securedUrl = `${url}${separator}token=${token.raw}`; return securedUrl; },