Finish import

This commit is contained in:
Paulo Gustavo Veiga 2021-02-10 18:03:51 -08:00
parent 1c7dbb8af5
commit 1c5d6342e5
5 changed files with 81 additions and 17 deletions

View File

@ -6,6 +6,13 @@ export type NewUser = {
recaptcha: string | null; recaptcha: string | null;
} }
export type ImportMapInfo = {
title: string;
description?: string;
contentType?: string;
content?: ArrayBuffer | null | string;
}
export type Label = { export type Label = {
id: number; id: number;
title: string; title: string;
@ -55,6 +62,7 @@ export type AccountInfo = {
} }
interface Client { interface Client {
importMap(model: ImportMapInfo): Promise<number>
createMap(map: BasicMapInfo): Promise<number>; createMap(map: BasicMapInfo): Promise<number>;
deleteMaps(ids: number[]): Promise<void>; deleteMaps(ids: number[]): Promise<void>;
deleteMap(id: number): Promise<void>; deleteMap(id: number): Promise<void>;

View File

@ -1,5 +1,4 @@
import Client, { AccountInfo, BasicMapInfo, ChangeHistory, Label, MapInfo, NewUser } from '..'; import Client, { AccountInfo, BasicMapInfo, ChangeHistory, ImportMapInfo, Label, MapInfo, NewUser} from '..';
class MockClient implements Client { class MockClient implements Client {
private maps: MapInfo[] = []; private maps: MapInfo[] = [];
private labels: Label[] = []; private labels: Label[] = [];
@ -34,6 +33,10 @@ class MockClient implements Client {
]; ];
} }
importMap(model: ImportMapInfo): Promise<number> {
return Promise.resolve(10);
}
fetchAccountInfo(): Promise<AccountInfo> { fetchAccountInfo(): Promise<AccountInfo> {
return Promise.resolve({ return Promise.resolve({
firstName: 'Costme', firstName: 'Costme',

View File

@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo } from '..'; import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo, ImportMapInfo } from '..';
export default class RestClient implements Client { export default class RestClient implements Client {
private baseUrl: string; private baseUrl: string;
@ -9,6 +9,20 @@ export default class RestClient implements Client {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.sessionExpired = sessionExpired; this.sessionExpired = sessionExpired;
} }
importMap(model: ImportMapInfo): Promise<number> {
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
axios.post(this.baseUrl + `/c/restful/maps?title=${model.title}&description=${model.description ? model.description : ''}`,
model.content,
{ headers: { 'Content-Type': model.contentType } }
).then(response => {
const mapId = response.headers.resourceid;
success(mapId);
}).catch(error => {
const errorInfo = this.parseResponseOnError(error.response);
reject(errorInfo);
});
}
return new Promise(handler); }
fetchAccountInfo(): Promise<AccountInfo> { fetchAccountInfo(): Promise<AccountInfo> {
const handler = (success: (account: AccountInfo) => void, reject: (error: ErrorInfo) => void) => { const handler = (success: (account: AccountInfo) => void, reject: (error: ErrorInfo) => void) => {

View File

@ -13,12 +13,14 @@ export type DialogProps = {
title: string; title: string;
description?: string; description?: string;
submitButton?: string; submitButton?: string;
actionUrl?: string;
} }
const BaseDialog = (props: DialogProps) => { const BaseDialog = (props: DialogProps) => {
const intl = useIntl(); const intl = useIntl();
const { onClose, onSubmit } = props; const { onClose, onSubmit, actionUrl = "" } = props;
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => { const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();

View File

@ -13,13 +13,15 @@ import BaseDialog from '../base-dialog';
export type ImportModel = { export type ImportModel = {
title: string; title: string;
description?: string; description?: string;
contentType?: string;
content?: ArrayBuffer | null | string;
} }
export type CreateProps = { export type CreateProps = {
onClose: () => void onClose: () => void
} }
const defaultModel: ImportModel = { title: '', description: '' }; const defaultModel: ImportModel = { title: '' };
const ImportDialog = (props: CreateProps) => { const ImportDialog = (props: CreateProps) => {
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const [model, setModel] = React.useState<ImportModel>(defaultModel); const [model, setModel] = React.useState<ImportModel>(defaultModel);
@ -27,7 +29,7 @@ const ImportDialog = (props: CreateProps) => {
const intl = useIntl(); const intl = useIntl();
const mutation = useMutation<number, ErrorInfo, ImportModel>((model: ImportModel) => { const mutation = useMutation<number, ErrorInfo, ImportModel>((model: ImportModel) => {
return client.createMap(model); return client.importMap(model);
}, },
{ {
onSuccess: (mapId: number) => { onSuccess: (mapId: number) => {
@ -55,9 +57,41 @@ const ImportDialog = (props: CreateProps) => {
const name = event.target.name; const name = event.target.name;
const value = event.target.value; const value = event.target.value;
setModel({ ...model, [name as keyof BasicMapInfo]: value }); setModel({ ...model, [name as keyof ImportModel]: value });
} }
const handleOnFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event?.target?.files;
const reader = new FileReader();
if (files) {
const file = files[0];
var title = file.name;
title = title.substring(0, title.lastIndexOf("."));
// Closure to capture the file information.
reader.onload = (event) => {
const fileContent = event?.target?.result;
model.content = fileContent;
// Suggest file name ...
const fileName = file.name;
if (fileName) {
var title = fileName.split('.')[0]
if (!model.title || 0 === model.title.length) {
model.title = title;
}
}
model.contentType = file.name.lastIndexOf(".wxml") != -1 ? "application/xml" : "application/freemind";
setModel({...model});
};
// Read in the image file as a data URL.
reader.readAsText(file);
}
};
return ( return (
<div> <div>
<BaseDialog onClose={handleOnClose} onSubmit={handleOnSubmit} error={error} <BaseDialog onClose={handleOnClose} onSubmit={handleOnSubmit} error={error}
@ -66,18 +100,21 @@ const ImportDialog = (props: CreateProps) => {
submitButton={intl.formatMessage({ id: 'import.button', defaultMessage: 'Create' })}> submitButton={intl.formatMessage({ id: 'import.button', defaultMessage: 'Create' })}>
<FormControl fullWidth={true}> <FormControl fullWidth={true}>
<input
accept=".wxml,.mm"
id="contained-button-file"
type="file"
required={true}
style={{ display: 'none' }}
onChange={handleOnFileChange}
/>
<Input name="title" type="text" label={intl.formatMessage({ id: "action.rename-name-placeholder", defaultMessage: "Name" })} <Input name="title" type="text" label={intl.formatMessage({ id: "action.rename-name-placeholder", defaultMessage: "Name" })}
value={model.title} onChange={handleOnChange} error={error} fullWidth={true} /> value={model.title} onChange={handleOnChange} error={error} fullWidth={true} />
<Input name="description" type="text" label={intl.formatMessage({ id: "action.rename-description-placeholder", defaultMessage: "Description" })} <Input name="description" type="text" label={intl.formatMessage({ id: "action.rename-description-placeholder", defaultMessage: "Description" })}
value={model.description} onChange={handleOnChange} required={false} fullWidth={true} /> value={model.description} onChange={handleOnChange} required={false} fullWidth={true} />
<input
accept="image/*"
id="contained-button-file"
type="file"
style={{display: 'none'}}
/>
<label htmlFor="contained-button-file"> <label htmlFor="contained-button-file">
<Button variant="outlined" color="primary" component="span" style={{ margin: '10px 5px', width: '100%' }}> <Button variant="outlined" color="primary" component="span" style={{ margin: '10px 5px', width: '100%' }}>
<FormattedMessage id="maps.choose-file" defaultMessage="Choose a file" /> <FormattedMessage id="maps.choose-file" defaultMessage="Choose a file" />