Skip to content

Commit 817f770

Browse files
authored
fix: adding layout trigger to titled container (#352)
* fix: adding layout trigger to titled container - Triggering layout initialization at the time of creation rather than after view init. * refactor: remove delay from set Timeout * refactor: initializing on init * refactor: fixing lint and test - moving dashboard provides to an exported variable - This would make it easier to provide essential services without being too verbose in every test - Needed to provide LayoutChangeService with me current change as we added it in the titled content component - Also, this fixes the navigation$ pipe console warning which usually comes during test runs
1 parent 41e011d commit 817f770

23 files changed

+206
-295
lines changed

projects/common/src/layout/layout-change.service.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ export class LayoutChangeService implements OnDestroy {
2020
@SkipSelf() @Optional() private readonly parentLayoutChange?: LayoutChangeService
2121
) {
2222
this.boundingElement = hostElementRef.nativeElement;
23-
// Get layout changes from our parent LayoutChangeService, or if it's root, collect from window
24-
const parentChange$ = this.parentLayoutChange
25-
? this.parentLayoutChange.layoutChangeSubject
26-
: this.getWindowResizeEvents();
2723

2824
// Filter out layout changes from our parent if we didn't change size
29-
parentChange$.pipe(filter(event => this.hasLayoutChanged(event))).subscribe(this.layoutChangeSubject);
25+
(this.parentLayoutChange?.getLayoutChangeEventObservable() ?? this.getWindowResizeEvents())
26+
.pipe(filter(event => this.hasLayoutChanged(event)))
27+
.subscribe(this.layoutChangeSubject);
28+
}
29+
30+
public getLayoutChangeEventObservable(): Observable<LayoutChangeEvent> {
31+
return this.layoutChangeSubject;
3032
}
3133

3234
public publishLayoutChange(): void {
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import { AfterViewInit, Directive, EventEmitter, Output } from '@angular/core';
1+
import { Directive, EventEmitter, Output } from '@angular/core';
22
import { LayoutChangeService, SubscriptionLifecycle } from '@hypertrace/common';
33

44
@Directive({
55
selector: '[htLayoutChange]',
66
providers: [SubscriptionLifecycle, LayoutChangeService]
77
})
8-
export class LayoutChangeDirective implements AfterViewInit {
8+
export class LayoutChangeDirective {
99
@Output('htLayoutChange')
1010
public readonly changeEmitter: EventEmitter<void> = new EventEmitter();
1111

1212
public constructor(private readonly layoutChange: LayoutChangeService, subscriptionLifecycle: SubscriptionLifecycle) {
1313
subscriptionLifecycle.add(layoutChange.layout$.subscribe(this.changeEmitter));
14-
}
15-
16-
public ngAfterViewInit(): void {
1714
this.layoutChange.initialize();
1815
}
1916
}

projects/components/src/titled-content/titled-content.component.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
width: 100%;
88

99
.header {
10+
max-height: 28px;
1011
display: flex;
1112
flex-direction: row;
1213
align-items: center;
@@ -31,7 +32,7 @@
3132
}
3233

3334
.content {
34-
flex: 1 1;
35+
flex: 1 1 auto;
3536
overflow: hidden;
3637
}
3738

projects/components/src/titled-content/titled-content.component.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { fakeAsync } from '@angular/core/testing';
2-
import { NavigationService } from '@hypertrace/common';
2+
import { LayoutChangeService, NavigationService } from '@hypertrace/common';
33
import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
4+
import { MockDirective } from 'ng-mocks';
5+
import { LayoutChangeTriggerDirective } from '../layout/layout-change-trigger.directive';
46
import { TitledContentComponent } from './titled-content.component';
57
import { TitledContentModule } from './titled-content.module';
68

@@ -11,6 +13,8 @@ describe('Titled content component', () => {
1113
declareComponent: false,
1214
component: TitledContentComponent,
1315
imports: [TitledContentModule],
16+
declarations: [MockDirective(LayoutChangeTriggerDirective)],
17+
componentProviders: [LayoutChangeService],
1418
providers: [mockProvider(NavigationService)]
1519
});
1620

projects/components/src/titled-content/titled-content.component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { TitledHeaderControlDirective } from './header-controls/titled-header-co
1010
changeDetection: ChangeDetectionStrategy.OnPush,
1111
template: `
1212
<div class="titled-content-container">
13-
<div class="header">
13+
<div class="header" [htLayoutChangeTrigger]="this.shouldShowHeader">
1414
<ht-label *ngIf="this.shouldShowTitleInHeader" [label]="this.title" class="title"></ht-label>
1515
<ht-link [paramsOrUrl]="this.link" class="link" *ngIf="this.link">
1616
<ht-button
@@ -51,6 +51,10 @@ export class TitledContentComponent {
5151
@Input()
5252
public linkLabel?: string;
5353

54+
public get shouldShowHeader(): boolean {
55+
return this.shouldShowTitleInHeader || this.headerControl !== undefined;
56+
}
57+
5458
private get shouldShowTitle(): boolean {
5559
return !isEmpty(this.title) && !this.hideTitle;
5660
}

projects/components/src/titled-content/titled-content.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { CommonModule } from '@angular/common';
22
import { NgModule } from '@angular/core';
33
import { ButtonModule } from '../button/button.module';
44
import { LabelModule } from '../label/label.module';
5+
import { LayoutChangeModule } from '../layout/layout-change.module';
56
import { LinkModule } from '../link/link.module';
67
import { TitledHeaderControlDirective } from './header-controls/titled-header-control.directive';
78
import { TitledContentComponent } from './titled-content.component';
89

910
@NgModule({
1011
declarations: [TitledContentComponent, TitledHeaderControlDirective],
1112
exports: [TitledContentComponent, TitledHeaderControlDirective],
12-
imports: [LabelModule, CommonModule, LinkModule, ButtonModule]
13+
imports: [LabelModule, CommonModule, LinkModule, ButtonModule, LayoutChangeModule]
1314
})
1415
export class TitledContentModule {}

projects/dashboards/src/test/dashboard-verification.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { StaticProvider } from '@angular/core';
12
import { ActivatedRoute } from '@angular/router';
23
import {
34
ColorService,
5+
LayoutChangeService,
46
NavigationService,
57
RelativeTimeRange,
68
TimeDuration,
@@ -10,7 +12,7 @@ import {
1012
import { MetadataService } from '@hypertrace/distributed-tracing';
1113
import { GraphQlRequestService } from '@hypertrace/graphql-client';
1214
import { ModelJson } from '@hypertrace/hyperdash';
13-
import { DashboardManagerService, LoggerService } from '@hypertrace/hyperdash-angular';
15+
import { DashboardManagerService, LoggerService, RENDERER_API } from '@hypertrace/hyperdash-angular';
1416
import { getMockFlexLayoutProviders } from '@hypertrace/test-utils';
1517
import { mockProvider, Spectator } from '@ngneat/spectator/jest';
1618
import { EMPTY, of } from 'rxjs';
@@ -32,6 +34,9 @@ export const isValidModelJson = (
3234
export const mockDashboardProviders = [
3335
mockProvider(GraphQlRequestService),
3436
mockProvider(ColorService),
37+
mockProvider(LayoutChangeService, {
38+
layout$: of()
39+
}),
3540
mockProvider(TimeRangeService, {
3641
getTimeRangeAndChanges: () => EMPTY,
3742
getCurrentTimeRange: jest.fn().mockReturnValue(new RelativeTimeRange(new TimeDuration(15, TimeUnit.Minute)))
@@ -53,3 +58,31 @@ export const mockDashboardProviders = [
5358
}),
5459
...getMockFlexLayoutProviders()
5560
];
61+
62+
export const rendererApiFactoryBuilder = <TModel extends object>(model: TModel) => () => ({
63+
getTimeRange: jest.fn(),
64+
model: model,
65+
change$: EMPTY,
66+
dataRefresh$: EMPTY,
67+
timeRangeChanged$: EMPTY
68+
});
69+
70+
export const mockDashboardWidgetProviders: <T extends object>(model: T) => StaticProvider[] = model => [
71+
{
72+
provide: RENDERER_API,
73+
useFactory: rendererApiFactoryBuilder(model)
74+
},
75+
mockProvider(GraphQlRequestService, {
76+
query: jest.fn(() => EMPTY)
77+
}),
78+
mockProvider(ColorService),
79+
mockProvider(LayoutChangeService, {
80+
getLayoutChangeEventObservable: jest.fn().mockReturnValue(of({})),
81+
layout$: of()
82+
}),
83+
mockProvider(NavigationService, {
84+
navigation$: EMPTY,
85+
getAllValuesForQueryParameter: () => []
86+
}),
87+
...getMockFlexLayoutProviders()
88+
];

projects/dashboards/src/widgets/divider/divider-widget-renderer.component.test.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,13 @@
1-
import { RENDERER_API } from '@hypertrace/hyperdash-angular';
21
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
3-
import { EMPTY } from 'rxjs';
2+
import { mockDashboardWidgetProviders } from '../../test/dashboard-verification';
43
import { DividerWidgetRendererComponent } from './divider-widget-renderer.component';
54

65
describe('Divider Widget Renderer Component', () => {
76
let spectator: Spectator<DividerWidgetRendererComponent>;
87

98
const createComponent = createComponentFactory<DividerWidgetRendererComponent>({
109
component: DividerWidgetRendererComponent,
11-
providers: [
12-
{
13-
provide: RENDERER_API,
14-
useFactory: () => ({
15-
model: {},
16-
getTimeRange: jest.fn(),
17-
change$: EMPTY,
18-
dataRefresh$: EMPTY,
19-
timeRangeChanged$: EMPTY
20-
})
21-
}
22-
],
10+
providers: [...mockDashboardWidgetProviders({})],
2311
shallow: true
2412
});
2513

projects/dashboards/src/widgets/greeting-label/greeting-label-widget-renderer.component.test.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { GreetingLabelComponent } from '@hypertrace/components';
2-
import { RENDERER_API } from '@hypertrace/hyperdash-angular';
32
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
4-
import { EMPTY } from 'rxjs';
3+
import { mockDashboardWidgetProviders } from '../../test/dashboard-verification';
54
import { GreetingLabelWidgetRendererComponent } from './greeting-label-widget-renderer.component';
65
import { GreetingLabelWidgetModel } from './greeting-label-widget.model';
76

@@ -11,19 +10,7 @@ describe('Greeting label widget renderer component', () => {
1110
const createComponent = createComponentFactory<GreetingLabelWidgetRendererComponent>({
1211
component: GreetingLabelWidgetRendererComponent,
1312
entryComponents: [GreetingLabelComponent],
14-
providers: [
15-
{
16-
provide: RENDERER_API,
17-
useFactory: () => ({
18-
model: mockModel,
19-
getDataFromModelDataSource: EMPTY,
20-
getTimeRange: jest.fn(),
21-
change$: EMPTY,
22-
dataRefresh$: EMPTY,
23-
timeRangeChanged$: EMPTY
24-
})
25-
}
26-
]
13+
providers: [...mockDashboardWidgetProviders(mockModel)]
2714
});
2815

2916
beforeEach(() => {

projects/dashboards/src/widgets/link/link-widget-renderer.component.test.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { RENDERER_API } from '@hypertrace/hyperdash-angular';
21
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
3-
import { EMPTY } from 'rxjs';
2+
import { mockDashboardWidgetProviders } from '../../test/dashboard-verification';
43
import { LinkWidgetRendererComponent } from './link-widget-renderer.component';
54
import { LinkWidgetModel } from './link-widget.model';
65

@@ -9,18 +8,6 @@ describe('Link widget renderer component', () => {
98
let mockModel: Partial<LinkWidgetModel> = {};
109
const createComponent = createComponentFactory<LinkWidgetRendererComponent>({
1110
component: LinkWidgetRendererComponent,
12-
providers: [
13-
{
14-
provide: RENDERER_API,
15-
useFactory: () => ({
16-
model: mockModel,
17-
getTimeRange: jest.fn(),
18-
change$: EMPTY,
19-
dataRefresh$: EMPTY,
20-
timeRangeChanged$: EMPTY
21-
})
22-
}
23-
],
2411
shallow: true
2512
});
2613

@@ -31,15 +18,19 @@ describe('Link widget renderer component', () => {
3118
test('Link should be displayed as expected if url and displayText are defined', () => {
3219
mockModel.url = '#';
3320
mockModel.displayText = 'Test';
34-
spectator = createComponent();
21+
spectator = createComponent({
22+
providers: [...mockDashboardWidgetProviders(mockModel)]
23+
});
3524

3625
expect(spectator.query('ht-link')).toExist();
3726
expect(spectator.component.getDisplayText()).toEqual('Test');
3827
});
3928

4029
test('Link should use url as displayText if displayText is undefined', () => {
4130
mockModel.url = '#';
42-
spectator = createComponent();
31+
spectator = createComponent({
32+
providers: [...mockDashboardWidgetProviders(mockModel)]
33+
});
4334

4435
expect(spectator.query('ht-link')).toExist();
4536
expect(spectator.component.getDisplayText()).toEqual(mockModel.url);

0 commit comments

Comments
 (0)