diff --git a/src/application/State/Filter/IUserFilter.ts b/src/application/State/Filter/IUserFilter.ts index ae159d9c..212b333d 100644 --- a/src/application/State/Filter/IUserFilter.ts +++ b/src/application/State/Filter/IUserFilter.ts @@ -2,6 +2,7 @@ import { IFilterResult } from './IFilterResult'; import { ISignal } from '@/infrastructure/Events/Signal'; export interface IUserFilter { + readonly currentFilter: IFilterResult | undefined; readonly filtered: ISignal; readonly filterRemoved: ISignal; setFilter(filter: string): void; diff --git a/src/application/State/Filter/UserFilter.ts b/src/application/State/Filter/UserFilter.ts index 7fe99a4b..ba1757d7 100644 --- a/src/application/State/Filter/UserFilter.ts +++ b/src/application/State/Filter/UserFilter.ts @@ -8,6 +8,7 @@ import { Signal } from '@/infrastructure/Events/Signal'; export class UserFilter implements IUserFilter { public readonly filtered = new Signal(); public readonly filterRemoved = new Signal(); + public currentFilter: IFilterResult | undefined; constructor(private application: IApplication) { @@ -28,11 +29,12 @@ export class UserFilter implements IUserFilter { filteredCategories, filter, ); - + this.currentFilter = matches; this.filtered.notify(matches); } public removeFilter(): void { + this.currentFilter = undefined; this.filterRemoved.notify(); } } diff --git a/src/presentation/Scripts/ScriptsTree/ScriptsTree.vue b/src/presentation/Scripts/ScriptsTree/ScriptsTree.vue index eaa12f81..f57d31b0 100644 --- a/src/presentation/Scripts/ScriptsTree/ScriptsTree.vue +++ b/src/presentation/Scripts/ScriptsTree/ScriptsTree.vue @@ -49,6 +49,7 @@ state.filter.filtered.on(this.handleFiltered); // Update initial state await this.initializeNodesAsync(this.categoryId); + await this.initializeFilter(state.filter.currentFilter); } public async toggleNodeSelectionAsync(event: INodeSelectedEvent) { @@ -84,6 +85,14 @@ (category: ICategory) => node.id === getCategoryNodeId(category)); } + private initializeFilter(currentFilter: IFilterResult | undefined) { + if (!currentFilter) { + this.handleFilterRemoved(); + } else { + this.handleFiltered(currentFilter); + } + } + private handleSelectionChanged(selectedScripts: ReadonlyArray): void { this.selectedNodeIds = selectedScripts .map((node) => node.id); diff --git a/src/presentation/Scripts/ScriptsTree/SelectableTree/SelectableTree.vue b/src/presentation/Scripts/ScriptsTree/SelectableTree/SelectableTree.vue index 74d330a9..f42b1b76 100644 --- a/src/presentation/Scripts/ScriptsTree/SelectableTree/SelectableTree.vue +++ b/src/presentation/Scripts/ScriptsTree/SelectableTree/SelectableTree.vue @@ -35,7 +35,7 @@ Node, }, }) - export default class SelectableTree extends Vue { + export default class SelectableTree extends Vue { // Keep it stateless to make it easier to switch out @Prop() public filterPredicate?: FilterPredicate; @Prop() public filterText?: string; @Prop() public selectedNodeIds?: ReadonlyArray; diff --git a/src/presentation/Scripts/TheScripts.vue b/src/presentation/Scripts/TheScripts.vue index 39e838fa..e14fa7de 100644 --- a/src/presentation/Scripts/TheScripts.vue +++ b/src/presentation/Scripts/TheScripts.vue @@ -72,7 +72,6 @@ public isSearching = false; public searchHasMatches = false; - public async mounted() { const state = await this.getCurrentStateAsync(); this.repositoryUrl = state.app.repositoryUrl; diff --git a/tests/unit/application/State/Filter/UserFilter.spec.ts b/tests/unit/application/State/Filter/UserFilter.spec.ts index 25985ecb..07a6b42c 100644 --- a/tests/unit/application/State/Filter/UserFilter.spec.ts +++ b/tests/unit/application/State/Filter/UserFilter.spec.ts @@ -7,129 +7,156 @@ import 'mocha'; import { expect } from 'chai'; describe('UserFilter', () => { - it('signals when removing filter', () => { - // arrange - let isCalled = false; - const sut = new UserFilter(new ApplicationStub()); - sut.filterRemoved.on(() => isCalled = true); - // act - sut.removeFilter(); - // assert - expect(isCalled).to.be.equal(true); - }); - it('signals when no matches', () => { - // arrange - let actual: IFilterResult; - const nonMatchingFilter = 'non matching filter'; - const sut = new UserFilter(new ApplicationStub()); - sut.filtered.on((filterResult) => actual = filterResult); - // act - sut.setFilter(nonMatchingFilter); - // assert - expect(actual.hasAnyMatches()).be.equal(false); - expect(actual.categoryMatches).to.have.lengthOf(0); - expect(actual.scriptMatches).to.have.lengthOf(0); - expect(actual.query).to.equal(nonMatchingFilter); - }); - describe('signals when script matches', () => { - it('code matches', () => { + describe('removeFilter', () => { + it('signals when removing filter', () => { // arrange - const code = 'HELLO world'; - const filter = 'Hello WoRLD'; - let actual: IFilterResult; - const script = new ScriptStub('id').withCode(code); - const category = new CategoryStub(33).withScript(script); - const sut = new UserFilter(new ApplicationStub() - .withAction(category)); - sut.filtered.on((filterResult) => actual = filterResult); + let isCalled = false; + const sut = new UserFilter(new ApplicationStub()); + sut.filterRemoved.on(() => isCalled = true); // act - sut.setFilter(filter); + sut.removeFilter(); // assert - expect(actual.hasAnyMatches()).be.equal(true); - expect(actual.categoryMatches).to.have.lengthOf(0); - expect(actual.scriptMatches).to.have.lengthOf(1); - expect(actual.scriptMatches[0]).to.deep.equal(script); - expect(actual.query).to.equal(filter); + expect(isCalled).to.be.equal(true); }); - it('revertCode matches', () => { + it('currentFilter is undefined', () => { // arrange - const revertCode = 'HELLO world'; - const filter = 'Hello WoRLD'; - let actual: IFilterResult; - const script = new ScriptStub('id').withRevertCode(revertCode); - const category = new CategoryStub(33).withScript(script); - const sut = new UserFilter(new ApplicationStub() - .withAction(category)); - sut.filtered.on((filterResult) => actual = filterResult); + const sut = new UserFilter(new ApplicationStub()); // act - sut.setFilter(filter); + sut.removeFilter(); // assert - expect(actual.hasAnyMatches()).be.equal(true); - expect(actual.categoryMatches).to.have.lengthOf(0); - expect(actual.scriptMatches).to.have.lengthOf(1); - expect(actual.scriptMatches[0]).to.deep.equal(script); - expect(actual.query).to.equal(filter); - }); - it('name matches', () => { - // arrange - const name = 'HELLO world'; - const filter = 'Hello WoRLD'; - let actual: IFilterResult; - const script = new ScriptStub('id').withName(name); - const category = new CategoryStub(33).withScript(script); - const sut = new UserFilter(new ApplicationStub() - .withAction(category)); - sut.filtered.on((filterResult) => actual = filterResult); - // act - sut.setFilter(filter); - // assert - expect(actual.hasAnyMatches()).be.equal(true); - expect(actual.categoryMatches).to.have.lengthOf(0); - expect(actual.scriptMatches).to.have.lengthOf(1); - expect(actual.scriptMatches[0]).to.deep.equal(script); - expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.be.equal(undefined); }); }); - it('signals when category matches', () => { - // arrange - const categoryName = 'HELLO world'; - const filter = 'Hello WoRLD'; - let actual: IFilterResult; - const category = new CategoryStub(55).withName(categoryName); - const sut = new UserFilter(new ApplicationStub() - .withAction(category)); - sut.filtered.on((filterResult) => actual = filterResult); - // act - sut.setFilter(filter); - // assert - expect(actual.hasAnyMatches()).be.equal(true); - expect(actual.categoryMatches).to.have.lengthOf(1); - expect(actual.categoryMatches[0]).to.deep.equal(category); - expect(actual.scriptMatches).to.have.lengthOf(0); - expect(actual.query).to.equal(filter); - }); - it('signals when category and script matches', () => { - // arrange - const matchingText = 'HELLO world'; - const filter = 'Hello WoRLD'; - let actual: IFilterResult; - const script = new ScriptStub('script') - .withName(matchingText); - const category = new CategoryStub(55) - .withName(matchingText) - .withScript(script); - const app = new ApplicationStub() - .withAction(category); - const sut = new UserFilter(app); - sut.filtered.on((filterResult) => actual = filterResult); - // act - sut.setFilter(filter); - // assert - expect(actual.hasAnyMatches()).be.equal(true); - expect(actual.categoryMatches).to.have.lengthOf(1); - expect(actual.categoryMatches[0]).to.deep.equal(category); - expect(actual.scriptMatches).to.have.lengthOf(1); - expect(actual.scriptMatches[0]).to.deep.equal(script); - expect(actual.query).to.equal(filter); + describe('setFilter', () => { + it('signals when no matches', () => { + // arrange + let actual: IFilterResult; + const nonMatchingFilter = 'non matching filter'; + const sut = new UserFilter(new ApplicationStub()); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(nonMatchingFilter); + // assert + expect(actual.hasAnyMatches()).be.equal(false); + expect(actual.query).to.equal(nonMatchingFilter); + }); + it('sets currentFilter as expected when no matches', () => { + // arrange + const nonMatchingFilter = 'non matching filter'; + const sut = new UserFilter(new ApplicationStub()); + // act + sut.setFilter(nonMatchingFilter); + // assert + const actual = sut.currentFilter; + expect(actual.hasAnyMatches()).be.equal(false); + expect(actual.query).to.equal(nonMatchingFilter); + }); + describe('signals when script matches', () => { + it('code matches', () => { + // arrange + const code = 'HELLO world'; + const filter = 'Hello WoRLD'; + let actual: IFilterResult; + const script = new ScriptStub('id').withCode(code); + const category = new CategoryStub(33).withScript(script); + const sut = new UserFilter(new ApplicationStub() + .withAction(category)); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(filter); + // assert + expect(actual.hasAnyMatches()).be.equal(true); + expect(actual.categoryMatches).to.have.lengthOf(0); + expect(actual.scriptMatches).to.have.lengthOf(1); + expect(actual.scriptMatches[0]).to.deep.equal(script); + expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.deep.equal(actual); + }); + it('revertCode matches', () => { + // arrange + const revertCode = 'HELLO world'; + const filter = 'Hello WoRLD'; + let actual: IFilterResult; + const script = new ScriptStub('id').withRevertCode(revertCode); + const category = new CategoryStub(33).withScript(script); + const sut = new UserFilter(new ApplicationStub() + .withAction(category)); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(filter); + // assert + expect(actual.hasAnyMatches()).be.equal(true); + expect(actual.categoryMatches).to.have.lengthOf(0); + expect(actual.scriptMatches).to.have.lengthOf(1); + expect(actual.scriptMatches[0]).to.deep.equal(script); + expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.deep.equal(actual); + }); + it('name matches', () => { + // arrange + const name = 'HELLO world'; + const filter = 'Hello WoRLD'; + let actual: IFilterResult; + const script = new ScriptStub('id').withName(name); + const category = new CategoryStub(33).withScript(script); + const sut = new UserFilter(new ApplicationStub() + .withAction(category)); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(filter); + // assert + expect(actual.hasAnyMatches()).be.equal(true); + expect(actual.categoryMatches).to.have.lengthOf(0); + expect(actual.scriptMatches).to.have.lengthOf(1); + expect(actual.scriptMatches[0]).to.deep.equal(script); + expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.deep.equal(actual); + }); + + it('signals when category matches', () => { + // arrange + const categoryName = 'HELLO world'; + const filter = 'Hello WoRLD'; + let actual: IFilterResult; + const category = new CategoryStub(55).withName(categoryName); + const sut = new UserFilter(new ApplicationStub() + .withAction(category)); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(filter); + // assert + expect(actual.hasAnyMatches()).be.equal(true); + expect(actual.categoryMatches).to.have.lengthOf(1); + expect(actual.categoryMatches[0]).to.deep.equal(category); + expect(actual.scriptMatches).to.have.lengthOf(0); + expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.deep.equal(actual); + }); + it('signals when category and script matches', () => { + // arrange + const matchingText = 'HELLO world'; + const filter = 'Hello WoRLD'; + let actual: IFilterResult; + const script = new ScriptStub('script') + .withName(matchingText); + const category = new CategoryStub(55) + .withName(matchingText) + .withScript(script); + const app = new ApplicationStub() + .withAction(category); + const sut = new UserFilter(app); + sut.filtered.on((filterResult) => actual = filterResult); + // act + sut.setFilter(filter); + // assert + expect(actual.hasAnyMatches()).be.equal(true); + expect(actual.categoryMatches).to.have.lengthOf(1); + expect(actual.categoryMatches[0]).to.deep.equal(category); + expect(actual.scriptMatches).to.have.lengthOf(1); + expect(actual.scriptMatches[0]).to.deep.equal(script); + expect(actual.query).to.equal(filter); + expect(sut.currentFilter).to.deep.equal(actual); + }); + }); }); });