Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/3213/add notes to a custom view #3234

Merged
merged 23 commits into from Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
177e38c
Enable safari compatibility and add babel class-static-blcok package
Feb 10, 2023
d825ea3
Add Custom Config Dialog Component, Add note to custom config model, …
Feb 16, 2023
c515573
Fix addCustomButton tests
Feb 16, 2023
9c13eb6
Move note edit below title, change button behaviour, display note pre…
Feb 16, 2023
785f26b
Merge branch 'main' into feature/3213/add-notes-to-a-custom-view
Feb 16, 2023
4833bf7
Update old tests
Feb 17, 2023
f9716f9
Add and fix remaining tests
Feb 22, 2023
5c9c2b3
Merge branch 'main' into feature/3213/add-notes-to-a-custom-view
RomanenkoVladimir Feb 22, 2023
9afb37d
Update Changelog
Feb 22, 2023
c69449f
Apply suggested scss changes
Feb 23, 2023
b6b63fd
Fix bottmo maring for note preview
Feb 23, 2023
2f79c04
Re-Enable previous click-on-title-to-apply-custom-config behaviour an…
Feb 23, 2023
c293eb6
Merge branch 'main' into feature/3213/add-notes-to-a-custom-view
RomanenkoVladimir Feb 23, 2023
4d41a05
Merge branch 'main' into feature/3213/add-notes-to-a-custom-view
Mar 17, 2023
cd4112a
Remove angular legacy dialogs #3213
Mar 17, 2023
71a4b56
Fix view of custom config list, make pipe for truncate text more reus…
Hall-Ma Mar 20, 2023
9e880cc
Adjust styling for editing custom config notes in dialog, restructure…
Hall-Ma Mar 20, 2023
9218c48
Adjust tests
Hall-Ma Mar 22, 2023
ef79d79
Update changelog
Hall-Ma Mar 22, 2023
3d3ebb6
Custom config note property is now optional, adjust tests and data mocks
Hall-Ma Mar 22, 2023
58b0f0e
Update tests
Hall-Ma Mar 24, 2023
b8ec50f
Merge branch 'main' into feature/3213/add-notes-to-a-custom-view
Hall-Ma Mar 24, 2023
d7e0be3
refactor: remove not needed mock
Mar 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
- Display the CodeCharta logo next to the MaibornWolff logo [#3226](https://github.com/MaibornWolff/codecharta/pull/3226)
- Tooltip for primary and secondary metrics that displays AttributeDescriptor information in the sidebar [#3239](https://github.com/MaibornWolff/codecharta/pull/3239) </br>
![image](https://user-images.githubusercontent.com/65733509/227218468-b7d1e1ae-b847-40ab-8513-f3762b8787bb.png)
- Supports adding note to a custom view, provides a preview and an edit option for notes from the selection menu [#3234](https://github.com/MaibornWolff/codecharta/pull/3234) </br>
![image](https://user-images.githubusercontent.com/72517530/226942610-9e08d39c-324d-4de3-81d0-4e5da4e589aa.png)
![image](https://user-images.githubusercontent.com/72517530/226943152-1bb339bb-c39f-4bf6-a32d-ee8476249f98.png)

### Changed

Expand Down
Expand Up @@ -25,6 +25,7 @@ export interface CustomConfig {
camera: Vector3
cameraTarget: Vector3
}
note?: string
}

export type ExportCustomConfig = CustomConfig
Expand Down
@@ -1,6 +1,6 @@
import { TestBed } from "@angular/core/testing"
import { AddCustomConfigButtonModule } from "./addCustomConfigButton.module"
import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/angular"
import { render, screen } from "@testing-library/angular"
import { AddCustomConfigButtonComponent } from "./addCustomConfigButton.component"
import userEvent from "@testing-library/user-event"
import { CustomConfigHelper } from "../../../util/customConfigHelper"
Expand All @@ -14,24 +14,25 @@ describe("addCustomConfigButtonComponent", () => {
imports: [AddCustomConfigButtonModule],
providers: [
{ provide: ThreeCameraService, useValue: { camera: { position: new Vector3(0, 300, 1000) } } },
{ provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(0, 0, 0) } } }
{
provide: ThreeOrbitControlsService,
useValue: { controls: { target: new Vector3(0, 0, 0) } }
}
]
})
})

it("should let a user save a custom config", async () => {
const addCustomConfigSpy = jest.spyOn(CustomConfigHelper, "addCustomConfig")
await render(AddCustomConfigButtonComponent, { excludeComponentDeclaration: true })
const configName = "myCustomConfig"
const configNote = "My Custom Note"

const button = screen.getByRole("button")
fireEvent.click(button)
await userEvent.click(screen.getByRole("button"))
await userEvent.type(screen.getAllByRole("textbox")[0], configName)
await userEvent.type(screen.getAllByRole("textbox")[1], configNote)
await userEvent.click(screen.getByRole("button", { name: "ADD" }))

await screen.findByText("Add Custom View")

await userEvent.type(screen.getByRole("textbox"), "myCustomConfig")
fireEvent.click(screen.getByRole("button", { name: "ADD" }))

await waitForElementToBeRemoved(screen.queryByText("Add Custom View"))
expect(addCustomConfigSpy).toHaveBeenCalledTimes(1)
})
})
Expand Up @@ -5,9 +5,10 @@ import { AddCustomConfigDialogComponent } from "./addCustomConfigDialog/addCusto
import { FormsModule, ReactiveFormsModule } from "@angular/forms"
import { CommonModule } from "@angular/common"
import { DownloadAndPurgeConfigsComponent } from "./addCustomConfigDialog/downloadAndPurgeConfigs/downloadAndPurgeConfigs.component"
import { CustomConfigNoteDialogButtonModule } from "../customConfigNoteDialogButton/customConfigNoteDialogButton.module"

@NgModule({
imports: [MaterialModule, ReactiveFormsModule, FormsModule, CommonModule],
imports: [MaterialModule, ReactiveFormsModule, FormsModule, CommonModule, CustomConfigNoteDialogButtonModule],
declarations: [AddCustomConfigButtonComponent, AddCustomConfigDialogComponent, DownloadAndPurgeConfigsComponent],
exports: [AddCustomConfigButtonComponent]
})
Expand Down
@@ -1,4 +1,4 @@
<mat-toolbar class="header">
<mat-toolbar class="header" xmlns="http://www.w3.org/1999/html">
<h2>Add Custom View</h2>
</mat-toolbar>

Expand All @@ -7,9 +7,21 @@ <h2>Add Custom View</h2>
<mat-form-field>
<label>Save individual configurations for your map.</label>
<input matInput class="custom-config-input" [formControl]="customConfigName" required />
<mat-hint align="start">View Name</mat-hint>
<mat-hint align="start">Config View Name</mat-hint>
<mat-error *ngIf="customConfigName.invalid">{{ getErrorMessage() }}</mat-error>
</mat-form-field>
<mat-form-field class="custom-config-note">
<label>Provide custom note for configuration (optional)</label>
<textarea
cdkAutosizeMinRows="8"
cdkTextareaAutosize
matInput
class="custom-config-input"
[(ngModel)]="customConfigNote"
required
></textarea>
Hall-Ma marked this conversation as resolved.
Show resolved Hide resolved
<mat-hint align="start">Config Note</mat-hint>
</mat-form-field>
</div>
</mat-dialog-content>

Expand Down
Expand Up @@ -14,6 +14,7 @@ import { VisibleFilesBySelectionMode, visibleFilesBySelectionModeSelector } from
})
export class AddCustomConfigDialogComponent implements OnInit {
customConfigName: UntypedFormControl
customConfigNote: string

constructor(
private state: State,
Expand All @@ -38,10 +39,15 @@ export class AddCustomConfigDialogComponent implements OnInit {
}

addCustomConfig() {
const newCustomConfig = buildCustomConfigFromState(this.customConfigName.value, this.state.getValue(), {
camera: this.threeCameraService.camera.position,
cameraTarget: this.threeOrbitControlsService.controls.target
})
const newCustomConfig = buildCustomConfigFromState(
this.customConfigName.value,
this.state.getValue(),
{
camera: this.threeCameraService.camera.position,
cameraTarget: this.threeOrbitControlsService.controls.target
},
this.customConfigNote
)
CustomConfigHelper.addCustomConfig(newCustomConfig)
}
}
Expand Down
Expand Up @@ -27,18 +27,30 @@ describe("addCustomConfigDialogComponent", () => {
it("should suggest a valid custom view name and 'add' button is enabled", async () => {
await render(AddCustomConfigDialogComponent, { excludeComponentDeclaration: true })

const input = screen.getByRole("textbox") as HTMLInputElement
const input = screen.getAllByRole("textbox") as HTMLInputElement[]
const nameTextField = input[0]

expect(input.value).toBe("new custom view name")
expect(nameTextField.value).toBe("new custom view name")
expect((screen.getByRole("button") as HTMLButtonElement).disabled).toBe(false)
})

it("should show an empty comment text field, with optional entry", async () => {
await render(AddCustomConfigDialogComponent, { excludeComponentDeclaration: true })

const input = screen.getAllByRole("textbox") as HTMLInputElement[]
const commentTextField = input[1]

expect(commentTextField.value).toBe("")
expect((screen.getByRole("button") as HTMLButtonElement).disabled).toBe(false)
})

it("should show error message when input field is empty and disable 'add' button", async () => {
await render(AddCustomConfigDialogComponent, { excludeComponentDeclaration: true })

const input = screen.getByRole("textbox") as HTMLInputElement
await userEvent.clear(input)
input.blur()
const input = screen.getAllByRole("textbox") as HTMLInputElement[]
const nameTextField = input[0]
await userEvent.clear(nameTextField)
nameTextField.blur()

expect(await screen.findByText("Please enter a view name.")).not.toBeNull()
expect((screen.getByRole("button") as HTMLButtonElement).disabled).toBe(true)
Expand All @@ -48,9 +60,11 @@ describe("addCustomConfigDialogComponent", () => {
await render(AddCustomConfigDialogComponent, { excludeComponentDeclaration: true })
jest.spyOn(CustomConfigHelper, "hasCustomConfigByName").mockReturnValue(true)

const input = screen.getByRole("textbox") as HTMLInputElement
await userEvent.type(input, "file name already exists")
input.blur()
const input = screen.getAllByRole("textbox") as HTMLInputElement[]
const nameTextField = input[0]

await userEvent.type(nameTextField, "file name already exists")
nameTextField.blur()

expect(await screen.findByText("A Custom View with this name already exists.")).not.toBeNull()
expect((screen.getByRole("button") as HTMLButtonElement).disabled).toBe(true)
Expand Down
Expand Up @@ -15,11 +15,12 @@
}

.dialog-content {
padding: 0 24px;
margin: 10px 0;

mat-form-field {
width: 100%;

&.custom-config-note {
padding-top: 30px;
}
}

label {
Expand Down
Expand Up @@ -3,10 +3,8 @@
(click)="applyCustomConfig()"
[disabled]="!customConfigItem.isApplicable"
[style.color]="customConfigItem | customConfig2ApplicableColor"
title="{{ customConfigItem.name }}"
>
<p class="config-name" title="{{ customConfigItem.name }}">
<b>{{ customConfigItem.name }}</b>
</p>
<div class="config-metric-list">
<p class="config-metric"><i class="fa fa-arrows-alt"></i> {{ customConfigItem.metrics.areaMetric }}</p>
<p class="config-metric"><i class="fa fa-arrows-v"></i> {{ customConfigItem.metrics.heightMetric }}</p>
Expand Down
Expand Up @@ -5,6 +5,7 @@ cc-apply-custom-config-button {
button {
flex-direction: row;
width: 100%;
margin: 0;

&:disabled {
cursor: default;
Expand All @@ -21,7 +22,7 @@ cc-apply-custom-config-button {
text-overflow: ellipsis;
overflow: hidden;
font-size: 15px;
margin: 5px 0;
margin: 0;
text-align: left;

&.config-name {
Expand Down
Expand Up @@ -8,16 +8,12 @@ import { ThreeCameraService } from "../../../../codeMap/threeViewer/threeCamera.
import { ThreeOrbitControlsService } from "../../../../codeMap/threeViewer/threeOrbitControls.service"
import { CUSTOM_CONFIG_ITEM_GROUPS } from "../../../../../util/dataMocks"
import { CustomConfigHelper } from "../../../../../util/customConfigHelper"
import { MatDialogRef } from "@angular/material/dialog"

describe("applyCustomConfigButtonComponent", () => {
const mockedDialogReference = { close: jest.fn() }

beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomConfigsModule],
providers: [
{ provide: MatDialogRef, useValue: mockedDialogReference },
{ provide: ThreeCameraService, useValue: {} },
{ provide: ThreeOrbitControlsService, useValue: {} }
]
Expand All @@ -39,7 +35,6 @@ describe("applyCustomConfigButtonComponent", () => {
expect(getComputedStyle(colorSwatchElements[2]).backgroundColor).toBe("rgb(130, 14, 14)")
expect(getComputedStyle(colorSwatchElements[3]).backgroundColor).toBe("rgb(235, 131, 25)")

expect(screen.getByText("SampleMap View #1")).not.toBeNull()
expect(screen.getByText("rloc")).not.toBeNull()
expect(screen.getByText("mcc")).not.toBeNull()
expect(screen.getByText("functions")).not.toBeNull()
Expand All @@ -63,7 +58,6 @@ describe("applyCustomConfigButtonComponent", () => {
const applyCustomConfigButton = screen.getByRole("button") as HTMLButtonElement

expect(getComputedStyle(applyCustomConfigButton).color).toBe("rgb(204, 204, 204)")
expect(screen.getByText("SampleMap View #1")).not.toBeNull()
expect(screen.getByText("rloc")).not.toBeNull()
expect(screen.getByText("mcc")).not.toBeNull()
expect(screen.getByText("functions")).not.toBeNull()
Expand Down
Expand Up @@ -5,19 +5,38 @@
*ngFor="let customConfigItemGroup of customConfigItemGroups | keyvalue"
>
<mat-expansion-panel-header>
<mat-panel-title>
<mat-panel-title class="custom-config-item-group-title">
Custom View(s) in
<span class="highlight-mode"> {{ customConfigItemGroup.value.mapSelectionMode | titlecase }} </span>
<strong> {{ customConfigItemGroup.value.mapSelectionMode | titlecase }} </strong>
mode for
{{ customConfigItemGroup.value.mapNames }}
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list *ngFor="let customConfig of customConfigItemGroup.value.customConfigItems">
<mat-list-item title="{{ customConfig | customConfig2ApplicableMessage }}">
<cc-apply-custom-config-button [customConfigItem]="customConfig"></cc-apply-custom-config-button>
<button class="remove-button" title="Remove Custom View" (click)="removeCustomConfig(customConfig.id)">
<i class="fa fa-trash"></i>
</button>
<div class="metrics-box">
<p class="config-item-name" title="{{ customConfig.name }}">
<strong>
<span (click)="applyCustomConfig(customConfig.id)" mat-dialog-close>
{{ customConfig.name | truncateText: 75 }}
</span>
</strong>
</p>
</div>
<div class="custom-config-note">
<p class="custom-config-note-content">
<span (click)="applyCustomConfig(customConfig.id)" mat-dialog-close>
{{ customConfig.note ? (customConfig.note | truncateText: 95) : "Add Note" }}
</span>
</p>
<cc-custom-config-note-dialog-button [customConfigItem]="customConfig"></cc-custom-config-note-dialog-button>
</div>
<div class="custom-config-action-buttons">
<cc-apply-custom-config-button [customConfigItem]="customConfig"></cc-apply-custom-config-button>
<button class="remove-button" title="Remove Custom View" (click)="removeCustomConfig(customConfig.id)">
<i class="fa fa-trash"></i>
</button>
</div>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
@@ -0,0 +1,38 @@
@use "../../../../../material/theme";

cc-custom-config-item-group {
.custom-config-item-group-title {
color: theme.$cc-font-color;
display: inline-block;
}

div {
.metrics-box {
margin-top: 10px;
}

.custom-config-note {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-top: 5px;
}

.custom-config-action-buttons {
display: flex;
align-items: center;
margin-bottom: 5px;
}
}

p {
font-size: 15px;
margin: 0;
white-space: pre-line;

&.custom-config-note-content {
margin-right: 7px;
font-size: 13px;
}
}
}