From 29625dce282764eaef7a9a4c84e12467340e2b6b Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Mon, 22 Aug 2022 15:03:46 +0000 Subject: [PATCH] Merged PR 164: Clear the leftover TODOs - Remove nullable type from container.properties.parentId - Add Swal when trying to delete main container - Moved default editor state to default.ts - Moved default symbol model to default.ts --- src/Components/App/Actions/MenuActions.ts | 33 +-------- .../Editor/Actions/ContainerOperations.ts | 7 +- .../Editor/Actions/SymbolOperations.ts | 15 +--- .../ElementsSidebar/ElementsSidebar.test.tsx | 2 +- src/Interfaces/IContainerProperties.ts | 3 +- src/utils/default.ts | 69 ++++++++++++++++++- 6 files changed, 81 insertions(+), 48 deletions(-) diff --git a/src/Components/App/Actions/MenuActions.ts b/src/Components/App/Actions/MenuActions.ts index 46bb2e1..4698e29 100644 --- a/src/Components/App/Actions/MenuActions.ts +++ b/src/Components/App/Actions/MenuActions.ts @@ -1,10 +1,9 @@ import { Dispatch, SetStateAction } from 'react'; import { IConfiguration } from '../../../Interfaces/IConfiguration'; -import { ContainerModel } from '../../../Interfaces/IContainerModel'; import { fetchConfiguration } from '../../API/api'; import { IEditorState } from '../../../Interfaces/IEditorState'; import { LoadState } from './Load'; -import { DEFAULT_MAINCONTAINER_PROPS } from '../../../utils/default'; +import { GetDefaultEditorState } from '../../../utils/default'; export function NewEditor( setEditorState: Dispatch>, @@ -13,38 +12,12 @@ export function NewEditor( // Fetch the configuration from the API fetchConfiguration() .then((configuration: IConfiguration) => { - // Set the main container from the given properties of the API - const MainContainer = new ContainerModel( - null, - { - ...DEFAULT_MAINCONTAINER_PROPS, - width: Number(configuration.MainContainer.Width), - height: Number(configuration.MainContainer.Height) - } - ); + // Set the editor from the given properties of the API + const editorState: IEditorState = GetDefaultEditorState(configuration); - // Save the configuration and the new MainContainer - // and default the selected container to it - // TODO: Put this in default.ts - const editorState: IEditorState = { - configuration, - history: - [ - { - LastAction: '', - MainContainer, - SelectedContainerId: MainContainer.properties.id, - TypeCounters: {}, - Symbols: new Map(), - SelectedSymbolId: '' - } - ], - historyCurrentStep: 0 - }; setEditorState(editorState); setLoaded(true); }, (error) => { - // TODO: Implement an alert component console.warn('[NewEditor] Could not fetch resource from API. Using default.', error); setLoaded(true); }); diff --git a/src/Components/Editor/Actions/ContainerOperations.ts b/src/Components/Editor/Actions/ContainerOperations.ts index 691a12d..a98fe53 100644 --- a/src/Components/Editor/Actions/ContainerOperations.ts +++ b/src/Components/Editor/Actions/ContainerOperations.ts @@ -9,6 +9,7 @@ import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer'; import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../../utils/default'; import { ApplyBehaviors } from '../Behaviors/Behaviors'; import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; +import Swal from 'sweetalert2'; /** * Select a container @@ -64,7 +65,11 @@ export function DeleteContainer( if (container === mainContainerClone || container.parent === undefined || container.parent === null) { - // TODO: Implement alert + Swal.fire({ + title: 'Oops...', + text: 'Deleting the main container is not allowed!', + icon: 'error' + }); throw new Error('[DeleteContainer] Tried to delete the main container! Deleting the main container is not allowed!'); } diff --git a/src/Components/Editor/Actions/SymbolOperations.ts b/src/Components/Editor/Actions/SymbolOperations.ts index aeb6119..aef67e0 100644 --- a/src/Components/Editor/Actions/SymbolOperations.ts +++ b/src/Components/Editor/Actions/SymbolOperations.ts @@ -3,7 +3,7 @@ import { IConfiguration } from '../../../Interfaces/IConfiguration'; import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { IHistoryState } from '../../../Interfaces/IHistoryState'; import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; -import { DEFAULT_SYMBOL_HEIGHT, DEFAULT_SYMBOL_WIDTH } from '../../../utils/default'; +import { GetDefaultSymbolModel } from '../../../utils/default'; import { findContainerById } from '../../../utils/itertools'; import { restoreX } from '../../../utils/svg'; import { ApplyBehaviors } from '../Behaviors/Behaviors'; @@ -31,16 +31,7 @@ export function AddSymbol( UpdateCounters(newCounters, type); const newSymbols = structuredClone(current.Symbols); - // TODO: Put this in default.ts as GetDefaultConfig - const newSymbol: ISymbolModel = { - id: `${name}-${newCounters[type]}`, - type: name, - config: structuredClone(symbolConfig), - x: 0, - width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH, - height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT, - linkedContainers: new Set() - }; + const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, newCounters, type, symbolConfig); newSymbol.x = restoreX(newSymbol.x, newSymbol.width, newSymbol.config.XPositionReference); newSymbols.set(newSymbol.id, newSymbol); @@ -114,7 +105,7 @@ export function DeleteSymbol( setHistoryCurrentStep(history.length - 1); } -function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel) { +function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel): void { symbol.linkedContainers.forEach((containerId) => { const container = findContainerById(newMainContainer, containerId); diff --git a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx index c7d19b2..e6bcde6 100644 --- a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx +++ b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx @@ -15,7 +15,7 @@ describe.concurrent('Elements sidebar', () => { parent: null, properties: { id: 'main', - parentId: null, + parentId: '', linkedSymbolId: '', displayedText: 'main', x: 0, diff --git a/src/Interfaces/IContainerProperties.ts b/src/Interfaces/IContainerProperties.ts index d5f7ae7..1166bad 100644 --- a/src/Interfaces/IContainerProperties.ts +++ b/src/Interfaces/IContainerProperties.ts @@ -8,9 +8,8 @@ export default interface IContainerProperties { /** id of the container */ id: string - // TODO: replace null by empty string /** id of the parent container (null when there is no parent) */ - parentId: string | null + parentId: string /** id of the linked symbol ('' when there is no parent) */ linkedSymbolId: string diff --git a/src/utils/default.ts b/src/utils/default.ts index f30323f..a15bd36 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -1,8 +1,11 @@ import { XPositionReference } from '../Enums/XPositionReference'; import { IAvailableContainer } from '../Interfaces/IAvailableContainer'; +import { IAvailableSymbol } from '../Interfaces/IAvailableSymbol'; import { IConfiguration } from '../Interfaces/IConfiguration'; -import { IContainerModel } from '../Interfaces/IContainerModel'; +import { ContainerModel, IContainerModel } from '../Interfaces/IContainerModel'; import IContainerProperties from '../Interfaces/IContainerProperties'; +import { IEditorState } from '../Interfaces/IEditorState'; +import { ISymbolModel } from '../Interfaces/ISymbolModel'; /// CONTAINER DEFAULTS /// @@ -29,6 +32,38 @@ export const ENABLE_SHORTCUTS = true; export const MAX_HISTORY = 200; export const APPLY_BEHAVIORS_ON_CHILDREN = true; +/** + * Returns the default editor state given the configuration + */ +export const GetDefaultEditorState = (configuration: IConfiguration): IEditorState => { + const mainContainer = new ContainerModel( + null, + { + ...DEFAULT_MAINCONTAINER_PROPS, + width: Number(configuration.MainContainer.Width), + height: Number(configuration.MainContainer.Height) + } + ); + + return { + configuration, + history: [ + { + LastAction: '', + MainContainer: mainContainer, + SelectedContainerId: mainContainer.properties.id, + TypeCounters: {}, + Symbols: new Map(), + SelectedSymbolId: '' + } + ], + historyCurrentStep: 0 + }; +}; + +/** + * Default config when the API is not available + */ export const DEFAULT_CONFIG: IConfiguration = { AvailableContainers: [ { @@ -53,9 +88,12 @@ export const DEFAULT_CONFIG: IConfiguration = { } }; +/** + * Default Main container properties + */ export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = { id: 'main', - parentId: 'null', + parentId: '', linkedSymbolId: '', displayedText: 'main', x: 0, @@ -72,6 +110,16 @@ export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = { } }; +/** + * Returns the default properties of a newly created container + * @param type Type of the container + * @param typeCount index of the container + * @param parent Parent of the container + * @param x horizontal offset + * @param y vertical offset + * @param containerConfig default config of the container sent by the API + * @returns {IContainerProperties} Default properties of a newly created container + */ export const GetDefaultContainerProps = ( type: string, typeCount: number, @@ -96,3 +144,20 @@ export const GetDefaultContainerProps = ( style: structuredClone(containerConfig.Style), userData: structuredClone(containerConfig.UserData) }); + +export const GetDefaultSymbolModel = ( + name: string, + newCounters: Record, + type: string, + symbolConfig: IAvailableSymbol +): ISymbolModel => { + return { + id: `${name}-${newCounters[type]}`, + type: name, + config: structuredClone(symbolConfig), + x: 0, + width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH, + height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT, + linkedContainers: new Set() + }; +};