Skip to content

Commit 0d48869

Browse files
committed
feat: add persistent color selection for browser container sessions
Adds a color picker dialog (9 Firefox container colors) accessible from the session contextual menu. The chosen color is persisted in the session model and sent to the browser extension via the existing WebSocket payload, so Firefox containers are created or updated with the user-defined color instead of a random fallback. - Session model gains an optional `color` field - New ChangeColorDialog component with swatch UI, fully keyboard accessible - Color dot indicator on session cards, updates live after save - extension-websocket.service forwards sessionColor to the extension - @noovolari/dpapi-addon moved to optionalDependencies (Windows-only) Signed-off-by: Jeremy Snidaro <jeremy.snidaro@papernest.com> Signed-off-by: Jeremy SNIDARO <jeremy.snidaro@papernest.com>
1 parent 663d619 commit 0d48869

14 files changed

Lines changed: 200 additions & 4 deletions

packages/core/src/models/session.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class Session {
1515
startDateTime?: string;
1616
type: SessionType;
1717
sessionTokenExpiration: string;
18+
color?: string;
1819

1920
constructor(public sessionName: string, public region: string) {
2021
this.sessionId = uuid.v4();

packages/desktop-app/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@
9494
"desktop": {
9595
"desktopActions": {
9696
"NewWindow": {
97-
"Exec": "leapp %U"
97+
"Exec": "leapp %U"
9898
}
99-
}
99+
}
100100
},
101101
"target": [
102102
"deb",
@@ -157,7 +157,6 @@
157157
"@ng-select/ng-select": "10.0.4",
158158
"@ngx-translate/core": "14.0.0",
159159
"@ngx-translate/http-loader": "~6.0.0",
160-
"@noovolari/dpapi-addon": "0.1.2",
161160
"@noovolari/leapp-core": "file:../core",
162161
"@smithy/fetch-http-handler": "2.4.2",
163162
"assert": "2.0.0",
@@ -273,5 +272,8 @@
273272
"ts-node": "^9.1.1",
274273
"typescript": "^4.9.0",
275274
"util": "^0.12.4"
275+
},
276+
"optionalDependencies": {
277+
"@noovolari/dpapi-addon": "0.1.2"
276278
}
277279
}

packages/desktop-app/src/app/components/components.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { MatTooltipModule } from "@angular/material/tooltip";
4343
import { CredentialProcessDialogComponent } from "./dialogs/credential-process-dialog/credential-process-dialog.component";
4444
import { ChangeRegionDialogComponent } from "./dialogs/change-region-dialog/change-region-dialog.component";
4545
import { ChangeNamedProfileDialogComponent } from "./dialogs/change-named-profile-dialog/change-named-profile-dialog.component";
46+
import { ChangeColorDialogComponent } from "./dialogs/change-color-dialog/change-color-dialog.component";
4647
import { SsmModalDialogComponent } from "./dialogs/ssm-modal-dialog/ssm-modal-dialog.component";
4748
import { ContextualMenuComponent } from "./contextual-menu/contextual-menu.component";
4849
import { BottomBarComponent } from "./bottom-bar/bottom-bar.component";
@@ -92,6 +93,7 @@ import { NoovolariDialogComponent } from "./dialogs/noovolari-dialog/noovolari-d
9293
CredentialProcessDialogComponent,
9394
ChangeRegionDialogComponent,
9495
ChangeNamedProfileDialogComponent,
96+
ChangeColorDialogComponent,
9597
SsmModalDialogComponent,
9698
ContextualMenuComponent,
9799
BottomBarComponent,

packages/desktop-app/src/app/components/contextual-menu/contextual-menu.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@
111111
<i class="moon-User"></i>&nbsp;
112112
<span>Named Profile</span>
113113
</button>
114+
<button mat-menu-item (click)="changeColorModalOpen();">
115+
<i class="moon-Star"></i>&nbsp;
116+
<span>Color</span>
117+
</button>
114118
</mat-menu>
115119

116120
<mat-menu #copy>

packages/desktop-app/src/app/components/contextual-menu/contextual-menu.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ export class ContextualMenuComponent implements OnInit, OnDestroy {
158158
await this.selectedSessionActionsService.changeProfileModalOpen(this.selectedSession);
159159
}
160160

161+
async changeColorModalOpen(): Promise<void> {
162+
await this.selectedSessionActionsService.changeColorModalOpen(this.selectedSession);
163+
}
164+
161165
async copyCredentials(type: number): Promise<void> {
162166
await this.selectedSessionActionsService.copyCredentials(this.selectedSession, type);
163167
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<a class="close-modal" (click)="closeModal();"><i class="moon-Close"></i></a>
2+
<h4>{{session.sessionName}}</h4>
3+
<h5>{{session | detail }}</h5>
4+
5+
<div class="color-form">
6+
<p>Select a color</p>
7+
<div class="color-swatches">
8+
<button
9+
*ngFor="let color of colors"
10+
type="button"
11+
class="color-swatch-wrapper"
12+
[class.selected]="selectedColor === color.name"
13+
(click)="selectColor(color.name)">
14+
<div class="color-swatch" [style.background-color]="color.hex"></div>
15+
<span class="color-label">{{color.name}}</span>
16+
</button>
17+
</div>
18+
<br>
19+
<button type="button" (click)="saveColor();" [disabled]="!selectedColor"
20+
[ngClass]="(!selectedColor) ? 'btn-control mat-button-disabled': 'btn-control'">Save Color
21+
</button>
22+
<a (click)="closeModal();">Cancel</a>
23+
</div>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
.color-form {
2+
margin-top: 20px;
3+
4+
p {
5+
display: block;
6+
margin-bottom: 12px;
7+
}
8+
9+
a {
10+
display: inline-block;
11+
margin-left: 10px;
12+
}
13+
}
14+
15+
.color-swatches {
16+
display: flex;
17+
flex-wrap: wrap;
18+
gap: 12px;
19+
}
20+
21+
.color-swatch-wrapper {
22+
display: flex;
23+
flex-direction: column;
24+
align-items: center;
25+
cursor: pointer;
26+
gap: 4px;
27+
background: none !important;
28+
border: none;
29+
padding: 0;
30+
outline: none;
31+
-webkit-appearance: none;
32+
appearance: none;
33+
34+
&:focus-visible .color-swatch {
35+
box-shadow: 0 0 0 3px white, 0 0 0 5px rgba(0, 0, 0, 0.4);
36+
}
37+
38+
&:hover .color-swatch {
39+
transform: scale(1.15);
40+
}
41+
42+
&.selected .color-swatch {
43+
transform: scale(1.15);
44+
box-shadow: 0 0 0 3px white, 0 0 0 5px rgba(0, 0, 0, 0.4);
45+
}
46+
47+
&.selected .color-label {
48+
font-weight: bold;
49+
}
50+
}
51+
52+
.color-swatch {
53+
width: 28px;
54+
height: 28px;
55+
border-radius: 50%;
56+
transition: transform 0.1s ease, box-shadow 0.1s ease;
57+
}
58+
59+
.color-label {
60+
font-size: 9px;
61+
text-transform: capitalize;
62+
opacity: 0.75;
63+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core";
2+
import { Session } from "@noovolari/leapp-core/models/session";
3+
import { AppService } from "../../../services/app.service";
4+
import { AppProviderService } from "../../../services/app-provider.service";
5+
import { MessageToasterService, ToastLevel } from "../../../services/message-toaster.service";
6+
7+
export const containerColors: { name: string; hex: string }[] = [
8+
{ name: "toolbar", hex: "#7c7c7d" },
9+
{ name: "red", hex: "#ff0039" },
10+
{ name: "pink", hex: "#ff84a3" },
11+
{ name: "orange", hex: "#ff9f00" },
12+
{ name: "yellow", hex: "#ffcb00" },
13+
{ name: "green", hex: "#51cd00" },
14+
{ name: "turquoise", hex: "#00c79a" },
15+
{ name: "blue", hex: "#37adff" },
16+
{ name: "purple", hex: "#af51f5" },
17+
];
18+
19+
@Component({
20+
selector: "app-change-color-dialog",
21+
templateUrl: "./change-color-dialog.component.html",
22+
styleUrls: ["./change-color-dialog.component.scss"],
23+
encapsulation: ViewEncapsulation.None,
24+
})
25+
export class ChangeColorDialogComponent implements OnInit {
26+
@Input()
27+
public session: Session;
28+
29+
public colors = containerColors;
30+
public selectedColor: string;
31+
32+
constructor(
33+
private readonly appService: AppService,
34+
private readonly appProviderService: AppProviderService,
35+
private readonly messageToasterService: MessageToasterService
36+
) {}
37+
38+
ngOnInit(): void {
39+
this.selectedColor = this.session.color ?? null;
40+
}
41+
42+
closeModal(): void {
43+
this.appService.closeModal();
44+
}
45+
46+
selectColor(colorName: string): void {
47+
this.selectedColor = colorName;
48+
}
49+
50+
saveColor(): void {
51+
if (this.selectedColor) {
52+
this.session.color = this.selectedColor;
53+
this.appProviderService.repository.updateSession(this.session.sessionId, this.session);
54+
this.appProviderService.behaviouralSubjectService.setSessions(this.appProviderService.repository.getSessions());
55+
this.messageToasterService.toast("Color has been changed!", ToastLevel.success, "Color changed!");
56+
this.closeModal();
57+
}
58+
}
59+
}

packages/desktop-app/src/app/components/sessions/session-card/session-card.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
class="moon-Hover-{{session.status !== eSessionStatus.active && session.status !== eSessionStatus.pending ? 'Start' : 'Stop'}} moon-hover-session hover-item"
1010
(click)="session.status === eSessionStatus.active || session.status === eSessionStatus.pending ? stopSession() : startSession()"></i>
1111
<span class="{{session.status === eSessionStatus.active ? 'strong' : ''}}">{{$any(session)?.awsAccount ? $any(session)?.awsAccount?.accountName : session.sessionName}}</span>
12+
<span *ngIf="getSessionColorHex()" class="session-color-dot" [style.background-color]="getSessionColorHex()"></span>
1213
<i class="moon-Pin" *ngIf="optionService.pinned.indexOf(session.sessionId) !== -1"></i>
1314
</div>
1415
</td>

packages/desktop-app/src/app/components/sessions/session-card/session-card.component.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ td:nth-child(4) {
266266
left: -65px !important;
267267
}
268268

269+
.session-color-dot {
270+
display: inline-block;
271+
width: 8px;
272+
height: 8px;
273+
border-radius: 50%;
274+
margin-left: 6px;
275+
flex-shrink: 0;
276+
}
277+
269278
.session-name-td {
270279
height: inherit;
271280
overflow: hidden;

0 commit comments

Comments
 (0)