mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-15 11:37:57 +01:00
WIP: Share dialog with mock support
This commit is contained in:
parent
1ad664cdfb
commit
cf3b2c90f7
@ -22,6 +22,8 @@ export type Label = {
|
||||
iconName: string;
|
||||
}
|
||||
|
||||
export type Role = 'owner' | 'editor' | 'viewer';
|
||||
|
||||
export type MapInfo = {
|
||||
id: number;
|
||||
starred: boolean;
|
||||
@ -33,7 +35,7 @@ export type MapInfo = {
|
||||
lastModificationTime: string;
|
||||
description: string;
|
||||
isPublic: boolean;
|
||||
role: 'owner' | 'editor' | 'viewer'
|
||||
role: Role;
|
||||
}
|
||||
|
||||
export type ChangeHistory = {
|
||||
@ -64,6 +66,12 @@ export type AccountInfo = {
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
export type Permission = {
|
||||
name?: string;
|
||||
email: string;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
interface Client {
|
||||
deleteAccount(): Promise<void>
|
||||
importMap(model: ImportMapInfo): Promise<number>
|
||||
@ -72,6 +80,9 @@ interface Client {
|
||||
deleteMap(id: number): Promise<void>;
|
||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
||||
fetchAllMaps(): Promise<MapInfo[]>;
|
||||
fetchMapPermissions(id: number): Promise<Permission[]>;
|
||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void>;
|
||||
|
||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>;
|
||||
|
||||
updateAccountLanguage(locale: LocaleCode): Promise<void>;
|
||||
|
@ -1,8 +1,10 @@
|
||||
import Client, { AccountInfo, BasicMapInfo, ChangeHistory, ImportMapInfo, Label, MapInfo, NewUser } from '..';
|
||||
import Client, { AccountInfo, BasicMapInfo, ChangeHistory, ImportMapInfo, Label, MapInfo, NewUser, Permission } from '..';
|
||||
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||
|
||||
class MockClient implements Client {
|
||||
private maps: MapInfo[] = [];
|
||||
private labels: Label[] = [];
|
||||
private permissionsByMap: Map<number, Permission[]> = new Map();
|
||||
|
||||
constructor() {
|
||||
|
||||
@ -22,6 +24,7 @@ class MockClient implements Client {
|
||||
): MapInfo {
|
||||
return { id, title, labels, createdBy: creator, creationTime, lastModificationBy: modifiedByUser, lastModificationTime: modifiedTime, starred, description, isPublic, role };
|
||||
}
|
||||
|
||||
this.maps = [
|
||||
createMapInfo(1, true, "El Mapa", [], "Paulo", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", true, 'owner'),
|
||||
createMapInfo(11, false, "El Mapa3", [1, 2, 3], "Paulo3", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", false, 'editor'),
|
||||
@ -32,7 +35,28 @@ class MockClient implements Client {
|
||||
{ id: 1, title: "Red Label", iconName: "", color: 'red' },
|
||||
{ id: 2, title: "Blue Label", iconName: "", color: 'blue' }
|
||||
];
|
||||
}
|
||||
|
||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
||||
let perm = this.permissionsByMap.get(id) || [];
|
||||
perm = perm.concat(permissions);
|
||||
this.permissionsByMap.set(id, perm);
|
||||
|
||||
console.log(`Message ${message}`)
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
fetchMapPermissions(id: number): Promise<Permission[]> {
|
||||
let perm = this.permissionsByMap.get(id);
|
||||
if (!perm) {
|
||||
perm = [{
|
||||
name: 'Cosme Sharing',
|
||||
email: 'pepe@gmail.com',
|
||||
role: 'editor'
|
||||
}];
|
||||
this.permissionsByMap.set(id, perm);
|
||||
}
|
||||
return Promise.resolve(perm);
|
||||
}
|
||||
|
||||
deleteAccount(): Promise<void> {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo, ImportMapInfo } from '..';
|
||||
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo, ImportMapInfo, Permission } from '..';
|
||||
import { LocaleCode, localeFromStr, Locales } from '../../app-i18n';
|
||||
|
||||
export default class RestClient implements Client {
|
||||
@ -10,6 +10,15 @@ export default class RestClient implements Client {
|
||||
this.baseUrl = baseUrl;
|
||||
this.sessionExpired = sessionExpired;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
fetchMapPermissions(id: number): Promise<Permission[]> {
|
||||
throw new Error('Method not implemented.' + id);
|
||||
}
|
||||
|
||||
deleteAccount(): Promise<void> {
|
||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||
axios.delete(this.baseUrl + `/c/restful/account`,
|
||||
|
@ -24,7 +24,7 @@ const ConfigStatusMessage = ({ enabled = false }: ConfigStatusProps): React.Reac
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
return result ? result : null;
|
||||
return result || null;
|
||||
}
|
||||
|
||||
const LoginError = () => {
|
||||
|
@ -32,7 +32,7 @@ const AccountMenu = (): React.ReactElement => {
|
||||
const account = fetchAccount();
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title={`${account?.firstname} ${account?.lastname} <${account?.email}>`}>
|
||||
<Tooltip arrow={true} title={`${account?.firstname} ${account?.lastname} <${account?.email}>`}>
|
||||
<IconButton
|
||||
onClick={handleMenu}>
|
||||
<AccountCircle fontSize="large" style={{ color: 'black' }} />
|
||||
|
@ -5,6 +5,7 @@ import { StyledDialog, StyledDialogActions, StyledDialogContent, StyledDialogTit
|
||||
import GlobalError from "../../../form/global-error";
|
||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { PaperProps } from "@material-ui/core/Paper";
|
||||
|
||||
export type DialogProps = {
|
||||
onClose: () => void;
|
||||
@ -18,10 +19,11 @@ export type DialogProps = {
|
||||
submitButton?: string;
|
||||
actionUrl?: string;
|
||||
maxWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false;
|
||||
PaperProps?: Partial<PaperProps>;
|
||||
}
|
||||
|
||||
const BaseDialog = (props: DialogProps): React.ReactElement => {
|
||||
const { onClose, onSubmit, maxWidth = 'sm' } = props;
|
||||
const { onClose, onSubmit, maxWidth = 'sm', PaperProps } = props;
|
||||
|
||||
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@ -31,13 +33,13 @@ const BaseDialog = (props: DialogProps): React.ReactElement => {
|
||||
}
|
||||
|
||||
const description = props.description ? (<DialogContentText>{props.description}</DialogContentText>) : null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StyledDialog
|
||||
open={true}
|
||||
onClose={onClose}
|
||||
maxWidth={maxWidth}
|
||||
PaperProps={PaperProps}
|
||||
fullWidth={true}>
|
||||
<form autoComplete="off" onSubmit={handleOnSubmit}>
|
||||
<StyledDialogTitle>
|
||||
|
@ -2,7 +2,7 @@ import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import { useSelector } from "react-redux";
|
||||
import Client from "../../../../classes/client";
|
||||
import Client, { ErrorInfo } from "../../../../classes/client";
|
||||
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice';
|
||||
import { SimpleDialogProps, handleOnMutationSuccess } from "..";
|
||||
import BaseDialog from "../base-dialog";
|
||||
@ -14,10 +14,14 @@ const DeleteDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
||||
const intl = useIntl();
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const queryClient = useQueryClient();
|
||||
const [error, setError] = React.useState<ErrorInfo>();
|
||||
|
||||
const mutation = useMutation((id: number) => client.deleteMap(id),
|
||||
{
|
||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient)
|
||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
||||
onError: (error: ErrorInfo) => {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@ -35,6 +39,7 @@ const DeleteDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
||||
return (
|
||||
<div>
|
||||
<BaseDialog
|
||||
error={error}
|
||||
onClose={handleOnClose} onSubmit={handleOnSubmit}
|
||||
title={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })}
|
||||
submitButton={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })}>
|
||||
|
@ -21,7 +21,10 @@ const DeleteMultiselectDialog = ({ onClose, mapsId }: DeleteMultiselectDialogPro
|
||||
|
||||
const mutation = useMutation((ids: number[]) => client.deleteMaps(ids),
|
||||
{
|
||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient)
|
||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
||||
onError: (error) => {
|
||||
console.error(`Unexpected error ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1,15 +1,16 @@
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { useSelector } from "react-redux";
|
||||
import Client from "../../../../classes/client";
|
||||
import Client, { ErrorInfo, Permission } from "../../../../classes/client";
|
||||
import { activeInstance } from '../../../../redux/clientSlice';
|
||||
import { SimpleDialogProps, handleOnMutationSuccess } from "..";
|
||||
import { SimpleDialogProps } from "..";
|
||||
import BaseDialog from "../base-dialog";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
||||
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
@ -19,16 +20,41 @@ import Button from "@material-ui/core/Button";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||
import Checkbox from "@material-ui/core/Checkbox";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { useStyles } from "./style";
|
||||
import RoleIcon from "../../role-icon";
|
||||
|
||||
|
||||
type ShareModel = {
|
||||
emails: string,
|
||||
role: 'editor' | 'viewer',
|
||||
message: string
|
||||
}
|
||||
|
||||
const defaultModel: ShareModel = { emails: '', role: 'editor', message: '' };
|
||||
const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||
const intl = useIntl();
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const queryClient = useQueryClient();
|
||||
const classes = useStyles();
|
||||
const [showMessage, setShowMessage] = React.useState<boolean>(false);
|
||||
const [model, setModel] = React.useState<ShareModel>(defaultModel);
|
||||
const [error, setError] = React.useState<ErrorInfo>();
|
||||
|
||||
const mutation = useMutation((id: number) => client.deleteMap(id),
|
||||
const mutation = useMutation(
|
||||
(model: ShareModel) => {
|
||||
const emails = model.emails.split("'");
|
||||
const permissions = emails.map((email) => { return { email: email, role: model.role } });
|
||||
return client.addMapPermissions(mapId, model.message, permissions);
|
||||
},
|
||||
{
|
||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient)
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(`perm-${mapId}`);
|
||||
setModel(defaultModel);
|
||||
},
|
||||
onError: (error: ErrorInfo) => {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@ -36,50 +62,102 @@ const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleOnSubmit = (): void => {
|
||||
mutation.mutate(mapId);
|
||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
event.preventDefault();
|
||||
|
||||
const name = event.target.name;
|
||||
const value = event.target.value;
|
||||
setModel({ ...model, [name as keyof ShareModel]: value });
|
||||
}
|
||||
|
||||
// Fetch map model to be rendered ...
|
||||
const handleOnClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
||||
event.stopPropagation();
|
||||
mutation.mutate(model);
|
||||
};
|
||||
|
||||
const { isLoading, data: permissions = [] } = useQuery<unknown, ErrorInfo, Permission[]>(`perm-${mapId}`, () => {
|
||||
return client.fetchMapPermissions(mapId);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BaseDialog
|
||||
onClose={handleOnClose} onSubmit={handleOnSubmit}
|
||||
onClose={handleOnClose}
|
||||
title={intl.formatMessage({ id: "share.delete-title", defaultMessage: "Share with people" })}
|
||||
description={intl.formatMessage({ id: "share.delete-description", defaultMessage: "Collaboration " })}
|
||||
submitButton={intl.formatMessage({ id: "share.delete-title", defaultMessage: "Share" })}
|
||||
maxWidth="md">
|
||||
description={intl.formatMessage({ id: "share.delete-description", defaultMessage: "Invite people to collaborate with you on the creation of your midnmap. They will be notified by email. " })}
|
||||
PaperProps={{ classes: { root: classes.paper } }}
|
||||
error={error}
|
||||
>
|
||||
|
||||
<div style={{ padding: '10px 10px', background: '#f9f9f9' }}>
|
||||
<TextField id="email" style={{ width: '300px' }} size="small" type="text" variant="outlined" placeholder="Add collaboratos's emails seperated by commas" label="Email" />
|
||||
<Select
|
||||
value='edit'
|
||||
<div className={classes.actionContainer}>
|
||||
<TextField
|
||||
id="emails"
|
||||
name="emails"
|
||||
required={true}
|
||||
style={{ width: '300px' }}
|
||||
size="small"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
placeholder="Add collaboration email"
|
||||
label="Emails"
|
||||
onChange={handleOnChange}
|
||||
value={model.emails}
|
||||
/>
|
||||
|
||||
<Select
|
||||
variant="outlined"
|
||||
onChange={handleOnChange}
|
||||
value={model.role}
|
||||
name="role"
|
||||
style={{ margin: '0px 10px' }}
|
||||
>
|
||||
<MenuItem value='edit'>Can Edit</MenuItem>
|
||||
<MenuItem value='view'>Can View</MenuItem>
|
||||
<MenuItem value='editor'><FormattedMessage id="share.can-edit" defaultMessage="Can edit" /></MenuItem>
|
||||
<MenuItem value='viewer'><FormattedMessage id="share.can-view" defaultMessage="Can view" /></MenuItem>
|
||||
</Select>
|
||||
|
||||
<FormControlLabel
|
||||
value="start"
|
||||
onChange={(event, value) => { setShowMessage(value) }}
|
||||
style={{ fontSize: "5px" }}
|
||||
control={<Checkbox color="primary" />}
|
||||
label={<FormattedMessage id="share.add-message" defaultMessage="Add message" />}
|
||||
label={<Typography variant="subtitle2"><FormattedMessage id="share.add-message" defaultMessage="Add message" /></Typography>}
|
||||
labelPlacement="end"
|
||||
/>
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
variant="contained" disableElevation={true}><FormattedMessage id="share.add-button" defaultMessage="Add " /></Button>
|
||||
type="button"
|
||||
variant="contained"
|
||||
disableElevation={true}
|
||||
onClick={handleOnClick}>
|
||||
<FormattedMessage id="share.add-button" defaultMessage="Add " />
|
||||
</Button>
|
||||
|
||||
{showMessage &&
|
||||
<TextField
|
||||
multiline
|
||||
rows={3}
|
||||
rowsMax={3}
|
||||
className={classes.textArea}
|
||||
variant="filled"
|
||||
name="message"
|
||||
onChange={handleOnChange}
|
||||
value={model.message}
|
||||
placeholder="Include a customize message to ..."
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<Paper elevation={1} style={{ maxHeight: 200, overflowY: 'scroll' }} variant="outlined">
|
||||
{!isLoading &&
|
||||
<Paper elevation={1} className={classes.listPaper} variant="outlined">
|
||||
<List>
|
||||
{[.4, 5, 7, 7, 8, 9, 100, 1, 2, 3].map((value) => {
|
||||
const labelId = `checkbox-list-label-${value}`;
|
||||
|
||||
{permissions && permissions.map((permission) => {
|
||||
return (
|
||||
<ListItem key={value} role={undefined} dense button>
|
||||
<ListItemText id={labelId} primary={`Line item ${value + 1}`} />
|
||||
<ListItem key={permission.email} role={undefined} dense button>
|
||||
<ListItemText id={`${permission.name}<${permission.email}>`} primary={permission.email} />
|
||||
|
||||
<RoleIcon role={permission.role} />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<IconButton edge="end">
|
||||
<DeleteIcon />
|
||||
@ -90,11 +168,11 @@ const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
||||
})}
|
||||
</List>
|
||||
</Paper>
|
||||
}
|
||||
|
||||
</BaseDialog>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default ShareDialog;
|
@ -0,0 +1,27 @@
|
||||
import createStyles from "@material-ui/core/styles/createStyles";
|
||||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
|
||||
export const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
actionContainer: {
|
||||
padding: '10px 0px',
|
||||
border: '1px solid rgba(0, 0, 0, 0.12)',
|
||||
borderRadius: '8px 8px 0px 0px',
|
||||
textAlign: "center"
|
||||
},
|
||||
textArea:
|
||||
{
|
||||
width: '730px',
|
||||
margin: '5px 0px',
|
||||
padding: '10px'
|
||||
},
|
||||
listPaper: {
|
||||
maxHeight: 200,
|
||||
overflowY: 'scroll',
|
||||
},
|
||||
paper: {
|
||||
width: "850px",
|
||||
minWidth: "850px"
|
||||
}
|
||||
}),
|
||||
);
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import Help from "@material-ui/icons/Help";
|
||||
import PolicyOutlined from "@material-ui/icons/PolicyOutlined";
|
||||
@ -11,10 +11,12 @@ import Menu from "@material-ui/core/Menu";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import Link from "@material-ui/core/Link";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
|
||||
const HelpMenu = (): React.ReactElement => {
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const intl = useIntl();
|
||||
|
||||
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
@ -26,11 +28,14 @@ const HelpMenu = (): React.ReactElement => {
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip arrow={true} title={intl.formatMessage({ id: 'help.support', defaultMessage: 'Support' })}>
|
||||
|
||||
<IconButton
|
||||
aria-haspopup="true"
|
||||
onClick={handleMenu}>
|
||||
<Help />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Menu id="appbar-profile"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
|
@ -74,7 +74,10 @@ const MapsPage = (): ReactElement => {
|
||||
const mutation = useMutation(
|
||||
(id: number) => client.deleteLabel(id),
|
||||
{
|
||||
onSuccess: () => queryClient.invalidateQueries('labels')
|
||||
onSuccess: () => queryClient.invalidateQueries('labels'),
|
||||
onError: (error) => {
|
||||
console.error(`Unexpected error ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@ -87,8 +90,8 @@ const MapsPage = (): ReactElement => {
|
||||
mutation.mutate(id);
|
||||
};
|
||||
|
||||
const { data } = useQuery<unknown, ErrorInfo, Label[]>('labels', async () => {
|
||||
return await client.fetchLabels();
|
||||
const { data } = useQuery<unknown, ErrorInfo, Label[]>('labels', () => {
|
||||
return client.fetchLabels();
|
||||
});
|
||||
|
||||
const labels: Label[] = data ? data : [];
|
||||
@ -140,7 +143,7 @@ const MapsPage = (): ReactElement => {
|
||||
elevation={0}>
|
||||
|
||||
<Toolbar>
|
||||
<Tooltip title={intl.formatMessage({ id: 'maps.create-tooltip', defaultMessage: 'Create a New Map' })}>
|
||||
<Tooltip arrow={true} title={intl.formatMessage({ id: 'maps.create-tooltip', defaultMessage: 'Create a New Map' })}>
|
||||
<Button color="primary"
|
||||
size="medium"
|
||||
variant="contained"
|
||||
@ -153,7 +156,7 @@ const MapsPage = (): ReactElement => {
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={intl.formatMessage({ id: 'maps.import-desc', defaultMessage: 'Import from other tools' })}>
|
||||
<Tooltip arrow={true} title={intl.formatMessage({ id: 'maps.import-desc', defaultMessage: 'Import from other tools' })}>
|
||||
<Button
|
||||
color="primary"
|
||||
size="medium"
|
||||
|
@ -32,6 +32,9 @@ const LanguageMenu = (): React.ReactElement => {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries('account')
|
||||
handleClose();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(`Unexpected error ${error}`)
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -52,7 +55,7 @@ const LanguageMenu = (): React.ReactElement => {
|
||||
const accountInfo = fetchAccount();
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title={intl.formatMessage({ id: 'language.change', defaultMessage: 'Change Language' })}>
|
||||
<Tooltip arrow={true} title={intl.formatMessage({ id: 'language.change', defaultMessage: 'Change Language' })}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
|
@ -225,8 +225,8 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
}, [props.filter.type, (props.filter as LabelFilter).label]);
|
||||
|
||||
|
||||
const { isLoading, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
||||
return await client.fetchAllMaps();
|
||||
const { isLoading, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
||||
return client.fetchAllMaps();
|
||||
});
|
||||
const mapsInfo: MapInfo[] = data ? data.filter(mapsFilter(filter, searchCondition)) : [];
|
||||
|
||||
@ -346,7 +346,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
|
||||
<div className={classes.toolbarActions}>
|
||||
{selected.length > 0 &&
|
||||
<Tooltip title="Delete selected">
|
||||
<Tooltip arrow={true} title="Delete selected">
|
||||
<Button
|
||||
color="primary"
|
||||
size="medium"
|
||||
@ -362,7 +362,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
}
|
||||
|
||||
{selected.length > 0 &&
|
||||
<Tooltip title="Add label to selected">
|
||||
<Tooltip arrow={true} title="Add label to selected">
|
||||
<Button
|
||||
color="primary"
|
||||
size="medium"
|
||||
@ -456,7 +456,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
<TableCell
|
||||
padding="checkbox"
|
||||
className={classes.bodyCell}>
|
||||
<Tooltip title="Starred">
|
||||
<Tooltip arrow={true} title="Starred">
|
||||
<IconButton aria-label="Starred" size="small" onClick={(e) => handleStarred(e, row.id)}>
|
||||
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
|
||||
</IconButton>
|
||||
@ -464,7 +464,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title="Open for edition" placement="bottom-start">
|
||||
<Tooltip arrow={true} title="Open for edition" placement="bottom-start">
|
||||
<Link href={`/c/maps/${row.id}/edit`} color="textPrimary" underline="always" onClick={(e) => e.stopPropagation()}>
|
||||
{row.title}
|
||||
</Link>
|
||||
@ -480,7 +480,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title={
|
||||
<Tooltip arrow={true} title={
|
||||
`Modified by ${row.lastModificationBy} on ${dayjs(row.lastModificationTime).format("lll")}`
|
||||
} placement="bottom-start">
|
||||
<span>{dayjs(row.lastModificationTime).fromNow()}</span>
|
||||
@ -488,7 +488,7 @@ export const MapsList = (props: MapsListProps):React.ReactElement => {
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title={intl.formatMessage({ id: 'map.more-actions', defaultMessage: 'More Actions' })}>
|
||||
<Tooltip arrow={true} title={intl.formatMessage({ id: 'map.more-actions', defaultMessage: 'More Actions' })}>
|
||||
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
|
||||
<MoreHorizIcon color="action" />
|
||||
</IconButton>
|
||||
|
47
packages/webapp/src/components/maps-page/role-icon/index.tsx
Normal file
47
packages/webapp/src/components/maps-page/role-icon/index.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from "react";
|
||||
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import PersonSharpIcon from '@material-ui/icons/PersonSharp';
|
||||
import EditSharpIcon from '@material-ui/icons/EditSharp';
|
||||
import VisibilitySharpIcon from '@material-ui/icons/VisibilitySharp';
|
||||
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Role } from "../../../classes/client";
|
||||
|
||||
type RoleIconProps = {
|
||||
role: Role;
|
||||
}
|
||||
|
||||
const RoleIcon = ({ role }: RoleIconProps): React.ReactElement => {
|
||||
|
||||
return (
|
||||
<span>
|
||||
{role == 'owner' &&
|
||||
<Tooltip
|
||||
title={<FormattedMessage id="role.owner" defaultMessage="Onwer" />}
|
||||
arrow={true}
|
||||
>
|
||||
<PersonSharpIcon />
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
{ role == 'editor' &&
|
||||
<Tooltip
|
||||
title={<FormattedMessage id="role.editor" defaultMessage="Editor" />}
|
||||
arrow={true}>
|
||||
<EditSharpIcon />
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
{role == 'viewer' &&
|
||||
<Tooltip
|
||||
title={<FormattedMessage id="role.viewer" defaultMessage="Viewer" />}
|
||||
arrow={true}>
|
||||
<VisibilitySharpIcon />
|
||||
</Tooltip>
|
||||
}
|
||||
</span>)
|
||||
};
|
||||
|
||||
export default RoleIcon;
|
||||
|
@ -76,7 +76,7 @@ export const fetchMapById = (id: number): MapLoadResult => {
|
||||
});
|
||||
|
||||
const result = data?.find(m => m.id == id);
|
||||
const map = result ? result : null;
|
||||
const map = result || null;
|
||||
return { isLoading: isLoading, error: error, map: map };
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user