From acb39dc0329e7962ed6ab084a27d41db72c9473e Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Thu, 19 May 2022 14:21:26 +0200 Subject: [PATCH 1/3] build: bump @lars-reimann/prettier-config to v5.0.0 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5446a3803..b125f03b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "devDependencies": { "@lars-reimann/eslint-config": "^4.1.2", - "@lars-reimann/prettier-config": "^4.0.4" + "@lars-reimann/prettier-config": "^5.0.0" } }, "node_modules/@babel/code-frame": { @@ -217,9 +217,9 @@ } }, "node_modules/@lars-reimann/prettier-config": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@lars-reimann/prettier-config/-/prettier-config-4.0.4.tgz", - "integrity": "sha512-/ZNaWoQouy0gmjEmjLlek5xOY7OULEJSBAZR3mHJPCXgaCweJULME0cVadlOrpODbskO6Tr/8zPr0uie8kjOag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@lars-reimann/prettier-config/-/prettier-config-5.0.0.tgz", + "integrity": "sha512-52Ha8xMKpQESiaEzceWgyQb+fuPVD3wl2p6Op1mpLyLj6natjq7Vy8lAmbWS3AbPRjPlJZZHnp/b+sOAOdNqbA==", "dev": true, "peerDependencies": { "prettier": ">= 2" @@ -3600,9 +3600,9 @@ } }, "@lars-reimann/prettier-config": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@lars-reimann/prettier-config/-/prettier-config-4.0.4.tgz", - "integrity": "sha512-/ZNaWoQouy0gmjEmjLlek5xOY7OULEJSBAZR3mHJPCXgaCweJULME0cVadlOrpODbskO6Tr/8zPr0uie8kjOag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@lars-reimann/prettier-config/-/prettier-config-5.0.0.tgz", + "integrity": "sha512-52Ha8xMKpQESiaEzceWgyQb+fuPVD3wl2p6Op1mpLyLj6natjq7Vy8lAmbWS3AbPRjPlJZZHnp/b+sOAOdNqbA==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 8fff8cd80..c01b73ea4 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,6 @@ "prettier": "@lars-reimann/prettier-config", "devDependencies": { "@lars-reimann/eslint-config": "^4.1.2", - "@lars-reimann/prettier-config": "^4.0.4" + "@lars-reimann/prettier-config": "^5.0.0" } } From acb75ae33b8ef4d8209bb63a2ca7aca684c4ae16 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Thu, 19 May 2022 14:03:07 +0200 Subject: [PATCH 2/3] feat: import usage data --- api-editor/gui/src/app/App.tsx | 58 +++++++-- api-editor/gui/src/app/store.ts | 2 + api-editor/gui/src/common/MenuBar.tsx | 8 ++ .../src/features/usages/UsageImportDialog.tsx | 113 ++++++++++++++++++ .../features/usages/model/UsageCountStore.ts | 50 ++++++++ .../gui/src/features/usages/usageSlice.ts | 34 ++++++ 6 files changed, 255 insertions(+), 10 deletions(-) create mode 100644 api-editor/gui/src/features/usages/UsageImportDialog.tsx create mode 100644 api-editor/gui/src/features/usages/model/UsageCountStore.ts create mode 100644 api-editor/gui/src/features/usages/usageSlice.ts diff --git a/api-editor/gui/src/app/App.tsx b/api-editor/gui/src/app/App.tsx index 992f7171a..9af8fbbba 100644 --- a/api-editor/gui/src/app/App.tsx +++ b/api-editor/gui/src/app/App.tsx @@ -11,11 +11,12 @@ import { UnorderedList, } from '@chakra-ui/react'; import * as idb from 'idb-keyval'; -import React, { useEffect, useState } from 'react'; -import { useLocation } from 'react-router'; +import React, {useEffect, useState} from 'react'; +import {useLocation} from 'react-router'; import MenuBar from '../common/MenuBar'; -import { Setter } from '../common/util/types'; -import AnnotationImportDialog from '../features/annotations/AnnotationImportDialog'; +import {Setter} from '../common/util/types'; +import AnnotationImportDialog + from '../features/annotations/AnnotationImportDialog'; import { AnnotationsState, GroupUserAction, @@ -32,38 +33,58 @@ import GroupForm from '../features/annotations/forms/GroupForm'; import MoveForm from '../features/annotations/forms/MoveForm'; import OptionalForm from '../features/annotations/forms/OptionalForm'; import RenameForm from '../features/annotations/forms/RenameForm'; -import { PythonFilter } from '../features/packageData/model/PythonFilter'; +import {PythonFilter} from '../features/packageData/model/PythonFilter'; import PythonPackage from '../features/packageData/model/PythonPackage'; import { parsePythonPackageJson, PythonPackageJson, } from '../features/packageData/model/PythonPackageBuilder'; -import PackageDataImportDialog from '../features/packageData/PackageDataImportDialog'; +import PackageDataImportDialog + from '../features/packageData/PackageDataImportDialog'; import { selectShowPackageDataImportDialog, toggleIsExpandedInTreeView, } from '../features/packageData/packageDataSlice'; import SelectionView from '../features/packageData/selectionView/SelectionView'; import TreeView from '../features/packageData/treeView/TreeView'; -import { useAppDispatch, useAppSelector } from './hooks'; +import {useAppDispatch, useAppSelector} from './hooks'; import PythonFunction from '../features/packageData/model/PythonFunction'; import AttributeForm from '../features/annotations/forms/AttributeForm'; +import { + UsageCountJson, + UsageCountStore +} from "../features/usages/model/UsageCountStore"; +import {selectShowUsageImportDialog} from "../features/usages/usageSlice"; +import UsageImportDialog from '../features/usages/UsageImportDialog'; const App: React.FC = function () { + const dispatch = useAppDispatch(); + const currentUserAction = useAppSelector(selectCurrentUserAction); + const currentPathName = useLocation().pathname; + + // Initialize package data const [pythonPackage, setPythonPackage] = useState( new PythonPackage('empty', 'empty', '0.0.1'), ); - const currentUserAction = useAppSelector(selectCurrentUserAction); - const currentPathName = useLocation().pathname; useEffect(() => { // noinspection JSIgnoredPromiseFromCall getPythonPackageFromIndexedDB(setPythonPackage); }, []); + // Initialize usages + const [usages, setUsages] = useState( + new UsageCountStore() + ) + + useEffect(() => { + // noinspection JSIgnoredPromiseFromCall + getUsagesFromIndexedDB(setUsages) + }) + + // Initialize annotations const annotationStore = useAppSelector(selectAnnotations); - const dispatch = useAppDispatch(); useEffect(() => { dispatch(initializeAnnotations()); }, [dispatch]); @@ -97,6 +118,9 @@ const App: React.FC = function () { const showPackageDataImportDialog = useAppSelector( selectShowPackageDataImportDialog, ); + const showUsagesImportDialog = useAppSelector( + selectShowUsageImportDialog, + ); const [showInferErrorDialog, setShowInferErrorDialog] = useState(false); const [inferErrors, setInferErrors] = useState([]); @@ -194,6 +218,11 @@ const App: React.FC = function () { setFilter={setFilter} /> )} + {showUsagesImportDialog && ( + + )} , +) { + const storedUsages = (await idb.get('usages')) as UsageCountJson; + if (storedUsages) { + setUsages(UsageCountStore.fromJson(storedUsages)); + } +}; + const setAnnotationsInIndexedDB = async function ( annotationStore: AnnotationsState, ) { diff --git a/api-editor/gui/src/app/store.ts b/api-editor/gui/src/app/store.ts index 9d830b0d0..28e6cf315 100644 --- a/api-editor/gui/src/app/store.ts +++ b/api-editor/gui/src/app/store.ts @@ -2,11 +2,13 @@ import { configureStore } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query'; import annotationReducer from '../features/annotations/annotationSlice'; import packageDataReducer from '../features/packageData/packageDataSlice'; +import usageReducer from '../features/usages/usageSlice'; export const store = configureStore({ reducer: { annotations: annotationReducer, packageData: packageDataReducer, + usages: usageReducer }, }); diff --git a/api-editor/gui/src/common/MenuBar.tsx b/api-editor/gui/src/common/MenuBar.tsx index aed0fb553..836267d9d 100644 --- a/api-editor/gui/src/common/MenuBar.tsx +++ b/api-editor/gui/src/common/MenuBar.tsx @@ -52,6 +52,7 @@ import { toggleShowPrivateDeclarations, } from '../features/packageData/packageDataSlice'; import { Setter } from './util/types'; +import {toggleUsageImportDialog} from "../features/usages/usageSlice"; interface MenuBarProps { pythonPackage: PythonPackage; @@ -243,6 +244,13 @@ const MenuBar: React.FC = function ({ > API Data + + dispatch(toggleUsageImportDialog()) + } + > + Usages + dispatch(toggleAnnotationImportDialog()) diff --git a/api-editor/gui/src/features/usages/UsageImportDialog.tsx b/api-editor/gui/src/features/usages/UsageImportDialog.tsx new file mode 100644 index 000000000..f4f4adc6c --- /dev/null +++ b/api-editor/gui/src/features/usages/UsageImportDialog.tsx @@ -0,0 +1,113 @@ +import { + Box, + Button, + FormControl, + FormLabel, + Heading, + HStack, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Text as ChakraText, +} from '@chakra-ui/react'; +import * as idb from 'idb-keyval'; +import React, {useState} from 'react'; +import {useAppDispatch} from '../../app/hooks'; +import StyledDropzone from '../../common/StyledDropzone'; +import {Setter} from '../../common/util/types'; +import {isValidJsonFile} from '../../common/util/validation'; +import {resetAnnotations} from '../annotations/annotationSlice'; +import {UsageCountJson, UsageCountStore} from './model/UsageCountStore'; + +import {toggleUsageImportDialog} from './usageSlice'; + +interface ImportPythonPackageDialogProps { + setUsages: Setter; +} + +const UsageImportDialog: React.FC = + function ({ setUsages }) { + const [fileName, setFileName] = useState(''); + const [newUsages, setNewUsages] = useState(); + const dispatch = useAppDispatch(); + + const submit = async () => { + if (newUsages) { + const parsedUsages = JSON.parse( + newUsages, + ) as UsageCountJson; + setUsages(UsageCountStore.fromJson(parsedUsages)); + + await idb.set('usages', parsedUsages); + } + close(); + }; + const close = () => dispatch(toggleUsageImportDialog()); + + const slurpAndParse = (acceptedFiles: File[]) => { + if (isValidJsonFile(acceptedFiles[acceptedFiles.length - 1].name)) { + if (acceptedFiles.length > 1) { + // eslint-disable-next-line no-param-reassign + acceptedFiles = [acceptedFiles[acceptedFiles.length - 1]]; + } + setFileName(acceptedFiles[0].name); + const reader = new FileReader(); + reader.onload = () => { + if (typeof reader.result === 'string') { + setNewUsages(reader.result); + dispatch(resetAnnotations()); + } + }; + reader.readAsText(acceptedFiles[0]); + } + }; + + return ( + + + + + Import usages + + + + + Select a usage file to import. + + + + Drag and drop a usage file here or click + to select the file. + + + (Only *.json will be accepted.) + + + + {fileName && ( + + Imported file: + {fileName} + + )} + + + + + + + + + + + ); + }; + +export default UsageImportDialog; diff --git a/api-editor/gui/src/features/usages/model/UsageCountStore.ts b/api-editor/gui/src/features/usages/model/UsageCountStore.ts new file mode 100644 index 000000000..2d4e519d7 --- /dev/null +++ b/api-editor/gui/src/features/usages/model/UsageCountStore.ts @@ -0,0 +1,50 @@ +export interface UsageCountJson { + class_counts: { + [target: string]: number + }, + function_counts: { + [target: string]: number + }, + parameter_counts: { + [target: string]: number + }, + value_counts: { + [target: string]: { + [stringifiedValue: string]: number + } + } +} + +export class UsageCountStore { + static fromJson(json: UsageCountJson): UsageCountStore { + return new UsageCountStore( + new Map(Object.entries(json.class_counts)), + new Map(Object.entries(json.function_counts)), + new Map(Object.entries(json.parameter_counts)), + new Map(Object.entries(json.value_counts).map((entry) => + [entry[0], new Map(Object.entries(entry[1]))] + )) + ) + } + + constructor( + readonly classUsages: Map = new Map(), + readonly functionUsages: Map = new Map(), + readonly parameterUsages: Map = new Map(), + readonly valueUsages: Map> = new Map() + ) { + } + + toJson(): UsageCountJson { + return { + class_counts: Object.fromEntries(this.classUsages), + function_counts: Object.fromEntries(this.functionUsages), + parameter_counts: Object.fromEntries(this.parameterUsages), + value_counts: Object.fromEntries( + [...this.valueUsages.entries()].map((entry) => + [entry[0], Object.fromEntries(entry[1])] + ) + ) + } + } +} diff --git a/api-editor/gui/src/features/usages/usageSlice.ts b/api-editor/gui/src/features/usages/usageSlice.ts new file mode 100644 index 000000000..5088144f6 --- /dev/null +++ b/api-editor/gui/src/features/usages/usageSlice.ts @@ -0,0 +1,34 @@ +import {createSlice} from '@reduxjs/toolkit'; +import {RootState} from '../../app/store'; + +export interface UsageState { + showImportDialog: boolean; +} + +// Initial state ------------------------------------------------------------------------------------------------------- + +const initialState: UsageState = { + showImportDialog: false, +}; + +// Slice --------------------------------------------------------------------------------------------------------------- + +const usageSlice = createSlice({ + name: 'usages', + initialState, + reducers: { + toggleImportDialog(state) { + state.showImportDialog = !state.showImportDialog; + }, + }, +}); + +const { actions, reducer } = usageSlice; +export const { + toggleImportDialog: toggleUsageImportDialog, +} = actions; +export default reducer; + +const selectUsage = (state: RootState) => state.usages; +export const selectShowUsageImportDialog = (state: RootState): boolean => + selectUsage(state).showImportDialog; From 1815d51758086c2d35a10e58ac7855df6cc0e9fa Mon Sep 17 00:00:00 2001 From: lars-reimann Date: Thu, 19 May 2022 12:56:33 +0000 Subject: [PATCH 3/3] style: apply automatic fixes of linters --- api-editor/gui/src/app/App.tsx | 126 ++++---------- api-editor/gui/src/app/store.ts | 2 +- api-editor/gui/src/common/MenuBar.tsx | 139 ++++------------ .../src/features/usages/UsageImportDialog.tsx | 154 ++++++++---------- .../features/usages/model/UsageCountStore.ts | 37 ++--- .../gui/src/features/usages/usageSlice.ts | 11 +- 6 files changed, 157 insertions(+), 312 deletions(-) diff --git a/api-editor/gui/src/app/App.tsx b/api-editor/gui/src/app/App.tsx index 9af8fbbba..97c4ad7a1 100644 --- a/api-editor/gui/src/app/App.tsx +++ b/api-editor/gui/src/app/App.tsx @@ -11,12 +11,11 @@ import { UnorderedList, } from '@chakra-ui/react'; import * as idb from 'idb-keyval'; -import React, {useEffect, useState} from 'react'; -import {useLocation} from 'react-router'; +import React, { useEffect, useState } from 'react'; +import { useLocation } from 'react-router'; import MenuBar from '../common/MenuBar'; -import {Setter} from '../common/util/types'; -import AnnotationImportDialog - from '../features/annotations/AnnotationImportDialog'; +import { Setter } from '../common/util/types'; +import AnnotationImportDialog from '../features/annotations/AnnotationImportDialog'; import { AnnotationsState, GroupUserAction, @@ -33,28 +32,21 @@ import GroupForm from '../features/annotations/forms/GroupForm'; import MoveForm from '../features/annotations/forms/MoveForm'; import OptionalForm from '../features/annotations/forms/OptionalForm'; import RenameForm from '../features/annotations/forms/RenameForm'; -import {PythonFilter} from '../features/packageData/model/PythonFilter'; +import { PythonFilter } from '../features/packageData/model/PythonFilter'; import PythonPackage from '../features/packageData/model/PythonPackage'; -import { - parsePythonPackageJson, - PythonPackageJson, -} from '../features/packageData/model/PythonPackageBuilder'; -import PackageDataImportDialog - from '../features/packageData/PackageDataImportDialog'; +import { parsePythonPackageJson, PythonPackageJson } from '../features/packageData/model/PythonPackageBuilder'; +import PackageDataImportDialog from '../features/packageData/PackageDataImportDialog'; import { selectShowPackageDataImportDialog, toggleIsExpandedInTreeView, } from '../features/packageData/packageDataSlice'; import SelectionView from '../features/packageData/selectionView/SelectionView'; import TreeView from '../features/packageData/treeView/TreeView'; -import {useAppDispatch, useAppSelector} from './hooks'; +import { useAppDispatch, useAppSelector } from './hooks'; import PythonFunction from '../features/packageData/model/PythonFunction'; import AttributeForm from '../features/annotations/forms/AttributeForm'; -import { - UsageCountJson, - UsageCountStore -} from "../features/usages/model/UsageCountStore"; -import {selectShowUsageImportDialog} from "../features/usages/usageSlice"; +import { UsageCountJson, UsageCountStore } from '../features/usages/model/UsageCountStore'; +import { selectShowUsageImportDialog } from '../features/usages/usageSlice'; import UsageImportDialog from '../features/usages/UsageImportDialog'; const App: React.FC = function () { @@ -63,9 +55,7 @@ const App: React.FC = function () { const currentPathName = useLocation().pathname; // Initialize package data - const [pythonPackage, setPythonPackage] = useState( - new PythonPackage('empty', 'empty', '0.0.1'), - ); + const [pythonPackage, setPythonPackage] = useState(new PythonPackage('empty', 'empty', '0.0.1')); useEffect(() => { // noinspection JSIgnoredPromiseFromCall @@ -73,14 +63,12 @@ const App: React.FC = function () { }, []); // Initialize usages - const [usages, setUsages] = useState( - new UsageCountStore() - ) + const [usages, setUsages] = useState(new UsageCountStore()); useEffect(() => { // noinspection JSIgnoredPromiseFromCall - getUsagesFromIndexedDB(setUsages) - }) + getUsagesFromIndexedDB(setUsages); + }); // Initialize annotations const annotationStore = useAppSelector(selectAnnotations); @@ -108,19 +96,11 @@ const App: React.FC = function () { const pythonFilter = PythonFilter.fromFilterBoxInput(filter); const filteredPythonPackage = pythonPackage.filter(pythonFilter); - const userActionTarget = pythonPackage.getByRelativePathAsString( - currentUserAction.target, - ); + const userActionTarget = pythonPackage.getByRelativePathAsString(currentUserAction.target); - const showAnnotationImportDialog = useAppSelector( - selectShowAnnotationImportDialog, - ); - const showPackageDataImportDialog = useAppSelector( - selectShowPackageDataImportDialog, - ); - const showUsagesImportDialog = useAppSelector( - selectShowUsageImportDialog, - ); + const showAnnotationImportDialog = useAppSelector(selectShowAnnotationImportDialog); + const showPackageDataImportDialog = useAppSelector(selectShowPackageDataImportDialog); + const showUsagesImportDialog = useAppSelector(selectShowUsageImportDialog); const [showInferErrorDialog, setShowInferErrorDialog] = useState(false); const [inferErrors, setInferErrors] = useState([]); @@ -157,55 +137,34 @@ const App: React.FC = function () { resize="horizontal" > {currentUserAction.type === 'attribute' && ( - + )} {currentUserAction.type === 'boundary' && ( - + )} - {currentUserAction.type === 'calledAfter' && - userActionTarget instanceof PythonFunction && ( - - )} - {currentUserAction.type === 'constant' && ( - + {currentUserAction.type === 'calledAfter' && userActionTarget instanceof PythonFunction && ( + )} - {currentUserAction.type === 'enum' && ( - + {currentUserAction.type === 'constant' && ( + )} + {currentUserAction.type === 'enum' && } {currentUserAction.type === 'group' && ( )} - {currentUserAction.type === 'move' && ( - - )} - {currentUserAction.type === 'none' && ( - - )} + {currentUserAction.type === 'move' && } + {currentUserAction.type === 'none' && } {currentUserAction.type === 'optional' && ( - - )} - {currentUserAction.type === 'rename' && ( - + )} + {currentUserAction.type === 'rename' && } @@ -213,16 +172,9 @@ const App: React.FC = function () { {showAnnotationImportDialog && } {showPackageDataImportDialog && ( - - )} - {showUsagesImportDialog && ( - + )} + {showUsagesImportDialog && } , -) { +const getPythonPackageFromIndexedDB = async function (setPythonPackage: Setter) { const storedPackage = (await idb.get('package')) as PythonPackageJson; if (storedPackage) { setPythonPackage(parsePythonPackageJson(storedPackage)); } }; -const getUsagesFromIndexedDB = async function ( - setUsages: Setter, -) { +const getUsagesFromIndexedDB = async function (setUsages: Setter) { const storedUsages = (await idb.get('usages')) as UsageCountJson; if (storedUsages) { setUsages(UsageCountStore.fromJson(storedUsages)); } }; -const setAnnotationsInIndexedDB = async function ( - annotationStore: AnnotationsState, -) { +const setAnnotationsInIndexedDB = async function (annotationStore: AnnotationsState) { await idb.set('annotations', annotationStore); }; diff --git a/api-editor/gui/src/app/store.ts b/api-editor/gui/src/app/store.ts index 28e6cf315..90261a44a 100644 --- a/api-editor/gui/src/app/store.ts +++ b/api-editor/gui/src/app/store.ts @@ -8,7 +8,7 @@ export const store = configureStore({ reducer: { annotations: annotationReducer, packageData: packageDataReducer, - usages: usageReducer + usages: usageReducer, }, }); diff --git a/api-editor/gui/src/common/MenuBar.tsx b/api-editor/gui/src/common/MenuBar.tsx index 836267d9d..04b76b608 100644 --- a/api-editor/gui/src/common/MenuBar.tsx +++ b/api-editor/gui/src/common/MenuBar.tsx @@ -39,10 +39,7 @@ import { FaCheck, FaChevronDown } from 'react-icons/fa'; import { useLocation } from 'react-router'; import { NavLink } from 'react-router-dom'; import { useAppDispatch, useAppSelector } from '../app/hooks'; -import { - resetAnnotations, - toggleAnnotationImportDialog, -} from '../features/annotations/annotationSlice'; +import { resetAnnotations, toggleAnnotationImportDialog } from '../features/annotations/annotationSlice'; import AnnotatedPythonPackageBuilder from '../features/annotatedPackageData/model/AnnotatedPythonPackageBuilder'; import { PythonFilter } from '../features/packageData/model/PythonFilter'; import PythonPackage from '../features/packageData/model/PythonPackage'; @@ -52,7 +49,7 @@ import { toggleShowPrivateDeclarations, } from '../features/packageData/packageDataSlice'; import { Setter } from './util/types'; -import {toggleUsageImportDialog} from "../features/usages/usageSlice"; +import { toggleUsageImportDialog } from '../features/usages/usageSlice'; interface MenuBarProps { pythonPackage: PythonPackage; @@ -78,15 +75,9 @@ const DeleteAllAnnotations = function () { return ( <> - + - + @@ -95,14 +86,10 @@ const DeleteAllAnnotations = function () { + Are you sure? You can't undo this action afterwards. - Are you sure? You can't undo this action - afterwards. - - - Hint: Consider exporting your work first by - clicking on the "Export" button in the menu - bar. + Hint: Consider exporting your work first by clicking on the "Export" button in the + menu bar. @@ -111,11 +98,7 @@ const DeleteAllAnnotations = function () { - @@ -126,12 +109,7 @@ const DeleteAllAnnotations = function () { ); }; -const MenuBar: React.FC = function ({ - pythonPackage, - filter, - setFilter, - displayInferErrors, -}) { +const MenuBar: React.FC = function ({ pythonPackage, filter, setFilter, displayInferErrors }) { const { colorMode, toggleColorMode } = useColorMode(); const initialFocusRef = useRef(null); const dispatch = useAppDispatch(); @@ -139,9 +117,7 @@ const MenuBar: React.FC = function ({ const pathname = useLocation().pathname.split('/').slice(1); const annotationStore = useAppSelector((state) => state.annotations); - const enableNavigation = useAppSelector( - (state) => state.annotations.currentUserAction.type === 'none', - ); + const enableNavigation = useAppSelector((state) => state.annotations.currentUserAction.type === 'none'); const exportAnnotations = () => { const a = document.createElement('a'); @@ -154,12 +130,8 @@ const MenuBar: React.FC = function ({ }; const infer = () => { - const annotatedPythonPackageBuilder = new AnnotatedPythonPackageBuilder( - pythonPackage, - annotationStore, - ); - const annotatedPythonPackage = - annotatedPythonPackageBuilder.generateAnnotatedPythonPackage(); + const annotatedPythonPackageBuilder = new AnnotatedPythonPackageBuilder(pythonPackage, annotationStore); + const annotatedPythonPackage = annotatedPythonPackageBuilder.generateAnnotatedPythonPackage(); const requestOptions = { method: 'POST', @@ -181,22 +153,12 @@ const MenuBar: React.FC = function ({ }; return ( - +
@@ -205,18 +167,11 @@ const MenuBar: React.FC = function ({ // eslint-disable-next-line react/no-array-index-key {enableNavigation && ( - + {part} )} - {!enableNavigation && ( - {part} - )} + {!enableNavigation && {part}} ))} @@ -230,78 +185,42 @@ const MenuBar: React.FC = function ({ {/* Box gets rid of popper.js warning "CSS margin styles cannot be used" */} - } - > + }> Import - - dispatch(togglePackageDataImportDialog()) - } - > - API Data - - - dispatch(toggleUsageImportDialog()) - } - > - Usages - - - dispatch(toggleAnnotationImportDialog()) - } - > - Annotations - + dispatch(togglePackageDataImportDialog())}>API Data + dispatch(toggleUsageImportDialog())}>Usages + dispatch(toggleAnnotationImportDialog())}>Annotations - - + - + - setFilter(event.target.value) - } - isInvalid={ - !PythonFilter.fromFilterBoxInput(filter) - } + onChange={(event) => setFilter(event.target.value)} + isInvalid={!PythonFilter.fromFilterBoxInput(filter)} borderColor={ - PythonFilter.fromFilterBoxInput( - filter, - )?.isFilteringModules() + PythonFilter.fromFilterBoxInput(filter)?.isFilteringModules() ? 'green' : 'inherit' } spellCheck={false} /> - {PythonFilter.fromFilterBoxInput( - filter, - )?.isFilteringModules() && ( + {PythonFilter.fromFilterBoxInput(filter)?.isFilteringModules() && ( @@ -310,9 +229,7 @@ const MenuBar: React.FC = function ({ - - Each scope must only be used once. - + Each scope must only be used once. diff --git a/api-editor/gui/src/features/usages/UsageImportDialog.tsx b/api-editor/gui/src/features/usages/UsageImportDialog.tsx index f4f4adc6c..ea1723bbd 100644 --- a/api-editor/gui/src/features/usages/UsageImportDialog.tsx +++ b/api-editor/gui/src/features/usages/UsageImportDialog.tsx @@ -14,100 +14,90 @@ import { Text as ChakraText, } from '@chakra-ui/react'; import * as idb from 'idb-keyval'; -import React, {useState} from 'react'; -import {useAppDispatch} from '../../app/hooks'; +import React, { useState } from 'react'; +import { useAppDispatch } from '../../app/hooks'; import StyledDropzone from '../../common/StyledDropzone'; -import {Setter} from '../../common/util/types'; -import {isValidJsonFile} from '../../common/util/validation'; -import {resetAnnotations} from '../annotations/annotationSlice'; -import {UsageCountJson, UsageCountStore} from './model/UsageCountStore'; +import { Setter } from '../../common/util/types'; +import { isValidJsonFile } from '../../common/util/validation'; +import { resetAnnotations } from '../annotations/annotationSlice'; +import { UsageCountJson, UsageCountStore } from './model/UsageCountStore'; -import {toggleUsageImportDialog} from './usageSlice'; +import { toggleUsageImportDialog } from './usageSlice'; interface ImportPythonPackageDialogProps { setUsages: Setter; } -const UsageImportDialog: React.FC = - function ({ setUsages }) { - const [fileName, setFileName] = useState(''); - const [newUsages, setNewUsages] = useState(); - const dispatch = useAppDispatch(); +const UsageImportDialog: React.FC = function ({ setUsages }) { + const [fileName, setFileName] = useState(''); + const [newUsages, setNewUsages] = useState(); + const dispatch = useAppDispatch(); - const submit = async () => { - if (newUsages) { - const parsedUsages = JSON.parse( - newUsages, - ) as UsageCountJson; - setUsages(UsageCountStore.fromJson(parsedUsages)); + const submit = async () => { + if (newUsages) { + const parsedUsages = JSON.parse(newUsages) as UsageCountJson; + setUsages(UsageCountStore.fromJson(parsedUsages)); - await idb.set('usages', parsedUsages); - } - close(); - }; - const close = () => dispatch(toggleUsageImportDialog()); + await idb.set('usages', parsedUsages); + } + close(); + }; + const close = () => dispatch(toggleUsageImportDialog()); - const slurpAndParse = (acceptedFiles: File[]) => { - if (isValidJsonFile(acceptedFiles[acceptedFiles.length - 1].name)) { - if (acceptedFiles.length > 1) { - // eslint-disable-next-line no-param-reassign - acceptedFiles = [acceptedFiles[acceptedFiles.length - 1]]; - } - setFileName(acceptedFiles[0].name); - const reader = new FileReader(); - reader.onload = () => { - if (typeof reader.result === 'string') { - setNewUsages(reader.result); - dispatch(resetAnnotations()); - } - }; - reader.readAsText(acceptedFiles[0]); + const slurpAndParse = (acceptedFiles: File[]) => { + if (isValidJsonFile(acceptedFiles[acceptedFiles.length - 1].name)) { + if (acceptedFiles.length > 1) { + // eslint-disable-next-line no-param-reassign + acceptedFiles = [acceptedFiles[acceptedFiles.length - 1]]; } - }; + setFileName(acceptedFiles[0].name); + const reader = new FileReader(); + reader.onload = () => { + if (typeof reader.result === 'string') { + setNewUsages(reader.result); + dispatch(resetAnnotations()); + } + }; + reader.readAsText(acceptedFiles[0]); + } + }; - return ( - - - - - Import usages - - - - - Select a usage file to import. - - - - Drag and drop a usage file here or click - to select the file. - - - (Only *.json will be accepted.) - - + return ( + + + + + Import usages + + + + Select a usage file to import. + + Drag and drop a usage file here or click to select the file. + (Only *.json will be accepted.) + - {fileName && ( - - Imported file: - {fileName} - - )} - - - - - - - - - - - ); - }; + {fileName && ( + + Imported file: + {fileName} + + )} + + + + + + + + + + + ); +}; export default UsageImportDialog; diff --git a/api-editor/gui/src/features/usages/model/UsageCountStore.ts b/api-editor/gui/src/features/usages/model/UsageCountStore.ts index 2d4e519d7..ad2ac37d8 100644 --- a/api-editor/gui/src/features/usages/model/UsageCountStore.ts +++ b/api-editor/gui/src/features/usages/model/UsageCountStore.ts @@ -1,18 +1,18 @@ export interface UsageCountJson { class_counts: { - [target: string]: number - }, + [target: string]: number; + }; function_counts: { - [target: string]: number - }, + [target: string]: number; + }; parameter_counts: { - [target: string]: number - }, + [target: string]: number; + }; value_counts: { [target: string]: { - [stringifiedValue: string]: number - } - } + [stringifiedValue: string]: number; + }; + }; } export class UsageCountStore { @@ -21,19 +21,16 @@ export class UsageCountStore { new Map(Object.entries(json.class_counts)), new Map(Object.entries(json.function_counts)), new Map(Object.entries(json.parameter_counts)), - new Map(Object.entries(json.value_counts).map((entry) => - [entry[0], new Map(Object.entries(entry[1]))] - )) - ) + new Map(Object.entries(json.value_counts).map((entry) => [entry[0], new Map(Object.entries(entry[1]))])), + ); } constructor( readonly classUsages: Map = new Map(), readonly functionUsages: Map = new Map(), readonly parameterUsages: Map = new Map(), - readonly valueUsages: Map> = new Map() - ) { - } + readonly valueUsages: Map> = new Map(), + ) {} toJson(): UsageCountJson { return { @@ -41,10 +38,8 @@ export class UsageCountStore { function_counts: Object.fromEntries(this.functionUsages), parameter_counts: Object.fromEntries(this.parameterUsages), value_counts: Object.fromEntries( - [...this.valueUsages.entries()].map((entry) => - [entry[0], Object.fromEntries(entry[1])] - ) - ) - } + [...this.valueUsages.entries()].map((entry) => [entry[0], Object.fromEntries(entry[1])]), + ), + }; } } diff --git a/api-editor/gui/src/features/usages/usageSlice.ts b/api-editor/gui/src/features/usages/usageSlice.ts index 5088144f6..2ac067df6 100644 --- a/api-editor/gui/src/features/usages/usageSlice.ts +++ b/api-editor/gui/src/features/usages/usageSlice.ts @@ -1,5 +1,5 @@ -import {createSlice} from '@reduxjs/toolkit'; -import {RootState} from '../../app/store'; +import { createSlice } from '@reduxjs/toolkit'; +import { RootState } from '../../app/store'; export interface UsageState { showImportDialog: boolean; @@ -24,11 +24,8 @@ const usageSlice = createSlice({ }); const { actions, reducer } = usageSlice; -export const { - toggleImportDialog: toggleUsageImportDialog, -} = actions; +export const { toggleImportDialog: toggleUsageImportDialog } = actions; export default reducer; const selectUsage = (state: RootState) => state.usages; -export const selectShowUsageImportDialog = (state: RootState): boolean => - selectUsage(state).showImportDialog; +export const selectShowUsageImportDialog = (state: RootState): boolean => selectUsage(state).showImportDialog;