Implement history
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Siklos 2022-08-04 10:23:48 +02:00
parent 767afb230d
commit fab40f5cf7

View file

@ -10,13 +10,18 @@ import { SVG } from './Components/SVG/SVG';
interface IAppProps { interface IAppProps {
} }
export interface IHistoryState {
MainContainer: Container | null,
SelectedContainer: Container | null,
TypeCounters: Record<string, number>
}
interface IAppState { interface IAppState {
isSidebarOpen: boolean, isSidebarOpen: boolean,
isSVGSidebarOpen: boolean, isSVGSidebarOpen: boolean,
configuration: Configuration, configuration: Configuration,
MainContainer: Container | null, history: Array<IHistoryState>,
SelectedContainer: Container | null historyCurrentStep: 0
Counters: Record<string, number>
} }
class App extends React.Component<IAppProps> { class App extends React.Component<IAppProps> {
@ -32,12 +37,20 @@ class App extends React.Component<IAppProps> {
AvailableSymbols: [], AvailableSymbols: [],
MainContainer: {} as AvailableContainer MainContainer: {} as AvailableContainer
}, },
MainContainer: null, history: [
SelectedContainer: null, {
Counters: {} MainContainer: null,
}; SelectedContainer: null,
TypeCounters: {}
}
],
historyCurrentStep: 0
} as IAppState;
} }
public getCurrentHistory = (): IHistoryState[] => this.state.history.slice(0, this.state.historyCurrentStep + 1);
public getCurrentHistoryState = (): IHistoryState => this.state.history[this.state.historyCurrentStep];
componentDidMount() { componentDidMount() {
// Fetch the configuration from the API // Fetch the configuration from the API
fetchConfiguration().then((configuration: Configuration) => { fetchConfiguration().then((configuration: Configuration) => {
@ -58,14 +71,25 @@ class App extends React.Component<IAppProps> {
} }
); );
const history = this.getCurrentHistory();
const current = history[history.length - 1];
// Save the configuration and the new MainContainer // Save the configuration and the new MainContainer
// and default the selected container to it // and default the selected container to it
this.setState(prevState => ({ this.setState(prevState => ({
...prevState, ...prevState,
configuration, configuration,
MainContainer, history: history.concat(
SelectedContainer: MainContainer [
})); {
MainContainer,
SelectedContainer: MainContainer,
TypeCounters: current.TypeCounters
}
]
),
historyCurrentStep: history.length
} as IAppState));
}); });
} }
@ -92,9 +116,16 @@ class App extends React.Component<IAppProps> {
* @param container Selected container * @param container Selected container
*/ */
public SelectContainer(container: Container) { public SelectContainer(container: Container) {
const history = this.getCurrentHistory();
const current = history[history.length - 1];
this.setState({ this.setState({
SelectedContainer: container history: history.concat([{
} as IAppProps); MainContainer: current.MainContainer,
TypeCounters: current.TypeCounters,
SelectedContainer: container
}]),
historyCurrentStep: history.length
} as IAppState);
} }
/** /**
@ -104,43 +135,55 @@ class App extends React.Component<IAppProps> {
* @returns void * @returns void
*/ */
public OnPropertyChange(key: string, value: string | number): void { public OnPropertyChange(key: string, value: string | number): void {
if (this.state.SelectedContainer === null || const history = this.getCurrentHistory();
this.state.SelectedContainer === undefined) { const current = history[history.length - 1];
if (current.SelectedContainer === null ||
current.SelectedContainer === undefined) {
throw new Error('Property was changed before selecting a Container'); throw new Error('Property was changed before selecting a Container');
} }
if (this.state.MainContainer === null || if (current.MainContainer === null ||
this.state.MainContainer === undefined) { current.MainContainer === undefined) {
throw new Error('Property was changed before the main container was added'); throw new Error('Property was changed before the main container was added');
} }
const pair = {} as Record<string, string | number>; const pair = {} as Record<string, string | number>;
pair[key] = value; pair[key] = value;
const properties = Object.assign(this.state.SelectedContainer.props.properties, pair); const properties = Object.assign(current.SelectedContainer.props.properties, pair);
const props = { const props = {
...this.state.SelectedContainer.props, ...current.SelectedContainer.props,
properties properties
}; };
const newSelectedContainer = new Container(props); const newSelectedContainer = new Container(props);
const parent = this.state.SelectedContainer.props.parent; const parent = current.SelectedContainer.props.parent;
if (parent === null) { if (parent === null) {
this.setState({ this.setState({
SelectedContainer: newSelectedContainer, history: history.concat([{
MainContainer: newSelectedContainer SelectedContainer: newSelectedContainer,
}); MainContainer: newSelectedContainer,
TypeCounters: current.TypeCounters
}]),
historyCurrentStep: history.length
} as IAppState);
return; return;
} }
const index = parent.props.children.indexOf(this.state.SelectedContainer); const index = parent.props.children.indexOf(current.SelectedContainer);
parent.props.children[index] = newSelectedContainer; parent.props.children[index] = newSelectedContainer;
const newMainContainer = new Container(Object.assign({}, this.state.MainContainer.props)); const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
this.setState({ this.setState(
SelectedContainer: newSelectedContainer, {
MainContainer: newMainContainer history: history.concat([{
}); SelectedContainer: newSelectedContainer,
MainContainer: newMainContainer,
TypeCounters: current.TypeCounters
}]),
historyCurrentStep: history.length
} as IAppState);
} }
/** /**
@ -149,13 +192,16 @@ class App extends React.Component<IAppProps> {
* @returns void * @returns void
*/ */
public AddContainer(type: string): void { public AddContainer(type: string): void {
if (this.state.SelectedContainer === null || const history = this.getCurrentHistory();
this.state.SelectedContainer === undefined) { const current = history[history.length - 1];
if (current.SelectedContainer === null ||
current.SelectedContainer === undefined) {
return; return;
} }
if (this.state.MainContainer === null || if (current.MainContainer === null ||
this.state.MainContainer === undefined) { current.MainContainer === undefined) {
return; return;
} }
@ -167,7 +213,7 @@ class App extends React.Component<IAppProps> {
} }
// Set the counter of the object type in order to assign an unique id // Set the counter of the object type in order to assign an unique id
const newCounters = Object.assign({}, this.state.Counters); const newCounters = Object.assign({}, current.TypeCounters);
if (newCounters[type] === null || if (newCounters[type] === null ||
newCounters[type] === undefined) { newCounters[type] === undefined) {
newCounters[type] = 0; newCounters[type] = 0;
@ -176,7 +222,7 @@ class App extends React.Component<IAppProps> {
} }
// Create the container // Create the container
const parent = this.state.SelectedContainer; const parent = current.SelectedContainer;
const count = newCounters[type]; const count = newCounters[type];
const container = new Container({ const container = new Container({
parent, parent,
@ -198,11 +244,15 @@ class App extends React.Component<IAppProps> {
parent.props.children.push(container); parent.props.children.push(container);
// Update the state // Update the state
const newMainContainer = new Container(Object.assign({}, this.state.MainContainer.props)); const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
this.setState({ this.setState({
MainContainer: newMainContainer, history: history.concat([{
Counters: newCounters MainContainer: newMainContainer,
}); TypeCounters: newCounters,
SelectedContainer: current.SelectedContainer
}]),
historyCurrentStep: history.length
} as IAppState);
} }
/** /**
@ -210,6 +260,7 @@ class App extends React.Component<IAppProps> {
* @returns {JSX.Element} Rendered JSX element * @returns {JSX.Element} Rendered JSX element
*/ */
render() { render() {
const current = this.getCurrentHistoryState();
return ( return (
<div className="App font-sans h-full"> <div className="App font-sans h-full">
<Sidebar <Sidebar
@ -220,16 +271,16 @@ class App extends React.Component<IAppProps> {
/> />
<button className='fixed z-10 top-4 left-4 text-lg bg-blue-200 hover:bg-blue-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleSidebar()}>&#9776; Components</button> <button className='fixed z-10 top-4 left-4 text-lg bg-blue-200 hover:bg-blue-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleSidebar()}>&#9776; Components</button>
<ElementsSidebar <ElementsSidebar
MainContainer={this.state.MainContainer} MainContainer={current.MainContainer}
SelectedContainer={this.state.SelectedContainer} SelectedContainer={current.SelectedContainer}
isOpen={this.state.isSVGSidebarOpen} isOpen={this.state.isSVGSidebarOpen}
onClick={() => this.ToggleElementsSidebar()} onClick={() => this.ToggleElementsSidebar()}
onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)} onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)}
selectContainer={(container: Container) => this.SelectContainer(container)} selectContainer={(container: Container) => this.SelectContainer(container)}
/> />
<button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleElementsSidebar()}>&#9776; Elements</button> <button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleElementsSidebar()}>&#9776; Elements</button>
<SVG selected={this.state.SelectedContainer}> <SVG selected={current.SelectedContainer}>
{ this.state.MainContainer } { current.MainContainer }
</SVG> </SVG>
</div> </div>
); );