ImportFile.tsx 3.26 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { PetriNetObject } from '@pseuco/colored-petri-nets/dist/coloredPetriNets';
import React, { useCallback, useEffect, useState } from 'react';
import { Button, ProgressBar } from 'react-bootstrap';
import { LTS } from '../../../../pseuco-shared-components/lts/lts';
import { TaskManagerAPI } from '../util/taskmanagerTypes';
import { redirect } from '../utils';
import { FilesAPI, fileTypes } from './filesAPI';
import { FileTypes } from './fileTypes';

export type PossibleImport = {
    formatName: string,
    data: LTS | PetriNetObject
};

let debounceTimeoutId: number | null = null;
export const ImportFile: React.FC<{
    fileType: keyof FileTypes,
    taskManager: TaskManagerAPI
}> = ({ fileType: fileTypeName, taskManager }) => {
    const fileType = fileTypes[fileTypeName];

    const [currentTask, setCurrentTask] = useState<null | number>(null);
    const [, _setImportData] = useState("");

    const fullscreenMode = false; // TODO: detect fullscreen, embed
    const [possibleImports, setPossibleImports] = useState<PossibleImport[]>([]);
    const [worker] = useState(taskManager.requestWorker("importer", (e) => {
        console.log("Importer worker crashed",e);
    }));

    useEffect(() => () => worker.terminateWorker());

    const parse = useCallback((newstr: string) => {
        // sanity check
        if (fileTypeName === "pseuco" || fileTypeName === "ccs") return;
        // kill running workers
        if (currentTask !== null) worker.cancelTask(currentTask);
        
        const taskId = worker.submitTask('parse', {
            data: newstr,
            fileType: fileTypeName
        }, ({possibleImports}) => {
            setPossibleImports(possibleImports);
            setCurrentTask(null);
        }, null, 5);
        setCurrentTask(taskId);
    }, [currentTask, fileTypeName, worker]);
    
    const setImportData = (newData: string) => {
        _setImportData(newData);
        if (debounceTimeoutId !== null) window.clearTimeout(debounceTimeoutId);
        debounceTimeoutId = window.setTimeout(() => {
            parse(newData);
        }, 1000);
    };

    const performImport = (possibleImports: PossibleImport): void => {
        const file = FilesAPI.createFile(fileTypeName);
        FilesAPI.setFileContent(file, possibleImports.data);
        redirect("edit/local/" + file.id);
    };

    return <div className="container">
        <h1>Import { fileType.fullName } file</h1>

        <p>Paste or type a {fileType.fullName} file below. We support {fileType.importableFilesStatement}.</p>

        <textarea onChange={(e) => setImportData(e.target.value)} className="import-box"></textarea>
        {!fullscreenMode ?
            <ProgressBar active={currentTask !== null} striped now={100} />
            : null}


        {possibleImports.length === 0 ?
            <p>
                Sorry, we can't parse the data you provided. Please make sure you are using a supported file format.
            </p>
            : possibleImports.map((possibleImport, index) =>
                <Button key={index} onClick={() => performImport(possibleImport)} bsStyle="success" style={{ marginRight: 10 }}>
                    <span className="glyphicon glyphicon-import pad-right-5" /> Import as {possibleImport.formatName}
                </Button>
            )
        }
    </div>;
};