Merged PR 164: Clear the leftover TODOs
All checks were successful
continuous-integration/drone/push Build is passing

- 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
This commit is contained in:
Eric Nguyen 2022-08-22 15:03:46 +00:00
parent 66ea3b1b64
commit 29625dce28
6 changed files with 81 additions and 48 deletions

View file

@ -1,10 +1,9 @@
import { Dispatch, SetStateAction } from 'react'; import { Dispatch, SetStateAction } from 'react';
import { IConfiguration } from '../../../Interfaces/IConfiguration'; import { IConfiguration } from '../../../Interfaces/IConfiguration';
import { ContainerModel } from '../../../Interfaces/IContainerModel';
import { fetchConfiguration } from '../../API/api'; import { fetchConfiguration } from '../../API/api';
import { IEditorState } from '../../../Interfaces/IEditorState'; import { IEditorState } from '../../../Interfaces/IEditorState';
import { LoadState } from './Load'; import { LoadState } from './Load';
import { DEFAULT_MAINCONTAINER_PROPS } from '../../../utils/default'; import { GetDefaultEditorState } from '../../../utils/default';
export function NewEditor( export function NewEditor(
setEditorState: Dispatch<SetStateAction<IEditorState>>, setEditorState: Dispatch<SetStateAction<IEditorState>>,
@ -13,38 +12,12 @@ export function NewEditor(
// Fetch the configuration from the API // Fetch the configuration from the API
fetchConfiguration() fetchConfiguration()
.then((configuration: IConfiguration) => { .then((configuration: IConfiguration) => {
// Set the main container from the given properties of the API // Set the editor from the given properties of the API
const MainContainer = new ContainerModel( const editorState: IEditorState = GetDefaultEditorState(configuration);
null,
{
...DEFAULT_MAINCONTAINER_PROPS,
width: Number(configuration.MainContainer.Width),
height: Number(configuration.MainContainer.Height)
}
);
// 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); setEditorState(editorState);
setLoaded(true); setLoaded(true);
}, (error) => { }, (error) => {
// TODO: Implement an alert component
console.warn('[NewEditor] Could not fetch resource from API. Using default.', error); console.warn('[NewEditor] Could not fetch resource from API. Using default.', error);
setLoaded(true); setLoaded(true);
}); });

View file

@ -9,6 +9,7 @@ import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer';
import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../../utils/default'; import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../../utils/default';
import { ApplyBehaviors } from '../Behaviors/Behaviors'; import { ApplyBehaviors } from '../Behaviors/Behaviors';
import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
import Swal from 'sweetalert2';
/** /**
* Select a container * Select a container
@ -64,7 +65,11 @@ export function DeleteContainer(
if (container === mainContainerClone || if (container === mainContainerClone ||
container.parent === undefined || container.parent === undefined ||
container.parent === null) { 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!'); throw new Error('[DeleteContainer] Tried to delete the main container! Deleting the main container is not allowed!');
} }

View file

@ -3,7 +3,7 @@ import { IConfiguration } from '../../../Interfaces/IConfiguration';
import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { IContainerModel } from '../../../Interfaces/IContainerModel';
import { IHistoryState } from '../../../Interfaces/IHistoryState'; import { IHistoryState } from '../../../Interfaces/IHistoryState';
import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; 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 { findContainerById } from '../../../utils/itertools';
import { restoreX } from '../../../utils/svg'; import { restoreX } from '../../../utils/svg';
import { ApplyBehaviors } from '../Behaviors/Behaviors'; import { ApplyBehaviors } from '../Behaviors/Behaviors';
@ -31,16 +31,7 @@ export function AddSymbol(
UpdateCounters(newCounters, type); UpdateCounters(newCounters, type);
const newSymbols = structuredClone(current.Symbols); const newSymbols = structuredClone(current.Symbols);
// TODO: Put this in default.ts as GetDefaultConfig const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, newCounters, type, symbolConfig);
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()
};
newSymbol.x = restoreX(newSymbol.x, newSymbol.width, newSymbol.config.XPositionReference); newSymbol.x = restoreX(newSymbol.x, newSymbol.width, newSymbol.config.XPositionReference);
newSymbols.set(newSymbol.id, newSymbol); newSymbols.set(newSymbol.id, newSymbol);
@ -114,7 +105,7 @@ export function DeleteSymbol(
setHistoryCurrentStep(history.length - 1); setHistoryCurrentStep(history.length - 1);
} }
function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel) { function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel): void {
symbol.linkedContainers.forEach((containerId) => { symbol.linkedContainers.forEach((containerId) => {
const container = findContainerById(newMainContainer, containerId); const container = findContainerById(newMainContainer, containerId);

View file

@ -15,7 +15,7 @@ describe.concurrent('Elements sidebar', () => {
parent: null, parent: null,
properties: { properties: {
id: 'main', id: 'main',
parentId: null, parentId: '',
linkedSymbolId: '', linkedSymbolId: '',
displayedText: 'main', displayedText: 'main',
x: 0, x: 0,

View file

@ -8,9 +8,8 @@ export default interface IContainerProperties {
/** id of the container */ /** id of the container */
id: string id: string
// TODO: replace null by empty string
/** id of the parent container (null when there is no parent) */ /** 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) */ /** id of the linked symbol ('' when there is no parent) */
linkedSymbolId: string linkedSymbolId: string

View file

@ -1,8 +1,11 @@
import { XPositionReference } from '../Enums/XPositionReference'; import { XPositionReference } from '../Enums/XPositionReference';
import { IAvailableContainer } from '../Interfaces/IAvailableContainer'; import { IAvailableContainer } from '../Interfaces/IAvailableContainer';
import { IAvailableSymbol } from '../Interfaces/IAvailableSymbol';
import { IConfiguration } from '../Interfaces/IConfiguration'; import { IConfiguration } from '../Interfaces/IConfiguration';
import { IContainerModel } from '../Interfaces/IContainerModel'; import { ContainerModel, IContainerModel } from '../Interfaces/IContainerModel';
import IContainerProperties from '../Interfaces/IContainerProperties'; import IContainerProperties from '../Interfaces/IContainerProperties';
import { IEditorState } from '../Interfaces/IEditorState';
import { ISymbolModel } from '../Interfaces/ISymbolModel';
/// CONTAINER DEFAULTS /// /// CONTAINER DEFAULTS ///
@ -29,6 +32,38 @@ export const ENABLE_SHORTCUTS = true;
export const MAX_HISTORY = 200; export const MAX_HISTORY = 200;
export const APPLY_BEHAVIORS_ON_CHILDREN = true; 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 = { export const DEFAULT_CONFIG: IConfiguration = {
AvailableContainers: [ AvailableContainers: [
{ {
@ -53,9 +88,12 @@ export const DEFAULT_CONFIG: IConfiguration = {
} }
}; };
/**
* Default Main container properties
*/
export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = { export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = {
id: 'main', id: 'main',
parentId: 'null', parentId: '',
linkedSymbolId: '', linkedSymbolId: '',
displayedText: 'main', displayedText: 'main',
x: 0, 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 = ( export const GetDefaultContainerProps = (
type: string, type: string,
typeCount: number, typeCount: number,
@ -96,3 +144,20 @@ export const GetDefaultContainerProps = (
style: structuredClone(containerConfig.Style), style: structuredClone(containerConfig.Style),
userData: structuredClone(containerConfig.UserData) userData: structuredClone(containerConfig.UserData)
}); });
export const GetDefaultSymbolModel = (
name: string,
newCounters: Record<string, number>,
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()
};
};