mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-10 17:33:24 +01:00
Add create dialog
This commit is contained in:
parent
67fec75d91
commit
481c1fe619
@ -56,6 +56,15 @@
|
||||
"common.wait": {
|
||||
"defaultMessage": "Please wait ..."
|
||||
},
|
||||
"create.button": {
|
||||
"defaultMessage": "Create"
|
||||
},
|
||||
"create.description": {
|
||||
"defaultMessage": "Please, fill the new map name and description."
|
||||
},
|
||||
"create.title": {
|
||||
"defaultMessage": "Create a new mindmap"
|
||||
},
|
||||
"duplicate.title": {
|
||||
"defaultMessage": "Duplicate"
|
||||
},
|
||||
|
@ -33,6 +33,7 @@ export type ErrorInfo = {
|
||||
}
|
||||
|
||||
interface Client {
|
||||
createMap(rest: { name: string; description?: string | undefined })
|
||||
deleteLabel(label: string): Promise<unknown>;
|
||||
registerNewUser(user: NewUser): Promise<void>;
|
||||
resetPassword(email: string): Promise<void>;
|
||||
|
@ -43,7 +43,10 @@ class MockClient implements Client {
|
||||
|
||||
}
|
||||
|
||||
|
||||
createMap(rest: { name: string; description?: string | undefined; }) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
s
|
||||
fetchLabels(): Promise<string[]> {
|
||||
console.log("Fetching labels from server")
|
||||
return Promise.resolve(this.labels);
|
||||
|
@ -113,6 +113,24 @@
|
||||
"value": "Please wait ..."
|
||||
}
|
||||
],
|
||||
"create.button": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create"
|
||||
}
|
||||
],
|
||||
"create.description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Please, fill the new map name and description."
|
||||
}
|
||||
],
|
||||
"create.title": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create a new mindmap"
|
||||
}
|
||||
],
|
||||
"duplicate.title": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -12,7 +12,7 @@ import ShareOutlinedIcon from '@material-ui/icons/ShareOutlined';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { LabelOutlined } from '@material-ui/icons';
|
||||
|
||||
export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'label' | 'rename' | 'print' | 'info' | 'publish' | 'history' | undefined;
|
||||
export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'create'| 'duplicate' | 'export' | 'label' | 'rename' | 'print' | 'info' | 'publish' | 'history' | undefined;
|
||||
|
||||
interface ActionProps {
|
||||
onClose: (action: ActionType) => void;
|
||||
|
@ -68,7 +68,7 @@ const BaseDialog = (props: DialogProps) => {
|
||||
variant="contained"
|
||||
type="submit"
|
||||
disableElevation={true}>
|
||||
{props.title}
|
||||
{props.submitButton}
|
||||
</Button>) : null
|
||||
}
|
||||
</StyledDialogActions>
|
||||
|
@ -0,0 +1,85 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import { useSelector } from "react-redux";
|
||||
import { FormControl } from "@material-ui/core";
|
||||
|
||||
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
|
||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
||||
import Input from "../../../form/input";
|
||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||
import BaseDialog from "../action-dialog";
|
||||
|
||||
export type CreateModel = {
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type CreateProps = {
|
||||
open: boolean,
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const defaultModel: CreateModel = { name: '', description: ''};
|
||||
const CreateDialog = (props: CreateProps) => {
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const [model, setModel] = React.useState<CreateModel>(defaultModel);
|
||||
const [error, setError] = React.useState<ErrorInfo>();
|
||||
const { open } = props;
|
||||
|
||||
const intl = useIntl();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const mutation = useMutation<CreateModel, ErrorInfo, CreateModel>((model: CreateModel) => {
|
||||
const { ...rest } = model;
|
||||
return client.createMap(rest).then(() => model);
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
handleOnMutationSuccess(props.onClose, queryClient);
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleOnClose = (): void => {
|
||||
props.onClose();
|
||||
setModel(defaultModel);
|
||||
setError(undefined);
|
||||
};
|
||||
|
||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||
event.preventDefault();
|
||||
mutation.mutate(model);
|
||||
};
|
||||
|
||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
event.preventDefault();
|
||||
|
||||
const name = event.target.name;
|
||||
const value = event.target.value;
|
||||
setModel({ ...model, [name as keyof BasicMapInfo]: value });
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BaseDialog open={open} onClose={handleOnClose} onSubmit={handleOnSubmit} error={error}
|
||||
title={intl.formatMessage({ id: 'create.title', defaultMessage: 'Create a new mindmap' })}
|
||||
description={intl.formatMessage({ id: 'create.description', defaultMessage: 'Please, fill the new map name and description.' })}
|
||||
submitButton={intl.formatMessage({ id: 'create.button', defaultMessage: 'Create' })}>
|
||||
|
||||
<FormControl fullWidth={true}>
|
||||
<Input name="name" type="text" label={{ id: "action.rename-name-placeholder", defaultMessage: "Name" }}
|
||||
value={model.name} onChange={handleOnChange} error={error} fullWidth={true} />
|
||||
|
||||
<Input name="description" type="text" label={{ id: "action.rename-description-placeholder", defaultMessage: "Description" }}
|
||||
value={model.description} onChange={handleOnChange} required={false} fullWidth={true} />
|
||||
</FormControl>
|
||||
</BaseDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreateDialog;
|
@ -10,6 +10,7 @@ import { activeInstance } from '../../../reducers/serviceSlice';
|
||||
import DuplicateDialog from './duplicate';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import InfoDialog from './info';
|
||||
import CreateDialog from './create';
|
||||
|
||||
|
||||
export type BasicMapInfo = {
|
||||
@ -43,6 +44,7 @@ const ActionDispatcher = (props: ActionDialogProps) => {
|
||||
|
||||
return (
|
||||
<span>
|
||||
<CreateDialog open={action === 'create'} onClose={handleOnClose}/>
|
||||
<DeleteDialog open={action === 'delete'} onClose={handleOnClose} mapId={mapId} />
|
||||
<RenameDialog open={action === 'rename'} onClose={handleOnClose} mapId={mapId} />
|
||||
<DuplicateDialog open={action === 'duplicate'} onClose={handleOnClose} mapId={mapId} />
|
||||
|
@ -16,11 +16,12 @@ import { useQuery, useMutation, useQueryClient } from 'react-query';
|
||||
import { activeInstance } from '../../reducers/serviceSlice';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Client from '../../client';
|
||||
import ActionDispatcher from './action-dispatcher';
|
||||
import { ActionType } from './action-chooser';
|
||||
|
||||
const logoIcon = require('../../images/logo-small.svg');
|
||||
const poweredByIcon = require('../../images/pwrdby-white.svg');
|
||||
|
||||
|
||||
export type Filter = GenericFilter | LabelFilter;
|
||||
|
||||
export interface GenericFilter {
|
||||
@ -42,6 +43,7 @@ const MapsPage = () => {
|
||||
const [filter, setFilter] = React.useState<Filter>({ type: 'all' });
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const queryClient = useQueryClient();
|
||||
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@ -103,8 +105,14 @@ const MapsPage = () => {
|
||||
|
||||
<Toolbar>
|
||||
<Tooltip title="Create a New Map">
|
||||
<Button color="primary" size="medium" variant="contained" type="button"
|
||||
disableElevation={true} startIcon={<AddCircleTwoTone />} className={classes.newMapButton}>
|
||||
<Button color="primary"
|
||||
size="medium"
|
||||
variant="contained"
|
||||
type="button"
|
||||
disableElevation={true}
|
||||
startIcon={<AddCircleTwoTone />}
|
||||
className={classes.newMapButton}
|
||||
onClick={e => setActiveDialog('create')}>
|
||||
<FormattedMessage id="action.new" defaultMessage="New Map" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
@ -115,6 +123,7 @@ const MapsPage = () => {
|
||||
<FormattedMessage id="action.import" defaultMessage="Import" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ActionDispatcher action={activeDialog} onClose={() => setActiveDialog(undefined)} mapId={-1} />
|
||||
|
||||
<div className={classes.rightButtonGroup}>
|
||||
<HelpToobarButton />
|
||||
|
@ -392,75 +392,79 @@ export const MapsList = (props: MapsListProps) => {
|
||||
/>
|
||||
|
||||
<TableBody>
|
||||
{isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy))
|
||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
.map((row: MapInfo) => {
|
||||
const isItemSelected = isSelected(row.id);
|
||||
const labelId = row.id;
|
||||
{isLoading ? (
|
||||
<TableRow><TableCell rowSpan={6}>Loading ...</TableCell></TableRow>) :
|
||||
(mapsInfo.length == 0 ?
|
||||
(<TableRow><TableCell rowSpan={6}>No matching records found</TableCell></TableRow>) :
|
||||
stableSort(mapsInfo, getComparator(order, orderBy))
|
||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
.map((row: MapInfo) => {
|
||||
const isItemSelected = isSelected(row.id);
|
||||
const labelId = row.id;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
onClick={(event: any) => handleRowClick(event, row.id)}
|
||||
role="checkbox"
|
||||
aria-checked={isItemSelected}
|
||||
tabIndex={-1}
|
||||
key={row.id}
|
||||
selected={isItemSelected}
|
||||
style={{ border: "0" }}
|
||||
>
|
||||
<TableCell
|
||||
padding="checkbox"
|
||||
className={classes.bodyCell}>
|
||||
<Checkbox
|
||||
checked={isItemSelected}
|
||||
inputProps={{ 'aria-labelledby': String(labelId) }}
|
||||
size="small" />
|
||||
</TableCell>
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
onClick={(event: any) => handleRowClick(event, row.id)}
|
||||
role="checkbox"
|
||||
aria-checked={isItemSelected}
|
||||
tabIndex={-1}
|
||||
key={row.id}
|
||||
selected={isItemSelected}
|
||||
style={{ border: "0" }}
|
||||
>
|
||||
<TableCell
|
||||
padding="checkbox"
|
||||
className={classes.bodyCell}>
|
||||
<Checkbox
|
||||
checked={isItemSelected}
|
||||
inputProps={{ 'aria-labelledby': String(labelId) }}
|
||||
size="small" />
|
||||
</TableCell>
|
||||
|
||||
<TableCell
|
||||
padding="checkbox"
|
||||
className={classes.bodyCell}>
|
||||
<Tooltip title="Starred">
|
||||
<IconButton aria-label="Starred" size="small" onClick={(e) => handleStarred(e, row.id)}>
|
||||
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
padding="checkbox"
|
||||
className={classes.bodyCell}>
|
||||
<Tooltip title="Starred">
|
||||
<IconButton aria-label="Starred" size="small" onClick={(e) => handleStarred(e, row.id)}>
|
||||
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title="Open for edition" placement="bottom-start">
|
||||
<Link href={`c/maps/${row.id}/edit`} color="textPrimary" underline="always">
|
||||
{row.name}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title="Open for edition" placement="bottom-start">
|
||||
<Link href={`c/maps/${row.id}/edit`} color="textPrimary" underline="always">
|
||||
{row.name}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
{row.labels}
|
||||
</TableCell>
|
||||
<TableCell className={classes.bodyCell}>
|
||||
{row.labels}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
{row.creator}
|
||||
</TableCell>
|
||||
<TableCell className={classes.bodyCell}>
|
||||
{row.creator}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title={moment(row.modified).format("lll")} placement="bottom-start">
|
||||
<span>{moment(row.modified).fromNow()}</span>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title={moment(row.modified).format("lll")} placement="bottom-start">
|
||||
<span>{moment(row.modified).fromNow()}</span>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title="Others">
|
||||
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
|
||||
<MoreHorizIcon color="action" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
<TableCell className={classes.bodyCell}>
|
||||
<Tooltip title="Others">
|
||||
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
|
||||
<MoreHorizIcon color="action" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
Loading…
Reference in New Issue
Block a user