Skip to content

Commit

Permalink
Fix/901/same size after reincluding buildings (#2297)
Browse files Browse the repository at this point in the history
* Add simple fix #901

* Add error message when excluding last building #901

* Fix console error  message #901

* Fix logic and add check to search #901

* Fix failing tests #901

* Add more tests #901

* Fix test logic #901

* Revert simple fix #901

* Add changelog entry #901

* Add e2e test for context menu #901

* Add e2e test for '*' search #901
  • Loading branch information
ngormsen committed Jul 16, 2021
1 parent fe5ed52 commit e3e44ef
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
### Fixed 🐞

- Performance improvements when loading new files. ([#1312](https://github.com/maibornwolff/codecharta/issues/1312))
- It is no longer possible to exclude all files on the map ([#901](https://github.com/MaibornWolff/codecharta/issues/901))

## [1.75.0] - 2021-07-05

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import "../../../state.module"
import { IRootScopeService } from "angular"
import { StoreService } from "../../../store.service"
import { getService, instantiateModule } from "../../../../../../mocks/ng.mockhelper"
import * as FilesHelper from "../../../../model/files/files.helper"
import { BlacklistService } from "./blacklist.service"
import { BlacklistAction, BlacklistActions } from "./blacklist.actions"
import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model"
import { PresentationModeActions } from "../../appSettings/isPresentationMode/isPresentationMode.actions"
import { withMockedEventMethods } from "../../../../util/dataMocks"
import { FILE_STATES, withMockedEventMethods } from "../../../../util/dataMocks"
import { FilesService } from "../../files/files.service"

describe("BlacklistService", () => {
Expand Down Expand Up @@ -66,4 +67,21 @@ describe("BlacklistService", () => {
expect($rootScope.$broadcast).not.toHaveBeenCalled()
})
})

describe("resultsInEmptyMap", () => {
it("should return true when all files are empty", () => {
jest.spyOn(FilesHelper, "getVisibleFileStates").mockReturnValue(FILE_STATES)
const blacklistItem: BlacklistItem[] = [{ path: "/root", type: BlacklistType.exclude }]

expect(blacklistService.resultsInEmptyMap(blacklistItem)).toBe(true)
})

it("should return false when files are left", () => {
blacklistService.isIncludedNode = jest.fn(() => true)
jest.spyOn(FilesHelper, "getVisibleFileStates").mockReturnValue(FILE_STATES)
const blacklistItem: BlacklistItem[] = [{ path: "/root/Parent Leaf", type: BlacklistType.exclude }]

expect(blacklistService.resultsInEmptyMap(blacklistItem)).toBe(false)
})
})
})
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { StoreService, StoreSubscriber } from "../../../store.service"
import { IRootScopeService } from "angular"
import { BlacklistItem } from "../../../../codeCharta.model"
import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model"
import { BlacklistActions, setBlacklist } from "./blacklist.actions"
import { getMergedBlacklist } from "./blacklist.merger"
import { FilesService, FilesSelectionSubscriber } from "../../files/files.service"
import { isActionOfType } from "../../../../util/reduxHelper"
import { getVisibleFiles, isPartialState } from "../../../../model/files/files.helper"
import { getVisibleFiles, getVisibleFileStates, isPartialState } from "../../../../model/files/files.helper"
import { FileState } from "../../../../model/files/files"
import { hierarchy } from "d3-hierarchy"
import { isLeaf, isPathBlacklisted } from "../../../../util/codeMapHelper"

export interface BlacklistSubscriber {
onBlacklistChanged(blacklist: BlacklistItem[])
Expand All @@ -31,6 +33,34 @@ export class BlacklistService implements StoreSubscriber, FilesSelectionSubscrib
this.merge(files)
}

resultsInEmptyMap(blacklistItems: BlacklistItem[]) {
const fileStates = getVisibleFileStates(this.storeService.getState().files)
for (const { file } of fileStates) {
if (!this.isEmptyFile(file, blacklistItems)) {
return false
}
}
return true
}

isIncludedNode(node, blacklist: Array<BlacklistItem>) {
return isLeaf(node) && node.data.path && !isPathBlacklisted(node.data.path, blacklist, BlacklistType.exclude)
}

private isEmptyFile(file, blacklistItems: BlacklistItem[]) {
const blacklist = [...this.storeService.getState().fileSettings.blacklist]
for (const blacklistItem of blacklistItems) {
blacklist.push(blacklistItem)
}

for (const node of hierarchy(file.map)) {
if (this.isIncludedNode(node, blacklist)) {
return false
}
}
return true
}

private merge(files: FileState[]) {
const visibleFiles = getVisibleFiles(files)
const withUpdatedPath = isPartialState(files)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ import { goto } from "../../../puppeteer.helper"
import { BlacklistPanelPageObject } from "../blacklistPanel/blacklistPanel.po"
import { SearchBarPageObject } from "../searchBar/searchBar.po"
import { SearchPanelModeSelectorPageObject } from "../searchPanelModeSelector/searchPanelModeSelector.po"
import { ERROR_MESSAGES } from "../../util/fileValidator"
import { DialogErrorPageObject } from "../dialog/dialog.error.po"

describe("Blacklist(TrackByEvaluation)", () => {
let searchBar: SearchBarPageObject
let searchPanelModeSelector: SearchPanelModeSelectorPageObject
let blacklistPanelPageObject: BlacklistPanelPageObject
let dialogError: DialogErrorPageObject

beforeEach(async () => {
searchBar = new SearchBarPageObject()
searchPanelModeSelector = new SearchPanelModeSelectorPageObject()
blacklistPanelPageObject = new BlacklistPanelPageObject()
dialogError = new DialogErrorPageObject()
await goto()
})

it("should display error when all files are excluded", async () => {
await searchBar.enterAndExcludeSearchPattern("*")

expect(await dialogError.getMessage()).toEqual(ERROR_MESSAGES.blacklistError)
})

it("should have correct list entries in case of track by", async () => {
await searchBar.enterAndExcludeSearchPattern("ts,html")
await searchPanelModeSelector.toggleBlacklistView()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { hasValidHexLength } from "../colorHelper"
export class NodeContextMenuColorPickerController {
private markFolder: ({ color: string }) => void

constructor(private $scope) {}
constructor(private $scope) {
"ngInject"
}

$onInit() {
this.$scope.color = "#FF0000" // without initial value the color-picker's popup would show a 100% transparent color initially
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { CodeMapMouseEventService } from "../codeMap/codeMap.mouseEvent.service"
import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService"
import { CodeMapBuilding } from "../codeMap/rendering/codeMapBuilding"
import { setIdToBuilding } from "../../state/store/lookUp/idToBuilding/idToBuilding.actions"
import { DialogService } from "../dialog/dialog.service"
import { BlacklistService } from "../../state/store/fileSettings/blacklist/blacklist.service"

describe("nodeContextMenuController", () => {
let element: Element
Expand All @@ -35,6 +37,8 @@ describe("nodeContextMenuController", () => {
let codeMapActionsService: CodeMapActionsService
let codeMapPreRenderService: CodeMapPreRenderService
let threeSceneService: ThreeSceneService
let dialogService: DialogService
let blacklistService: BlacklistService

beforeEach(() => {
restartSystem()
Expand All @@ -59,6 +63,8 @@ describe("nodeContextMenuController", () => {
codeMapActionsService = getService<CodeMapActionsService>("codeMapActionsService")
codeMapPreRenderService = getService<CodeMapPreRenderService>("codeMapPreRenderService")
threeSceneService = getService<ThreeSceneService>("threeSceneService")
dialogService = getService<DialogService>("dialogService")
blacklistService = getService<BlacklistService>("blacklistService")
}

function mockElement() {
Expand All @@ -79,7 +85,9 @@ describe("nodeContextMenuController", () => {
storeService,
codeMapActionsService,
codeMapPreRenderService,
threeSceneService
threeSceneService,
dialogService,
blacklistService
)
}

Expand Down Expand Up @@ -394,12 +402,22 @@ describe("nodeContextMenuController", () => {
})

it("should add exclude blacklistItem", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => false)
const expected = { attributes: {}, nodeType: "Folder", path: "/root/Parent Leaf", type: BlacklistType.exclude }

nodeContextMenuController.excludeNode()

expect(storeService.getState().fileSettings.blacklist).toContainEqual(expected)
})

it("should display error dialog when no files are left", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => true)
dialogService.showErrorDialog = jest.fn()

nodeContextMenuController.excludeNode()

expect(dialogService.showErrorDialog).toBeCalled()
})
})

describe("nodeIsFolder", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { BuildingRightClickedEventSubscriber, CodeMapMouseEventService } from ".
import { MapColorsService, MapColorsSubscriber } from "../../state/store/appSettings/mapColors/mapColors.service"
import { getCodeMapNodeFromPath } from "../../util/codeMapHelper"
import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService"
import { DialogService } from "../dialog/dialog.service"
import { BlacklistService } from "../../state/store/fileSettings/blacklist/blacklist.service"
import { ERROR_MESSAGES } from "../../util/fileValidator"

export enum ClickType {
RightClick = 2
Expand Down Expand Up @@ -52,7 +55,9 @@ export class NodeContextMenuController
private storeService: StoreService,
private codeMapActionsService: CodeMapActionsService,
private codeMapPreRenderService: CodeMapPreRenderService,
private threeSceneService: ThreeSceneService
private threeSceneService: ThreeSceneService,
private dialogService: DialogService,
private blacklistService: BlacklistService
) {
"ngInject"
MapColorsService.subscribe(this.$rootScope, this)
Expand Down Expand Up @@ -158,14 +163,18 @@ export class NodeContextMenuController

excludeNode() {
const codeMapNode = this._viewModel.codeMapNode
this.storeService.dispatch(
addBlacklistItem({
path: codeMapNode.path,
type: BlacklistType.exclude,
nodeType: codeMapNode.type,
attributes: codeMapNode.attributes
})
)
const blacklistItem: BlacklistItem = {
path: codeMapNode.path,
type: BlacklistType.exclude,
nodeType: codeMapNode.type,
attributes: codeMapNode.attributes
}

if (this.blacklistService.resultsInEmptyMap([blacklistItem])) {
this.dialogService.showErrorDialog(ERROR_MESSAGES.blacklistError, "Blacklist Error")
} else {
this.storeService.dispatch(addBlacklistItem(blacklistItem))
}
}

addNodeToConstantHighlight() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,34 @@ import { NodeContextMenuPageObject } from "./nodeContextMenu.po"
import { SearchPanelModeSelectorPageObject } from "../searchPanelModeSelector/searchPanelModeSelector.po"
import { MapTreeViewLevelPageObject } from "../mapTreeView/mapTreeView.level.po"
import { CodeMapPageObject } from "../codeMap/codeMap.po"
import { ERROR_MESSAGES } from "../../util/fileValidator"
import { DialogErrorPageObject } from "../dialog/dialog.error.po"

describe("NodeContextMenu", () => {
let contextMenu: NodeContextMenuPageObject
let searchPanelModeSelector: SearchPanelModeSelectorPageObject
let mapTreeViewLevel: MapTreeViewLevelPageObject
let codeMap: CodeMapPageObject
let dialogError: DialogErrorPageObject

beforeEach(async () => {
contextMenu = new NodeContextMenuPageObject()
searchPanelModeSelector = new SearchPanelModeSelectorPageObject()
mapTreeViewLevel = new MapTreeViewLevelPageObject()
codeMap = new CodeMapPageObject()
dialogError = new DialogErrorPageObject()

await goto()
})

it("should show error message when user excludes all files", async () => {
await searchPanelModeSelector.toggleTreeView()
await mapTreeViewLevel.openContextMenu("/root")
await contextMenu.clickOnExclude()

expect(await dialogError.getMessage()).toEqual(`${ERROR_MESSAGES.blacklistError}`)
})

it("right clicking a folder should open a context menu with color options", async () => {
await searchPanelModeSelector.toggleTreeView()
await mapTreeViewLevel.openContextMenu("/root")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export class NodeContextMenuPageObject {
async isClosed() {
await page.waitForSelector("#codemap-context-menu", { hidden: true })
}

async clickOnExclude() {
await clickButtonOnPageElement(`[id='exclude-button']`, { button: "left" })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { BlacklistService } from "../../state/store/fileSettings/blacklist/black
import { setBlacklist } from "../../state/store/fileSettings/blacklist/blacklist.actions"
import { SearchPatternService } from "../../state/store/dynamicSettings/searchPattern/searchPattern.service"
import { setSearchPattern } from "../../state/store/dynamicSettings/searchPattern/searchPattern.actions"
import { DialogService } from "../dialog/dialog.service"

describe("SearchBarController", () => {
let searchBarController: SearchBarController

let $rootScope: IRootScopeService
let storeService: StoreService
let blacklistService: BlacklistService
let dialogService: DialogService
const SOME_EXTRA_TIME = 100

beforeEach(() => {
Expand All @@ -28,10 +31,12 @@ describe("SearchBarController", () => {

$rootScope = getService<IRootScopeService>("$rootScope")
storeService = getService<StoreService>("storeService")
blacklistService = getService<BlacklistService>("blacklistService")
dialogService = getService<DialogService>("dialogService")
}

function rebuildController() {
searchBarController = new SearchBarController($rootScope, storeService)
searchBarController = new SearchBarController($rootScope, storeService, blacklistService, dialogService)
}

describe("constructor", () => {
Expand Down Expand Up @@ -79,6 +84,7 @@ describe("SearchBarController", () => {

describe("onClickBlacklistPattern", () => {
it("should add new blacklist entry and clear searchPattern", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => false)
const blacklistItem = { path: "/root/node/path", type: BlacklistType.exclude }
searchBarController["_viewModel"].searchPattern = blacklistItem.path
storeService.dispatch(setSearchPattern(blacklistItem.path))
Expand All @@ -89,10 +95,19 @@ describe("SearchBarController", () => {
expect(searchBarController["_viewModel"].searchPattern).toBe("")
expect(storeService.getState().dynamicSettings.searchPattern).toBe("")
})
})

describe("onClickBlacklistPattern", () => {
it("separate entries for many in one searchPattern", () => {
it("should display error message when no files are left", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => true)
dialogService.showErrorDialog = jest.fn()
const blacklistItem = { path: "/root", type: BlacklistType.exclude }

searchBarController.onClickBlacklistPattern(blacklistItem.type)

expect(dialogService.showErrorDialog).toBeCalled()
})

it("should separate entries for many in one searchPattern", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => false)
const blacklistItem = { path: "*html*", type: BlacklistType.exclude }
const blacklistItem1 = { path: "*ts*", type: BlacklistType.exclude }
searchBarController["_viewModel"].searchPattern = "html,ts"
Expand All @@ -109,10 +124,9 @@ describe("SearchBarController", () => {
expect(searchBarController["_viewModel"].isPatternHidden).toBeFalsy()
expect(searchBarController["_viewModel"].isPatternExcluded).toBeTruthy()
})
})

describe("onClickBlacklistPattern", () => {
it("separate entries for negated many in one searchPattern", () => {
it("should separate entries for negated many in one searchPattern", () => {
blacklistService.resultsInEmptyMap = jest.fn(() => false)
const blacklistItem = { path: "!*html*", type: BlacklistType.exclude }
const blacklistItem1 = { path: "!*ts*", type: BlacklistType.exclude }
searchBarController["_viewModel"].searchPattern = "!html,ts"
Expand Down

0 comments on commit e3e44ef

Please sign in to comment.