diff --git a/client/package.json b/client/package.json index 0a7ed3b80..978e284c3 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "@types/react-router-dom": "^5.1.7", "bootstrap": "^4.6.0", "formik": "^2.2.9", + "immutable": "^4.0.0-rc.12", "react": "^17.0.2", "react-bootstrap": "^1.6.1", "react-dom": "^17.0.2", diff --git a/client/src/Components/App/App.tsx b/client/src/Components/App/App.tsx index f764fc176..a079d6d9f 100644 --- a/client/src/Components/App/App.tsx +++ b/client/src/Components/App/App.tsx @@ -1,5 +1,6 @@ import React, {useState} from 'react'; import pythonPackageJson from "../../data/sklearn.json"; +import AnnotationStore from "../../model/annotation/AnnotationStore"; import PythonDeclaration from "../../model/python/PythonDeclaration"; import {parsePythonPackageJson, PythonPackageJson} from "../../model/python/PythonPackageBuilder"; import Menu from "../Menu/Menu"; @@ -10,6 +11,7 @@ import AppCSS from './App.module.css'; export default function App(): JSX.Element { const pythonPackage = parsePythonPackageJson(pythonPackageJson as PythonPackageJson); const [selection, setSelection] = useState(pythonPackage); + const [annotationStore, setAnnotationStore] = useState(new AnnotationStore()); return (
@@ -17,12 +19,18 @@ export default function App(): JSX.Element {
- +
- +
); diff --git a/client/src/Components/Dialog/RenameDialog.tsx b/client/src/Components/Dialog/RenameDialog.tsx index 4d7bddbd9..a2e99b964 100644 --- a/client/src/Components/Dialog/RenameDialog.tsx +++ b/client/src/Components/Dialog/RenameDialog.tsx @@ -1,6 +1,5 @@ import React, {useState} from "react"; import {Button, Form, Modal} from "react-bootstrap"; -import RenameAnnotation from "../../model/annotation/RenameAnnotation"; import {Nullable, Setter} from "../../util/types"; import {isValidPythonIdentifier} from "../../util/validation"; import "../ParameterView/ParameterView.css"; @@ -8,13 +7,13 @@ import "../ParameterView/ParameterView.css"; interface RenameDialogProps { isVisible: boolean setIsVisible: Setter - originalName: string - renameAnnotation: Nullable - setRenameAnnotation: Setter> + oldName: string + newName: Nullable + setNewName: Setter> } export default function RenameDialog(props: RenameDialogProps): JSX.Element { - const [currentUserInput, setCurrentUserInput] = useState(props.renameAnnotation?.newName ?? props.originalName); + const [currentUserInput, setCurrentUserInput] = useState(props.newName ?? props.oldName); const handleChange = (event: React.ChangeEvent) => setCurrentUserInput(event.target.value); @@ -23,11 +22,11 @@ export default function RenameDialog(props: RenameDialogProps): JSX.Element { }; const submit = () => { - if (currentUserInput === props.originalName) { - props.setRenameAnnotation(null); + if (currentUserInput === props.oldName) { + props.setNewName(null); props.setIsVisible(false); } else if (isValidPythonIdentifier(currentUserInput)) { - props.setRenameAnnotation(new RenameAnnotation(currentUserInput)); + props.setNewName(currentUserInput); props.setIsVisible(false); } }; @@ -46,7 +45,7 @@ export default function RenameDialog(props: RenameDialogProps): JSX.Element { - New name for "{props.originalName}": + New name for "{props.oldName}": } export default function ParameterNode(props: ParameterNodeProps): JSX.Element { const [showRenameDialog, setShowRenameDialog] = useState(false); - const [renameAnnotation, setRenameAnnotation] = useState>(null); + + const newName = props.annotationStore.getRenamingFor(props.pythonParameter); + const setNewName = (newName: Nullable) => { + props.setAnnotationStore( + props.annotationStore.setRenamingFor(props.pythonParameter, newName) + ); + }; const openRenameDialog = () => setShowRenameDialog(true); const handleEnumSelect = () => console.log("TODO"); @@ -22,7 +30,7 @@ export default function ParameterNode(props: ParameterNodeProps): JSX.Element { return (
-

{props.inputParameter.name}

+

{props.pythonParameter.name}

+ @Annotation @@ -34,8 +42,8 @@ export default function ParameterNode(props: ParameterNodeProps): JSX.Element {
@@ -43,17 +51,17 @@ export default function ParameterNode(props: ParameterNodeProps): JSX.Element { {showRenameDialog && } { - props.inputParameter.description && - + props.pythonParameter.description && + } { - !props.inputParameter.description && + !props.pythonParameter.description &&

There is no documentation for this parameter.

}
diff --git a/client/src/Components/ParameterView/ParameterView.tsx b/client/src/Components/ParameterView/ParameterView.tsx index 2268ddc38..3d705fbc8 100644 --- a/client/src/Components/ParameterView/ParameterView.tsx +++ b/client/src/Components/ParameterView/ParameterView.tsx @@ -1,27 +1,36 @@ import React from "react"; +import AnnotationStore from "../../model/annotation/AnnotationStore"; import PythonDeclaration from "../../model/python/PythonDeclaration"; import PythonFunction from "../../model/python/PythonFunction"; import {isEmptyList} from "../../util/listOperations"; +import {Setter} from "../../util/types"; import DocumentationText from "./DocumentationText"; import ParameterNode from "./ParameterNode"; interface ParameterViewProps { - selection: PythonDeclaration + selection: PythonDeclaration, + annotationStore: AnnotationStore + setAnnotationStore: Setter } -export default function ParameterView({selection}: ParameterViewProps): JSX.Element { +export default function ParameterView(props: ParameterViewProps): JSX.Element { return (
- {selection instanceof PythonFunction && + {props.selection instanceof PythonFunction && <> -

{selection.name}

- +

{props.selection.name}

+

Parameters

{ - !isEmptyList(selection.parameters) ? - selection.parameters.map(function (parameters) { - return (); - }) : + !isEmptyList(props.selection.parameters) ? + props.selection.parameters.map(parameters => ( + + )) : There are no parameters. } diff --git a/client/src/Components/ParameterView/RenameAnnotationView.tsx b/client/src/Components/ParameterView/RenameAnnotationView.tsx index 4553f3521..19ad14587 100644 --- a/client/src/Components/ParameterView/RenameAnnotationView.tsx +++ b/client/src/Components/ParameterView/RenameAnnotationView.tsx @@ -1,25 +1,24 @@ +import {faTrash, faWrench} from '@fortawesome/free-solid-svg-icons'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import React from "react"; import {Button, ButtonGroup, Col, Row} from "react-bootstrap"; -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faTrash, faWrench} from '@fortawesome/free-solid-svg-icons'; -import RenameAnnotation from "../../model/annotation/RenameAnnotation"; import {Nullable, Setter} from "../../util/types"; interface RenameAnnotationViewProps { - renameAnnotation: Nullable, - setRenameAnnotation: Setter>, + newName: Nullable, + setNewName: Setter>, onRenameEdit: () => void, } const RenameAnnotationView: React.FC = (props) => { - const deleteRenameAnnotation = () => props.setRenameAnnotation(null); + const deleteRenameAnnotation = () => props.setNewName(null); - if (props.renameAnnotation !== null) { + if (props.newName !== null) { return (
Annotations
- {`@rename: ${props.renameAnnotation.newName}`} + {`@rename: ${props.newName}`} diff --git a/client/src/model/annotation/AnnotationStore.tsx b/client/src/model/annotation/AnnotationStore.tsx new file mode 100644 index 000000000..6e79a25c1 --- /dev/null +++ b/client/src/model/annotation/AnnotationStore.tsx @@ -0,0 +1,29 @@ +import {Map} from "immutable"; +import {Nullable} from "../../util/types"; +import PythonDeclaration from "../python/PythonDeclaration"; + +export default class AnnotationStore { + private readonly renamings: RenameAnnotationStore + + constructor(renamings: RenameAnnotationStore = Map()) { + this.renamings = renamings; + } + + getRenamingFor(declaration: PythonDeclaration): Nullable { + return this.renamings.get(declaration.pathAsString()) ?? null; + } + + setRenamingFor(declaration: PythonDeclaration, newName: Nullable): AnnotationStore { + if (newName === null) { + return this.removeRenamingFor(declaration); + } + + return new AnnotationStore(this.renamings.set(declaration.pathAsString(), newName)); + } + + removeRenamingFor(declaration: PythonDeclaration): AnnotationStore { + return new AnnotationStore(this.renamings.remove(declaration.pathAsString())); + } +} + +export type RenameAnnotationStore = Map diff --git a/client/src/model/annotation/RenameAnnotation.tsx b/client/src/model/annotation/RenameAnnotation.tsx deleted file mode 100644 index 467a61533..000000000 --- a/client/src/model/annotation/RenameAnnotation.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default class RenameAnnotation { - readonly newName: string; - - constructor(newName: string) { - this.newName = newName; - } -} diff --git a/client/src/model/python/PythonDeclaration.ts b/client/src/model/python/PythonDeclaration.ts index 1d73a34e5..28424708d 100644 --- a/client/src/model/python/PythonDeclaration.ts +++ b/client/src/model/python/PythonDeclaration.ts @@ -20,6 +20,10 @@ export default abstract class PythonDeclaration { return result; } + pathAsString(): string { + return this.path().join("/"); + } + getByRelativePath(relativePath: string[]): Nullable { if (isEmptyList(relativePath)) { return this; diff --git a/client/yarn.lock b/client/yarn.lock index 8f674a1e1..e78dea70e 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -5913,6 +5913,11 @@ immer@8.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"