diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts index e47603fd..82e80916 100644 --- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts +++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts @@ -52,6 +52,7 @@ export const finishLine = createAction( `${actionTypePrefix} Finish line`, props<{ voxelChanges: VoxelChange[] }>(), ); +export const cancelLine = createAction(`${actionTypePrefix} Cancel line`); export const addFirstLineChange = createAction( `${actionTypePrefix} Add first line change`, props(), diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts index fcbb9c48..fca6256d 100644 --- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts +++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts @@ -115,10 +115,8 @@ export class SceneViewerContainerEffects { }), tap(([_action, state]) => { // remove old line - state.selectedLineChanges.map(change => - change.oldValue === this.gridService.background - ? this.gridService.removeVoxel(change.xyz) - : this.gridService.setVoxel(change.xyz, change.oldValue), + state.selectedLineChanges.forEach(change => + this.gridService.setVoxel(change.xyz, change.oldValue), ); }), map(([action, state]) => { diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts index 2b13bec5..41dc9149 100644 --- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts +++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts @@ -10,6 +10,7 @@ import * as menuBarContainerActions from '../menu-bar-container/menu-bar-contain import { VoxelChange } from './grid.service'; import { addFirstLineChange, + cancelLine, finishLine, setLineChanges, startLine, @@ -48,6 +49,7 @@ export const reducer = createReducer( }, ), on( + cancelLine, finishLine, (state): State => { return { diff --git a/apps/frontend/src/app/tools-panel/tools-panel.actions.ts b/apps/frontend/src/app/tools-panel/tools-panel.actions.ts index 2fd9987a..eaa58b2c 100644 --- a/apps/frontend/src/app/tools-panel/tools-panel.actions.ts +++ b/apps/frontend/src/app/tools-panel/tools-panel.actions.ts @@ -1,4 +1,10 @@ import { createAction, props } from '@ngrx/store'; import { Tool } from '@talus/model'; -export const selectTool = createAction('[toolsPanel] Select tool', props<{ id: Tool }>()); +const actionTypePrefix = `[toolsPanel]`; + +export const selectTool = createAction(`${actionTypePrefix} Select tool`, props<{ id: Tool }>()); + +export const removeSelectionLinePreview = createAction( + `${actionTypePrefix} Remove selection line preview`, +); diff --git a/apps/frontend/src/app/tools-panel/tools-panel.component.spec.ts b/apps/frontend/src/app/tools-panel/tools-panel.component.spec.ts index 040dc23f..1ad0c2cf 100644 --- a/apps/frontend/src/app/tools-panel/tools-panel.component.spec.ts +++ b/apps/frontend/src/app/tools-panel/tools-panel.component.spec.ts @@ -1,26 +1,28 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { StoreModule } from '@ngrx/store'; -import { ROOT_REDUCERS } from '../app.reducer'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { Action } from '@ngrx/store'; +import { provideMockStore } from '@ngrx/store/testing'; +import { UiToolbarModule } from '@talus/ui'; +import { Observable, of } from 'rxjs'; +import { default as fromApp } from '../app.reducer'; +import { initialMockState } from '../testing'; import { ToolsPanelComponent } from './tools-panel.component'; -import { ToolsPanelModule } from './tools-panel.module'; describe('ToolsPanelComponent', () => { let component: ToolsPanelComponent; let fixture: ComponentFixture; + const actions$: Observable = of(); + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [], - imports: [ - ToolsPanelModule, - StoreModule.forRoot(ROOT_REDUCERS, { - runtimeChecks: { - strictStateImmutability: true, - strictActionImmutability: true, - strictStateSerializability: true, - strictActionSerializability: true, - }, + declarations: [ToolsPanelComponent], + imports: [UiToolbarModule], + providers: [ + provideMockStore({ + initialState: initialMockState, }), + provideMockActions(() => actions$), ], }).compileComponents(); })); diff --git a/apps/frontend/src/app/tools-panel/tools-panel.effects.ts b/apps/frontend/src/app/tools-panel/tools-panel.effects.ts new file mode 100644 index 00000000..98bee551 --- /dev/null +++ b/apps/frontend/src/app/tools-panel/tools-panel.effects.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { select, Store } from '@ngrx/store'; +import { filter, map, switchMap, withLatestFrom } from 'rxjs/operators'; +import * as fromApp from '../app.reducer'; +import { GridService } from '../scene-viewer-container/grid.service'; +import { cancelLine, voxelsSet } from '../scene-viewer-container/scene-viewer-container.actions'; +import { removeSelectionLinePreview, selectTool } from './tools-panel.actions'; + +@Injectable() +export class ToolsPanelEffects { + constructor( + private actions$: Actions, + private gridService: GridService, + private store: Store, + ) {} + + selectTool$ = createEffect(() => + this.actions$.pipe( + ofType(selectTool), + withLatestFrom(this.store.pipe(select(fromApp.selectSceneViewerContainerState))), + filter(([_action, state]) => Boolean(state.selectedLineStartCoord)), + map(() => removeSelectionLinePreview()), + ), + ); + + removeSelectionLinePreview$ = createEffect(() => + this.actions$.pipe( + ofType(removeSelectionLinePreview), + withLatestFrom(this.store.pipe(select(fromApp.selectSceneViewerContainerState))), + map(([_action, state]) => + state.selectedLineChanges.map(change => + this.gridService.setVoxel(change.xyz, change.oldValue), + ), + ), + switchMap(voxelChanges => [voxelsSet({ voxelChanges }), cancelLine()]), + ), + ); +} diff --git a/apps/frontend/src/app/tools-panel/tools-panel.module.ts b/apps/frontend/src/app/tools-panel/tools-panel.module.ts index fc96800f..622be2ac 100644 --- a/apps/frontend/src/app/tools-panel/tools-panel.module.ts +++ b/apps/frontend/src/app/tools-panel/tools-panel.module.ts @@ -1,11 +1,15 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { EffectsModule } from '@ngrx/effects'; import { UiToolbarModule } from '@talus/ui'; +import { GridService } from '../scene-viewer-container/grid.service'; import { ToolsPanelComponent } from './tools-panel.component'; +import { ToolsPanelEffects } from './tools-panel.effects'; @NgModule({ declarations: [ToolsPanelComponent], - imports: [CommonModule, UiToolbarModule], + imports: [CommonModule, EffectsModule.forFeature([ToolsPanelEffects]), UiToolbarModule], + providers: [GridService], exports: [ToolsPanelComponent], }) export class ToolsPanelModule {}