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

NAS-133494 / 25.04 / WIP: Enclosure Colors #11345

Merged
merged 30 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
84f10df
NAS-133494: WIP enclosure color fixes
Jan 9, 2025
10a36ec
NAS-133494: Add color to mini-r lever element
Jan 9, 2025
118f506
NAS-133494: Make default svg drive tray colors persist
Jan 10, 2025
e2a0968
NAS-133494: Add es102g2 support and fix css collision with some other…
Jan 10, 2025
48e4acd
NAS-133494: Merged master
Jan 16, 2025
e31b980
NAS-133494: Remove unused styles
Jan 21, 2025
0458b9d
NAS-133494: Merge master
Jan 21, 2025
9adfc44
NAS-133494: Fix failed tests
Jan 21, 2025
1057679
NAS-133494: Store slot elements instead of always doing DOM query
Jan 24, 2025
0c29bc9
NAS-133494: r20 & r20b
Jan 26, 2025
b2571b0
NAS-133494: r10
Jan 26, 2025
3c347b6
NAS-133494: r20a
Jan 26, 2025
fbfe420
NAS-133494: r20a-rear: remove comment
Jan 26, 2025
f185ff0
NAS-133494: Use IDs to avoid css caching issues
Jan 26, 2025
52f3717
NAS-133494: R40
Jan 26, 2025
af80298
NAS-133494: R30
Jan 26, 2025
212ad93
NAS-133494: R50
Jan 26, 2025
493a81e
NAS-133494: Remove unused css rule
Jan 26, 2025
2db2113
NAS-133494: R50B
Jan 26, 2025
a903c2f
NAS-133494: R50BM
Jan 26, 2025
abf4f7c
NAS-133494: ES24N
Jan 26, 2025
0313509
NAS-133494: ES60
Jan 26, 2025
b8d6d77
NAS-133494: ES60_G2
Jan 26, 2025
4fbbb2b
NAS-133494: ES60G3
Jan 26, 2025
7154151
NAS-133494: ES102 G1
Jan 26, 2025
0c888a7
NAS-133494: F Series
Jan 26, 2025
110c8e7
NAS-133494: Desktop MINIs
Jan 27, 2025
8ea09b3
NAS-133494: Properly ensure svgContainer is present in resetDimValues()
Jan 31, 2025
bfcea80
NAS-133494: Add tint-target class to internal views like with R30
Jan 31, 2025
28935e1
Merge branch 'master' into NAS-133494
Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,31 +36,15 @@
}

&.selected {
fill-opacity: 0.7;
filter: brightness(1.2);
fill-opacity: 0;
stroke: var(--primary);
stroke-dasharray: none;
stroke-width: 1%;

&.tinted {
fill: var(--primary) !important;
}
stroke-width: 3px;
}

&.selected-vdev-disk {
filter: brightness(1.2);
stroke: white;
stroke-dasharray: none;
stroke-width: 4px;

&.tinted {
fill: var(--primary) !important;
}
}

&.not-selected-vdev-disk {
fill: black;
opacity: 0.5;
opacity: 0.25;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ describe('EnclosureSvgComponent', () => {
spectator.detectChanges();
}

function getTintTargets(slotNumber: number): SVGGElement[] {
const slotId: string = 'DRIVE_CAGE_' + slotNumber.toString();
const driveTrays = spectator.queryAll<SVGGElement>(`svg [id^=${slotId}] .tint-target`);

return driveTrays;
}

describe('svg is loaded', () => {
beforeEach(fakeAsync(() => {
mockGetBBox();
Expand Down Expand Up @@ -106,9 +113,14 @@ describe('EnclosureSvgComponent', () => {
expect(tintFn).toHaveBeenCalledTimes(2);
expect(tintFn).toHaveBeenNthCalledWith(1, { drive_bay_number: 1 });

const overlays = spectator.queryAll<SVGRectElement>('.overlay-rect');
expect(overlays[0].style.fill).toBe('red');
expect(overlays[1].style.fill).toBe('blue');
const slotOneTargets: SVGGElement[] = getTintTargets(1);
slotOneTargets.forEach((target) => {
expect(target.style.fill).toBe('red');
});
const slotTwoTargets: SVGGElement[] = getTintTargets(2);
slotTwoTargets.forEach((target) => {
expect(target.style.fill).toBe('blue');
});
});

it('adds overlays for every drive cage in an svg', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export type TintingFunction = (slot: DashboardEnclosureSlot) => string | null;
imports: [NgxSkeletonLoaderModule],
})
export class EnclosureSvgComponent implements OnDestroy {
readonly emptyOpacity = 0.15;
readonly unselectedOpacity = 0.3;
readonly svgUrl = input.required<string>();
readonly slots = input.required<DashboardEnclosureSlot[]>();
readonly enableMouseEvents = input(true);
Expand All @@ -55,6 +57,7 @@ export class EnclosureSvgComponent implements OnDestroy {
protected svgContainer = viewChild<ElementRef<HTMLElement>>('svgContainer');

private overlayRects: Record<number, SVGRectElement> = {};
private slotElements: Record<number, SVGGElement> = {};

constructor(
private renderer: Renderer2,
Expand Down Expand Up @@ -105,6 +108,7 @@ export class EnclosureSvgComponent implements OnDestroy {
return;
}

this.slotElements[slot.drive_bay_number] = tray;
this.addOverlay(slot, tray);

if (this.enableMouseEvents()) {
Expand Down Expand Up @@ -133,6 +137,7 @@ export class EnclosureSvgComponent implements OnDestroy {
});

private clearSelectionStylesFromAllSlots(): void {
this.resetDimValues();
Object.values(this.overlayRects).forEach((overlay) => {
overlay.classList.remove('selected');
overlay.classList.remove('selected-vdev-disk');
Expand Down Expand Up @@ -162,8 +167,11 @@ export class EnclosureSvgComponent implements OnDestroy {
for (const slot of allSlots) {
if (slot.dev && selectedVdevDisks.includes(slot.dev)) {
this.renderer.addClass(this.overlayRects[slot.drive_bay_number], 'selected-vdev-disk');
if (slot.type) {
this.dimSlot(slot.drive_bay_number, 1);
}
} else if (slot.drive_bay_number !== selectedSlot.drive_bay_number) {
this.renderer.addClass(this.overlayRects[slot.drive_bay_number], 'not-selected-vdev-disk');
this.dimSlot(slot.drive_bay_number, this.unselectedOpacity);
}
}
}
Expand Down Expand Up @@ -246,25 +254,63 @@ export class EnclosureSvgComponent implements OnDestroy {
const prevSlotExists = !!selectedSlot;

if (!isNewSlotEmpty && prevSlotExists && slot.dev === selectedSlot.dev) {
this.selectedSlot.set(null);
return;
}

this.selectedSlot.set(slot);
};

private addTint(slot: DashboardEnclosureSlot): void {
const overlay = this.overlayRects[slot.drive_bay_number];
const tintTargets: NodeListOf<SVGGElement> = this.getTintTargets(slot.drive_bay_number);
const slotTint = this.slotTintFn()(slot);

if (slotTint) {
tintTargets.forEach((tintTarget: SVGGElement) => {
this.renderer.addClass(tintTarget, 'tinted');
this.renderer.setStyle(tintTarget, 'fill', slotTint);
this.renderer.setStyle(tintTarget, 'filter', 'brightness(1.25)');
});
this.dimSlot(slot.drive_bay_number, 1);
} else {
tintTargets.forEach((tintTarget: SVGGElement) => {
this.renderer.removeClass(tintTarget, 'tinted');
this.renderer.setStyle(tintTarget, 'fill', null);
this.renderer.setStyle(tintTarget, 'filter', 'brightness(1)');
});
this.dimSlot(slot.drive_bay_number, this.emptyOpacity);
}
}

this.renderer.removeClass(overlay, 'tinted');
private dimSlot(slotNumber: number, opacity: number): void {
this.renderer.setStyle(this.slotElements[slotNumber], 'opacity', opacity.toString());
}

const slotTint = this.slotTintFn()?.(slot);
if (!slotTint) {
private resetDimValues(): void {
const svgContainer = this.svgContainer();
if (!svgContainer || !this.svg()) {
return;
}

this.renderer.addClass(overlay, 'tinted');
this.renderer.setStyle(overlay, 'fill', slotTint);
const driveTrays = this.svgContainer().nativeElement.querySelectorAll<SVGGElement>('svg [id^="DRIVE_CAGE_"]');
driveTrays.forEach((tray) => {
const slot = this.getSlotForTray(tray);
if (!slot) {
return;
}

if (!slot.dev) {
this.dimSlot(slot.drive_bay_number, this.emptyOpacity);
} else {
this.dimSlot(slot.drive_bay_number, 1);
}
});
}

private getTintTargets(slotNumber: number): NodeListOf<SVGGElement> {
const slotId: string = 'DRIVE_CAGE_' + slotNumber.toString();
const tintTargets = this.slotElements[slotNumber].querySelectorAll<SVGGElement>(`svg [id^=${slotId}] .tint-target`);

return tintTargets;
}

private getSlotForTray(tray: SVGGElement): DashboardEnclosureSlot | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
>
@for (slot of slots(); track slot.drive_bay_number) {
<a
class="slot"
class="slot tint-target"
[class.selected]="slot.drive_bay_number === selectedSlot()?.drive_bay_number"
[class.static]="!enableMouseEvents()"
[ixTest]="['enclosure-slot', slot.drive_bay_number]"
Expand Down
Loading
Loading