Skip to content

Commit 8ced838

Browse files
rfontanarosagino-m
andauthored
Hide Job/Loi Menu when no Lois are available + Various fixes (#2150)
Co-authored-by: Gino Miceli <[email protected]>
1 parent 1af002e commit 8ced838

File tree

7 files changed

+121
-101
lines changed

7 files changed

+121
-101
lines changed

web/src/app/components/job-list-item/_job-list-item.component-theme.scss

+5-10
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
@use '@angular/material' as mat;
33

44
@mixin color($theme) {
5-
.expandable-node-start {
5+
.job-name, .loi-name {
66
color: mat.get-theme-color($theme, on-surface-variant);
7-
8-
.job-name {
9-
color: mat.get-theme-color($theme, on-surface-variant);
10-
}
117
}
128

139
.tree-node-selected {
@@ -21,12 +17,11 @@
2117
.mat-tree {
2218
--mat-tree-container-background-color: #{mat.get-theme-color($theme, surface-container)};
2319

24-
.mat-mdc-unelevated-button {
25-
background-color: mat.get-theme-color($theme, surface-container);
20+
.mat-tree-node {
21+
min-height: 36px;
2622
}
2723

28-
.loi-tree-node{
29-
color: mat.get-theme-color($theme, on-surface-variant);
24+
.loi-tree-node {
3025
&:hover {
3126
color: mat.get-theme-color($theme, on-secondary-container);
3227
background-color: rgba(mat.get-theme-color($theme, on-surface), 0.12);
@@ -36,7 +31,7 @@
3631
}
3732

3833
@mixin typography($theme) {
39-
.expandable-node-start, .loi-name {
34+
.job-name, .loi-name {
4035
font: mat.get-theme-typography($theme, label-large, font);
4136
}
4237
}

web/src/app/components/job-list-item/job-list-item.component.html

+75-50
Original file line numberDiff line numberDiff line change
@@ -17,68 +17,93 @@
1717
<div class="job-list-item-container">
1818
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
1919
<!-- Tree node for lois -->
20-
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding [class.tree-node-selected]="isSelectedLoi(node)"
21-
class="loi-tree-node" role="button" tabindex="0" mat-button (click)="selectLoi(node)"
22-
[style.padding-left]="isSidePanelExpanded() ? '40px' : '16px'">
23-
<mat-icon svgIcon="{{ node.iconName }}" class="{{ node.jobId }} loi-icon" [ngStyle]="{color: node.iconColor}"
24-
[style.padding-left]="isSidePanelExpanded() ? '10px' : '0'"></mat-icon>
25-
<div class="loi-name" *ngIf="isSidePanelExpanded()">
26-
{{ node.name }}
27-
</div>
28-
</mat-tree-node>
29-
<!-- Tree node for jobs -->
3020
<mat-tree-node
21+
*matTreeNodeDef="let node"
22+
matTreeNodePadding
23+
mat-button
24+
class="loi-tree-node"
25+
tabindex="0"
26+
role="button"
27+
(click)="selectLoi(node)"
3128
[class.tree-node-selected]="isSelectedLoi(node)"
32-
*matTreeNodeDef="let node; when: hasChild"
33-
matTreeNodePadding class="expandable-node"
29+
[style.padding-left]="isSidePanelExpanded() ? '50px' : '0px'"
3430
>
35-
<div class="expandable-node-start" *ngIf="isSidePanelExpanded()">
31+
<ng-container *ngIf="isSidePanelExpanded()">
32+
<mat-icon svgIcon="{{ node.iconName }}" class="loi-icon" [ngStyle]="{color: node.iconColor}"></mat-icon>
33+
34+
<div class="loi-name">{{ node.name }}</div>
35+
</ng-container>
36+
37+
<ng-container *ngIf="!isSidePanelExpanded()">
3638
<button mat-icon-button [attr.aria-label]="'Toggle ' + node.item" matTreeNodeToggle>
37-
<mat-icon class="mat-icon-rtl-mirror">
38-
chevron_right
39-
</mat-icon>
39+
<mat-icon svgIcon="{{ node.iconName }}" class="loi-icon" [ngStyle]="{color: node.iconColor}"></mat-icon>
4040
</button>
41+
</ng-container>
42+
</mat-tree-node>
43+
<!-- Tree node for jobs -->
44+
<mat-tree-node
45+
*matTreeNodeDef="let node; when: isJob"
46+
matTreeNodePadding
47+
class="job-tree-node"
48+
>
49+
<ng-container *ngIf="isSidePanelExpanded()">
50+
<ng-container *ngIf="hasChild(node)">
51+
<button mat-icon-button [attr.aria-label]="'Toggle ' + node.item" matTreeNodeToggle>
52+
<mat-icon class="mat-icon-rtl-mirror">
53+
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
54+
</mat-icon>
55+
</button>
56+
</ng-container>
4157

42-
<mat-icon class="job-icon" [ngStyle]="{color: node.iconColor}">
43-
{{ node.iconName }}
44-
</mat-icon>
58+
<ng-container *ngIf="!hasChild(node)">
59+
<div style="width: 40px; visibility: hidden;"></div>
60+
</ng-container>
4561

46-
<div class="job-name">{{ node.name }}</div>
47-
</div>
62+
<div class="job-tree-node-label">
63+
<ng-container *ngTemplateOutlet="jobLabel; context: { node: node }"></ng-container>
64+
</div>
65+
66+
<div [ngSwitch]="actionsType">
67+
<div *ngSwitchCase="jobListItemActionsType.MENU">
68+
<button mat-icon-button [matMenuTriggerFor]="jobMenu">
69+
<mat-icon>more_vert</mat-icon>
70+
</button>
71+
<mat-menu #jobMenu="matMenu">
72+
<a (click)="onDownloadCsvClick()" target="_blank">
73+
<button mat-menu-item>
74+
<span>Download job data (CSV)</span>
75+
</button>
76+
</a>
77+
<a (click)="onDownloadGeoJsonClick()" target="_blank">
78+
<button mat-menu-item>
79+
<span>Download site locations (GeoJSON)</span>
80+
</button>
81+
</a>
82+
</mat-menu>
83+
</div>
84+
<div *ngSwitchCase="jobListItemActionsType.BACK">
85+
<button mat-icon-button aria-label="back" (click)="onGoBackClick()">
86+
<mat-icon>close</mat-icon>
87+
</button>
88+
</div>
89+
</div>
90+
</ng-container>
4891

49-
<div class="expandable-node-start" *ngIf="!isSidePanelExpanded()">
92+
<ng-container *ngIf="!isSidePanelExpanded()">
5093
<button mat-icon-button [attr.aria-label]="'Toggle ' + node.item" matTreeNodeToggle>
51-
<mat-icon class="job-icon" [ngStyle]="{color: node.iconColor}"
52-
(click)="treeControl.toggle(node)">
94+
<mat-icon class="job-icon" [ngStyle]="{color: node.iconColor}">
5395
{{ node.iconName }}
5496
</mat-icon>
5597
</button>
56-
</div>
57-
58-
<div [ngSwitch]="actionsType" *ngIf="isSidePanelExpanded()">
59-
<div *ngSwitchCase="jobListItemActionsType.MENU">
60-
<button mat-icon-button [matMenuTriggerFor]="jobMenu">
61-
<mat-icon>more_vert</mat-icon>
62-
</button>
63-
<mat-menu #jobMenu="matMenu">
64-
<a (click)="onDownloadCsvClick()" target="_blank">
65-
<button mat-menu-item>
66-
<span>Download job data (CSV)</span>
67-
</button>
68-
</a>
69-
<a (click)="onDownloadGeoJsonClick()" target="_blank">
70-
<button mat-menu-item>
71-
<span>Download site locations (GeoJSON)</span>
72-
</button>
73-
</a>
74-
</mat-menu>
75-
</div>
76-
<div *ngSwitchCase="jobListItemActionsType.BACK">
77-
<button mat-icon-button aria-label="back" (click)="onGoBackClick()">
78-
<mat-icon>close</mat-icon>
79-
</button>
80-
</div>
81-
</div>
98+
</ng-container>
8299
</mat-tree-node>
83100
</mat-tree>
84101
</div>
102+
103+
<ng-template #jobLabel let-node="node">
104+
<mat-icon class="job-icon" [ngStyle]="{color: node.iconColor}">
105+
{{ node.iconName }}
106+
</mat-icon>
107+
108+
<div class="job-name">{{ node.name }}</div>
109+
</ng-template>

web/src/app/components/job-list-item/job-list-item.component.scss

+9-17
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,24 @@
1414
* limitations under the License.
1515
*/
1616

17-
.job-list-item-container {
18-
padding: 2px 0;
19-
}
20-
2117
::ng-deep .mat-mdc-list .mat-mdc-list-item .mat-line {
2218
word-wrap: break-word !important;
2319
white-space: pre-wrap !important;
2420
}
2521

26-
.expandable-node {
22+
.job-list-item-container {
23+
margin-bottom: 8px;
24+
}
25+
26+
.job-tree-node {
2727
display: flex;
28-
justify-content: space-between;
2928

30-
.expandable-node-start {
29+
.job-tree-node-label {
30+
min-width: 0;
3131
display: flex;
3232
align-items: center;
33-
min-width: 0;
34-
35-
.job-icon {
36-
padding-right: 16px;
37-
}
33+
gap: 8px;
34+
flex: 1;
3835

3936
.job-name {
4037
flex: 1;
@@ -54,11 +51,6 @@
5451
border-radius: 24px;
5552
cursor: pointer;
5653

57-
.loi-icon {
58-
width: 20px;
59-
height: 20px;
60-
}
61-
6254
.loi-name {
6355
flex: 1;
6456
padding-left: 16px;

web/src/app/components/job-list-item/job-list-item.component.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ describe('JobListItemComponent', () => {
207207
loader = TestbedHarnessEnvironment.loader(fixture);
208208

209209
surveyId$.next(surveyId);
210+
lois$.next(List([]));
210211
});
211212

212213
it('should create', () => {

web/src/app/components/job-list-item/job-list-item.component.ts

+23-19
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ export class JobListItemComponent implements OnInit, OnDestroy {
4545
subscription: Subscription = new Subscription();
4646
treeControl: FlatTreeControl<DynamicFlatNode>;
4747
dataSource: DynamicDataSource;
48-
lois: List<LocationOfInterest> = List();
4948

5049
getLevel = (node: DynamicFlatNode) => node.level;
5150
isExpandable = (node: DynamicFlatNode) => node.expandable;
52-
hasChild = (_: number, _nodeData: DynamicFlatNode) => _nodeData.expandable;
51+
hasChild = (node: DynamicFlatNode) => node.childCount > 0;
52+
isJob = (_: number, node: DynamicFlatNode) => node.level === 0;
5353

5454
constructor(
5555
private sanitizer: DomSanitizer,
@@ -82,18 +82,13 @@ export class JobListItemComponent implements OnInit, OnDestroy {
8282
this.surveyId = id;
8383
})
8484
);
85-
86-
// Add initial node for current job
87-
this.dataSource.data = this.dataSource.data.concat([
88-
new DynamicFlatNode(
89-
/* name= */ this.job!.name!,
90-
/* level= */ 0,
91-
/* expandable= */ true,
92-
/* iconName= */ 'label',
93-
/* iconColo= */ this.job!.color!,
94-
/* jobId= */ this.job!.id
95-
),
96-
]);
85+
this.subscription.add(
86+
this.loiService.getLocationsOfInterest$().subscribe(lois => {
87+
this.dataSource.data = this.dataSource.data.concat([
88+
this.createJobNode(this.job!, lois),
89+
]);
90+
})
91+
);
9792
}
9893

9994
ngOnChanges() {
@@ -130,16 +125,25 @@ export class JobListItemComponent implements OnInit, OnDestroy {
130125
);
131126
}
132127

133-
isSelectedLoi(node: DynamicFlatNode): boolean {
134-
return node.loi?.id === this.loiId;
128+
createJobNode(job: Job, lois: List<LocationOfInterest>): DynamicFlatNode {
129+
return new DynamicFlatNode(
130+
/* name= */ job!.name!,
131+
/* level= */ 0,
132+
/* expandable= */ true,
133+
/* iconName= */ 'label',
134+
/* iconColo= */ job!.color!,
135+
/* jobId= */ job!.id,
136+
/* isJob= */ true,
137+
/* childCount= */ lois.filter(loi => loi.jobId === this.job?.id).size
138+
);
135139
}
136140

137-
isLoiNode(node: DynamicFlatNode): boolean {
138-
return node.loi ? true : false;
141+
isSelectedLoi(node: DynamicFlatNode): boolean {
142+
return node.loi?.id === this.loiId;
139143
}
140144

141145
selectLoi(node: DynamicFlatNode) {
142-
if (this.surveyId && this.isLoiNode(node)) {
146+
if (this.surveyId && !node.isJob) {
143147
this.navigationService.selectLocationOfInterest(
144148
this.surveyId,
145149
node.loi!.id

web/src/app/components/job-list-item/tree-data-source.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {List} from 'immutable';
2424
import {BehaviorSubject, Observable, Subscription, merge} from 'rxjs';
2525
import {map, shareReplay} from 'rxjs/operators';
2626

27-
import {GeometryType} from 'app/models/geometry/geometry';
2827
import {LocationOfInterest} from 'app/models/loi.model';
2928
import {LocationOfInterestService} from 'app/services/loi/loi.service';
3029
import {getLoiIcon} from 'app/utils/utils';
@@ -41,6 +40,8 @@ export class DynamicFlatNode {
4140
public iconName = '',
4241
public iconColor = '',
4342
public jobId: string,
43+
public isJob: boolean,
44+
public childCount: number,
4445
// Specific for nodes that represent lois.
4546
public loi?: LocationOfInterest
4647
) {}
@@ -129,6 +130,8 @@ export class DynamicDataSource implements DataSource<DynamicFlatNode> {
129130
/* iconName= */ getLoiIcon(loi),
130131
/* iconColor= */ node.iconColor,
131132
/* jobId= */ 'undefined',
133+
/* isJob= */ false,
134+
/* childCount= */ 0,
132135
/* loi= */ loi
133136
);
134137
loiNodes.push(loiNode);

web/src/app/pages/main-page-container/main-page/side-panel/job-list/job-list.component.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
class="jobs"
2121
[ngClass]="{collapsed: !isSidePanelExpanded()}"
2222
>
23-
<div *ngFor="let entry of jobs; let i = index" class="job">
24-
<mat-divider *ngIf="i > 0"></mat-divider>
25-
<ground-job-list-item [job]="entry"></ground-job-list-item>
26-
</div>
23+
<ground-job-list-item
24+
*ngFor="let entry of jobs; let i = index; trackBy: trackById"
25+
[job]="entry"
26+
></ground-job-list-item>
2727
</mat-list>

0 commit comments

Comments
 (0)