Skip to content

Commit fc9cbcd

Browse files
Jan Kaiserhonzikec
authored andcommitted
wip: issues tab
1 parent b04e937 commit fc9cbcd

22 files changed

Lines changed: 574 additions & 57 deletions

angular-ngrx-scss/src/app/fixtures/repository.fixtures.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {
2-
PR_STATE,
2+
ISSUE_STATE,
33
PullRequestAPIResponse,
44
PullRequestItemAPIResponse,
5-
PullRequestLabel,
5+
IssueLabel,
66
RepoPullRequests,
77
} from '../state/repository';
88

99
export const generatePullRequestAPIResponseFixture = (
10-
state: PR_STATE = 'open',
10+
state: ISSUE_STATE = 'open',
1111
): PullRequestAPIResponse => {
1212
const closedDate = new Date(2022, 2, 1).toISOString();
1313
return {
@@ -34,7 +34,7 @@ export const generatePullRequestAPIResponseFixture = (
3434
labels: [
3535
{
3636
name: 'bugs',
37-
} as PullRequestLabel,
37+
} as IssueLabel,
3838
],
3939
comments: 305,
4040
} as PullRequestItemAPIResponse,

angular-ngrx-scss/src/app/issues/components/issues-header/issues-header.component.html

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
<div class="filters-container">
22
<div class="issue-status">
3-
<a href="" class="active">
4-
<span class="icon" appOcticon="no-entry" size="16"></span>
5-
<span>412 Open</span>
6-
</a>
7-
<a href="">
3+
<button [ngClass]="{ active: viewState === 'open' }" (click)="selectOpen()">
84
<span class="icon" appOcticon="check" size="16"></span
9-
><span>4877 Open</span></a
5+
><span>{{ openIssues?.total ?? 0 }} Open</span>
6+
</button>
7+
<button
8+
[ngClass]="{ active: viewState === 'closed' }"
9+
(click)="selectClosed()"
1010
>
11+
<span class="icon" appOcticon="no-entry" size="16"></span>
12+
<span>{{ closedIssues?.total ?? 0 }} Closed</span>
13+
</button>
1114
</div>
1215
<div class="issue-filters">
1316
<app-filter-dropdown
1417
name="Label"
1518
description="Select label"
1619
[isRepo]="true"
20+
[items]="(labels$ | async) || []"
1721
></app-filter-dropdown>
1822
<app-filter-dropdown
1923
name="Milestones"
2024
description="Select milestone"
2125
[isRepo]="true"
26+
[items]="(milestones$ | async) || []"
2227
></app-filter-dropdown>
2328
<app-filter-dropdown
2429
name="Sort"

angular-ngrx-scss/src/app/issues/components/issues-header/issues-header.component.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
gap: 1rem;
2222
color: variables.$gray600;
2323

24-
a {
24+
button {
2525
color: inherit;
26+
border: none;
27+
cursor: pointer;
2628

2729
.icon {
2830
margin-right: 0.375rem;
Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,56 @@
1-
import { Component } from '@angular/core';
1+
import { Component, EventEmitter, Input, Output } from '@angular/core';
2+
import { Store } from '@ngrx/store';
3+
import { Observable, map } from 'rxjs';
4+
import { FilterOption } from 'src/app/shared/components/filter-dropdown/filter-dropdown.component';
5+
import {
6+
ISSUE_STATE,
7+
RepoIssues,
8+
selectLabels,
9+
selectMilestones,
10+
} from 'src/app/state/repository';
211

312
@Component({
413
selector: 'app-issues-header',
514
templateUrl: './issues-header.component.html',
615
styleUrls: ['./issues-header.component.scss'],
716
})
8-
export class IssuesHeaderComponent {}
17+
export class IssuesHeaderComponent {
18+
milestones$: Observable<FilterOption[]> = this.store
19+
.select(selectMilestones)
20+
.pipe(
21+
map((milestones) =>
22+
milestones.map((milestone) => ({
23+
label: milestone.title,
24+
value: milestone.title,
25+
})),
26+
),
27+
);
28+
29+
labels$: Observable<FilterOption[]> = this.store
30+
.select(selectLabels)
31+
.pipe(
32+
map((labels) =>
33+
labels.map((label) => ({ label: label.name, value: label.name })),
34+
),
35+
);
36+
37+
@Input() viewState: ISSUE_STATE = 'open';
38+
39+
@Input()
40+
openIssues: RepoIssues | null = null;
41+
42+
@Input()
43+
closedIssues: RepoIssues | null = null;
44+
45+
@Output() viewStateChange = new EventEmitter<ISSUE_STATE>();
46+
47+
constructor(private store: Store) {}
48+
49+
selectOpen() {
50+
this.viewStateChange.emit('open');
51+
}
52+
53+
selectClosed() {
54+
this.viewStateChange.emit('closed');
55+
}
56+
}

angular-ngrx-scss/src/app/issues/components/issues-list/issues-list.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="issue">
2-
<div class="issues-list-container">
3-
<ng-container *ngFor="let issue of issues">
2+
<div class="issues-list-container" *ngIf="issues">
3+
<ng-container *ngFor="let issue of issues.issues">
44
<app-repo-issue-pull-card [item]="issue"></app-repo-issue-pull-card>
55
</ng-container>
66
</div>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Component, Input } from '@angular/core';
22
import { Issue } from 'src/app/repository/services/repository.interfaces';
3+
import { RepoIssues } from 'src/app/state/repository';
34

45
@Component({
56
selector: 'app-issues-list',
67
templateUrl: './issues-list.component.html',
78
})
89
export class IssuesListComponent {
9-
@Input() issues: Issue[] = [];
10+
@Input() issues: RepoIssues | null = null;
1011
}
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
<div class="container issues-container">
2-
<app-issues-header></app-issues-header>
3-
<app-issues-list></app-issues-list>
2+
<app-issues-header
3+
[viewState]="viewState"
4+
[openIssues]="openIssues$ | async"
5+
[closedIssues]="closedIssues$ | async"
6+
(viewStateChange)="viewStateChange($event)"
7+
></app-issues-header>
8+
<app-issues-list
9+
[issues]="
10+
viewState === 'open' ? (openIssues$ | async) : (closedIssues$ | async)
11+
"
12+
></app-issues-list>
413
</div>
5-
<app-pagination></app-pagination>
14+
<app-pagination
15+
[params]="
16+
viewState === 'open'
17+
? (openIssuesPaginationParams$ | async)
18+
: (closedIssuesPaginationParams$ | async)
19+
"
20+
(pageChange)="pageChange($event)"
21+
></app-pagination>
Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,68 @@
11
import { Component } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { Store } from '@ngrx/store';
4+
import {
5+
ISSUE_STATE,
6+
fetchIssues,
7+
selectClosedIssuePaginationParams,
8+
selectClosedIssues,
9+
selectOpenIssuePaginationParams,
10+
selectOpenIssues,
11+
} from 'src/app/state/repository';
212

313
@Component({
414
selector: 'app-issues',
515
templateUrl: './issues.component.html',
616
styleUrls: ['./issues.component.scss'],
717
})
8-
export class IssuesComponent {}
18+
export class IssuesComponent {
19+
owner!: string;
20+
repoName!: string;
21+
openIssues$ = this.store.select(selectOpenIssues);
22+
closedIssues$ = this.store.select(selectClosedIssues);
23+
viewState: ISSUE_STATE = 'open';
24+
25+
openIssuesPaginationParams$ = this.store.select(
26+
selectOpenIssuePaginationParams,
27+
);
28+
closedIssuesPaginationParams$ = this.store.select(
29+
selectClosedIssuePaginationParams,
30+
);
31+
32+
constructor(private route: ActivatedRoute, private store: Store) {}
33+
34+
ngOnInit(): void {
35+
this.owner = this.route.snapshot.paramMap.get('owner') as string;
36+
this.repoName = this.route.snapshot.paramMap.get('repo') as string;
37+
38+
this.store.dispatch(
39+
fetchIssues({
40+
owner: this.owner,
41+
repoName: this.repoName,
42+
params: { state: 'open' },
43+
}),
44+
);
45+
46+
this.store.dispatch(
47+
fetchIssues({
48+
owner: this.owner,
49+
repoName: this.repoName,
50+
params: { state: 'closed' },
51+
}),
52+
);
53+
}
54+
55+
pageChange(page: number) {
56+
this.store.dispatch(
57+
fetchIssues({
58+
owner: this.owner,
59+
repoName: this.repoName,
60+
params: { state: this.viewState, page },
61+
}),
62+
);
63+
}
64+
65+
viewStateChange(viewState: ISSUE_STATE) {
66+
this.viewState = viewState;
67+
}
68+
}

angular-ngrx-scss/src/app/pull-requests/components/pull-requests-header/pull-requests-header.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
Input,
66
Output,
77
} from '@angular/core';
8-
import { PR_STATE, RepoPullRequests } from '../../../state/repository';
8+
import { ISSUE_STATE, RepoPullRequests } from '../../../state/repository';
99

1010
@Component({
1111
selector: 'app-pull-requests-header',
@@ -16,10 +16,10 @@ import { PR_STATE, RepoPullRequests } from '../../../state/repository';
1616
export class PullRequestsHeaderComponent {
1717
@Input() openPullRequests!: RepoPullRequests | null;
1818
@Input() closedPullRequests!: RepoPullRequests | null;
19-
@Input() viewState: PR_STATE = 'open';
20-
@Output() viewStateChange = new EventEmitter<PR_STATE>();
19+
@Input() viewState: ISSUE_STATE = 'open';
20+
@Output() viewStateChange = new EventEmitter<ISSUE_STATE>();
2121

22-
changeViewState(state: PR_STATE) {
22+
changeViewState(state: ISSUE_STATE) {
2323
this.viewState = state;
2424
this.viewStateChange.emit(this.viewState);
2525
}

angular-ngrx-scss/src/app/pull-requests/pull-requests.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ActivatedRoute } from '@angular/router';
33
import { Store } from '@ngrx/store';
44
import {
55
fetchPullRequests,
6-
PR_STATE,
6+
ISSUE_STATE,
77
selectClosedPullRequests,
88
selectOpenPullRequests,
99
} from '../state/repository';
@@ -18,7 +18,7 @@ export class PullRequestsComponent implements OnInit {
1818
repoName!: string;
1919
openPullRequests$ = this.store.select(selectOpenPullRequests);
2020
closedPullRequests$ = this.store.select(selectClosedPullRequests);
21-
viewState: PR_STATE = 'open';
21+
viewState: ISSUE_STATE = 'open';
2222

2323
constructor(private route: ActivatedRoute, private store: Store) {}
2424

0 commit comments

Comments
 (0)