From 709afa760ec06204f463ce476aaefd008b8e8c0a Mon Sep 17 00:00:00 2001 From: Arif Khalid <88131400+Arif-Khalid@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:05:02 +0800 Subject: [PATCH 1/6] Show preset view only when repo is set (#355) Preset view is shown before a repo is selected. There is no reason to show the current preset view and might confuse users as to its purpose when no repo is selected. Let's hide the preset view until a repo is selected. --- src/app/shared/layout/header.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/layout/header.component.html b/src/app/shared/layout/header.component.html index e0b8c0cf..65a3d207 100644 --- a/src/app/shared/layout/header.component.html +++ b/src/app/shared/layout/header.component.html @@ -11,7 +11,7 @@ WATcher v{{ this.getVersion() }} - + {{ this.presetViews[this.filtersService.presetView$.value] }} @@ -34,7 +34,7 @@ -
+
From a5e695ab2f183b6d10f2c1bf1db20ef7403e4cc1 Mon Sep 17 00:00:00 2001 From: NereusWB922 <107099783+NereusWB922@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:34:29 +0800 Subject: [PATCH 2/6] Consider open milestone without deadline as currently active (#359) For open milestones, only those with deadlines were considered as currently active. This led to setting a closed milestone with the latest deadline as currently active when there is an open milestone without deadline. Let's update the selection logic to also include open milestones without deadlines. --- src/app/core/services/milestone.service.ts | 39 +++++++++++++++------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/app/core/services/milestone.service.ts b/src/app/core/services/milestone.service.ts index 13e7ac8a..64d938ee 100644 --- a/src/app/core/services/milestone.service.ts +++ b/src/app/core/services/milestone.service.ts @@ -47,22 +47,37 @@ export class MilestoneService { } /** - * Gets the open milestone with the earliest deadline. - * Returns null if there is no open milestone with deadline. + * Returns the open milestone with earliest deadline. + * If no deadline exists, returns milestone with alphabetically smallest title. + * Returns null if there are no open milestones. */ getEarliestOpenMilestone(): Milestone { - let earliestOpenMilestone: Milestone = null; - for (const milestone of this.milestones) { - if (!milestone.deadline || milestone.state !== 'open') { - continue; + const openMilestones: Milestone[] = this.milestones.filter((milestone: Milestone) => milestone.state === 'open'); + + if (openMilestones.length === 0) { + return null; + } + + const target = openMilestones.reduce((prev, curr) => { + if (prev === null) { + return curr; } - if (earliestOpenMilestone === null) { - earliestOpenMilestone = milestone; - } else if (milestone.deadline < earliestOpenMilestone.deadline) { - earliestOpenMilestone = milestone; + + if (prev.deadline !== curr.deadline) { + if (!prev.deadline) { + return curr; + } + if (!curr.deadline) { + return prev; + } + return prev.deadline < curr.deadline ? prev : curr; } - } - return earliestOpenMilestone; + + // Both without due date or with the same due date + return prev.title.localeCompare(curr.title) < 0 ? prev : curr; + }, null); + + return target; } /** From 5ff13fec764fee4239503d43734594127ee2ba85 Mon Sep 17 00:00:00 2001 From: Arif Khalid <88131400+Arif-Khalid@users.noreply.github.com> Date: Wed, 10 Apr 2024 22:19:35 +0800 Subject: [PATCH 3/6] Fix top and bottom shadow of columns (#357) A few bugs exist related to column shadows. Top shadow is shown when there are no elements behind header and hidden when there are. Bottom shadow sticks to the column as a user scrolls. These are not the intended behaviour of the shadows to indicate presence of elements behind above or below columns respectively. Let's update the CSS to correspond to appropriate shadow behaviours. --- .../card-view/card-view.component.css | 45 +++++++++---------- .../card-view/card-view.component.html | 2 +- .../issue-pr-card/issue-pr-card.component.css | 1 + 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/app/issues-viewer/card-view/card-view.component.css b/src/app/issues-viewer/card-view/card-view.component.css index b1c656be..10fdf38e 100644 --- a/src/app/issues-viewer/card-view/card-view.component.css +++ b/src/app/issues-viewer/card-view/card-view.component.css @@ -52,7 +52,26 @@ div.column-header .mat-card-header { position: relative; } -/* Ref: https://css-scroll-shadows.vercel.app */ +/* Ref: https://lea.verou.me/blog/2012/04/background-attachment-local/ */ +.scroll-shadow { + background: + /* Shadow covers */ linear-gradient(white 30%, rgba(255, 255, 255, 0)), + linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, + /* Shadows */ radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), + radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)) 0 100%; + background: + /* Shadow covers */ linear-gradient(white 30%, rgba(255, 255, 255, 0)), + linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, + /* Shadows */ radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0)), + radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0)) 0 100%; + background-repeat: no-repeat; + background-color: white; + background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px; + + /* Opera doesn't support this in the shorthand */ + background-attachment: local, local, scroll, scroll; +} + .scrollable-container::before { pointer-events: none; content: ''; @@ -87,30 +106,6 @@ div.column-header .mat-card-header { display: none; } -.scrollable-container-wrapper::before { - pointer-events: none; - content: ''; - position: absolute; - z-index: 1; - top: 0; - left: 0; - right: 0; - height: 5px; - background-image: radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.5), transparent); -} - -.scrollable-container-wrapper::after { - pointer-events: none; - content: ''; - position: absolute; - z-index: 1; - bottom: 0; - left: 0; - right: 0; - height: 5px; - background-image: radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.5), transparent); -} - .loading-spinner { display: flex; justify-content: center; diff --git a/src/app/issues-viewer/card-view/card-view.component.html b/src/app/issues-viewer/card-view/card-view.component.html index 37b3e98e..3e876acf 100644 --- a/src/app/issues-viewer/card-view/card-view.component.html +++ b/src/app/issues-viewer/card-view/card-view.component.html @@ -3,7 +3,7 @@ [ngTemplateOutlet]="getHeaderTemplate() || defaultHeader" [ngTemplateOutletContext]="{ $implicit: this.group }" > -
+
diff --git a/src/app/shared/issue-pr-card/issue-pr-card.component.css b/src/app/shared/issue-pr-card/issue-pr-card.component.css index 373546ae..76f2ced3 100644 --- a/src/app/shared/issue-pr-card/issue-pr-card.component.css +++ b/src/app/shared/issue-pr-card/issue-pr-card.component.css @@ -1,5 +1,6 @@ .card { margin: 8px 0px 8px 0px; + background-color: transparent; } .mat-card { From 95a5486be2ecaade7f43496356b0a1f76be7710e Mon Sep 17 00:00:00 2001 From: Nguyen <87511888+nknguyenhc@users.noreply.github.com> Date: Thu, 11 Apr 2024 08:58:24 +0800 Subject: [PATCH 4/6] Optimise Github API calls (#360) Previously, multiple Github API calls causes Github to ask users for reauthorisation, or in rare cases, rate limit is exceeded. We reduce the number of API calls to Github to reduce such issues. --- src/app/core/services/github.service.ts | 34 ++++++++----------- .../grouping/grouping-context.service.ts | 6 ++-- src/app/core/services/issue.service.ts | 2 +- src/app/core/services/label.service.ts | 2 +- src/app/core/services/view.service.ts | 7 ++-- .../issues-viewer/issues-viewer.component.ts | 9 ----- .../label-filter-bar.component.ts | 10 +----- 7 files changed, 25 insertions(+), 45 deletions(-) diff --git a/src/app/core/services/github.service.ts b/src/app/core/services/github.service.ts index e306d00f..3d2d605e 100644 --- a/src/app/core/services/github.service.ts +++ b/src/app/core/services/github.service.ts @@ -115,31 +115,25 @@ export class GithubService { /* * Github Issues consists of issues and pull requests in WATcher. */ - const issueObs = this.toFetchIssues(issuesFilter).pipe( + return this.toFetchIssues(issuesFilter).pipe( filter((toFetch) => toFetch), flatMap(() => { - return this.fetchGraphqlList( - FetchIssues, - { owner: ORG_NAME, name: REPO, filter: graphqlFilter }, - (result) => result.data.repository.issues.edges, - GithubGraphqlIssueOrPr + return merge( + this.fetchGraphqlList( + FetchIssues, + { owner: ORG_NAME, name: REPO, filter: graphqlFilter }, + (result) => result.data.repository.issues.edges, + GithubGraphqlIssueOrPr + ), + this.fetchGraphqlList( + FetchPullRequests, + { owner: ORG_NAME, name: REPO }, + (result) => result.data.repository.pullRequests.edges, + GithubGraphqlIssueOrPr + ) ); }) ); - const prObs = this.toFetchIssues(issuesFilter).pipe( - filter((toFetch) => toFetch), - flatMap(() => { - return this.fetchGraphqlList( - FetchPullRequests, - { owner: ORG_NAME, name: REPO }, - (result) => result.data.repository.pullRequests.edges, - GithubGraphqlIssueOrPr - ); - }) - ); - - // Concatenate both streams together. - return merge(issueObs, prObs); } /** diff --git a/src/app/core/services/grouping/grouping-context.service.ts b/src/app/core/services/grouping/grouping-context.service.ts index 3957514c..0a3319e5 100644 --- a/src/app/core/services/grouping/grouping-context.service.ts +++ b/src/app/core/services/grouping/grouping-context.service.ts @@ -58,8 +58,10 @@ export class GroupingContextService { * @param groupBy The grouping type to set. */ setCurrentGroupingType(groupBy: GroupBy): void { - this.currGroupBy = groupBy; - this.currGroupBySubject.next(this.currGroupBy); + if (groupBy !== this.currGroupBy) { + this.currGroupBy = groupBy; + this.currGroupBySubject.next(this.currGroupBy); + } this.router.navigate([], { relativeTo: this.route, diff --git a/src/app/core/services/issue.service.ts b/src/app/core/services/issue.service.ts index 4bc7bb83..2c66051b 100644 --- a/src/app/core/services/issue.service.ts +++ b/src/app/core/services/issue.service.ts @@ -18,7 +18,7 @@ import { ViewService } from './view.service'; * using GitHub. */ export class IssueService { - static readonly POLL_INTERVAL = 5000; // 5 seconds + static readonly POLL_INTERVAL = 20000; // 20 seconds issues: Issues; issues$: BehaviorSubject; diff --git a/src/app/core/services/label.service.ts b/src/app/core/services/label.service.ts index cdbb6de8..2f42164f 100644 --- a/src/app/core/services/label.service.ts +++ b/src/app/core/services/label.service.ts @@ -22,7 +22,7 @@ const COLOR_WHITE = 'ffffff'; // Light color for text with dark background * from the GitHub repository for the WATcher application. */ export class LabelService { - static readonly POLL_INTERVAL = 5000; // 5 seconds + static readonly POLL_INTERVAL = 20000; // 20 seconds labels: Label[]; simpleLabels: SimpleLabel[]; diff --git a/src/app/core/services/view.service.ts b/src/app/core/services/view.service.ts index 198a8cd4..3f8e959c 100644 --- a/src/app/core/services/view.service.ts +++ b/src/app/core/services/view.service.ts @@ -105,11 +105,12 @@ export class ViewService { /** Adds past repositories to view */ (this.otherRepos || []).push(this.currentRepo); } - this.setRepository(repo, this.otherRepos); + if (!repo.equals(this.currentRepo)) { + this.setRepository(repo, this.otherRepos); + this.repoChanged$.next(repo); + } this.repoUrlCacheService.cache(repo.toString()); - - this.repoChanged$.next(repo); } /** diff --git a/src/app/issues-viewer/issues-viewer.component.ts b/src/app/issues-viewer/issues-viewer.component.ts index 58665dda..4afe6d85 100644 --- a/src/app/issues-viewer/issues-viewer.component.ts +++ b/src/app/issues-viewer/issues-viewer.component.ts @@ -106,20 +106,11 @@ export class IssuesViewerComponent implements OnInit, AfterViewInit, OnDestroy { this.availableGroupsSubscription.unsubscribe(); } - this.checkIfValidRepository().subscribe((isValidRepository) => { - if (!isValidRepository) { - throw new Error(ErrorMessageService.repositoryNotPresentMessage()); - } - }); - // Fetch assignees this.groups = []; this.hiddenGroups = []; this.availableGroupsSubscription = this.groupingContextService.getGroups().subscribe((x) => (this.groups = x)); - - // Fetch issues - this.issueService.reloadAllIssues(); } /** diff --git a/src/app/shared/filter-bar/label-filter-bar/label-filter-bar.component.ts b/src/app/shared/filter-bar/label-filter-bar/label-filter-bar.component.ts index bf86435d..216db5fc 100644 --- a/src/app/shared/filter-bar/label-filter-bar/label-filter-bar.component.ts +++ b/src/app/shared/filter-bar/label-filter-bar/label-filter-bar.component.ts @@ -40,6 +40,7 @@ export class LabelFilterBarComponent implements OnInit, AfterViewInit, OnDestroy this.selectedLabelNames = new Set(this.filtersService.filter$.value.labels); this.deselectedLabelNames = this.filtersService.filter$.value.deselectedLabels; this.hiddenLabelNames = this.filtersService.filter$.value.hiddenLabels; + this.loaded = true; }); }); } @@ -100,15 +101,6 @@ export class LabelFilterBarComponent implements OnInit, AfterViewInit, OnDestroy /** loads in the labels in the repository */ public load() { this.labelService.startPollLabels(); - this.labelSubscription = this.labelService.fetchLabels().subscribe( - (response) => { - this.logger.debug('LabelFilterBarComponent: Fetched labels from Github'); - }, - (err) => {}, - () => { - this.loaded = true; - } - ); } filter(filter: string, target: string): boolean { From d70f9b1881972d0491ee92774f04ae29f0a9233b Mon Sep 17 00:00:00 2001 From: AdityaMisra <114080910+MadLamprey@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:52:52 +0800 Subject: [PATCH 5/6] Make ItemsPerPage common for all card views (#362) Co-authored-by: Misra Aditya --- src/app/core/services/filters.service.ts | 21 ++++++++++++++++--- .../card-view/card-view.component.html | 2 +- .../card-view/card-view.component.ts | 9 ++++---- .../filter-bar/filter-bar.component.css | 4 ++-- .../filter-bar/filter-bar.component.html | 15 +++++++++++-- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/app/core/services/filters.service.ts b/src/app/core/services/filters.service.ts index 6179fcaf..e3b7c9c0 100644 --- a/src/app/core/services/filters.service.ts +++ b/src/app/core/services/filters.service.ts @@ -16,6 +16,7 @@ export type Filter = { milestones: string[]; hiddenLabels: Set; deselectedLabels: Set; + itemsPerPage: number; }; @Injectable({ @@ -27,6 +28,8 @@ export type Filter = { */ export class FiltersService { public static readonly PRESET_VIEW_QUERY_PARAM_KEY = 'presetview'; + private itemsPerPage = 20; + readonly presetViews: { [key: string]: () => Filter; } = { @@ -38,7 +41,8 @@ export class FiltersService { labels: [], milestones: this.getMilestonesForCurrentlyActive().map((milestone) => milestone.title), hiddenLabels: new Set(), - deselectedLabels: new Set() + deselectedLabels: new Set(), + itemsPerPage: this.itemsPerPage }), contributions: () => ({ title: '', @@ -48,7 +52,8 @@ export class FiltersService { labels: [], milestones: this.milestoneService.milestones.map((milestone) => milestone.title), hiddenLabels: new Set(), - deselectedLabels: new Set() + deselectedLabels: new Set(), + itemsPerPage: this.itemsPerPage }), custom: () => this.filter$.value }; @@ -69,7 +74,11 @@ export class FiltersService { private router: Router, private route: ActivatedRoute, private milestoneService: MilestoneService - ) {} + ) { + this.filter$.subscribe((filter: Filter) => { + this.itemsPerPage = filter.itemsPerPage; + }); + } private pushFiltersToUrl(): void { const queryParams = { ...this.route.snapshot.queryParams }; @@ -111,6 +120,9 @@ export class FiltersService { case 'sort': queryParams[filterName] = JSON.stringify(filterValue); break; + case 'itemsPerPage': + queryParams[filterName] = filterValue.toString(); + break; default: } } @@ -174,6 +186,9 @@ export class FiltersService { case 'sort': nextFilter[filterName] = JSON.parse(filterData[0]); break; + case 'itemsPerPage': + nextFilter[filterName] = Number(filterData[0]); + break; default: } } diff --git a/src/app/issues-viewer/card-view/card-view.component.html b/src/app/issues-viewer/card-view/card-view.component.html index 3e876acf..15273a4f 100644 --- a/src/app/issues-viewer/card-view/card-view.component.html +++ b/src/app/issues-viewer/card-view/card-view.component.html @@ -15,9 +15,9 @@
diff --git a/src/app/issues-viewer/card-view/card-view.component.ts b/src/app/issues-viewer/card-view/card-view.component.ts index b4fb9151..1eaf2de8 100644 --- a/src/app/issues-viewer/card-view/card-view.component.ts +++ b/src/app/issues-viewer/card-view/card-view.component.ts @@ -46,6 +46,7 @@ export class CardViewComponent implements OnInit, AfterViewInit, OnDestroy, Filt private timeoutId: NodeJS.Timeout | null = null; private issuesLengthSubscription: Subscription; private issuesLoadingStateSubscription: Subscription; + private filterSubscription: Subscription; isLoading = true; issueLength = 0; @@ -73,6 +74,10 @@ export class CardViewComponent implements OnInit, AfterViewInit, OnDestroy, Filt this.group, this.filters ); + + this.filterSubscription = this.filtersService.filter$.subscribe((filter: any) => { + this.pageSize = filter.itemsPerPage; + }); } ngAfterViewInit(): void { @@ -125,8 +130,4 @@ export class CardViewComponent implements OnInit, AfterViewInit, OnDestroy, Filt retrieveFilterable(): FilterableSource { return this.issues; } - - updatePageSize(newPageSize: number) { - this.pageSize = newPageSize; - } } diff --git a/src/app/shared/filter-bar/filter-bar.component.css b/src/app/shared/filter-bar/filter-bar.component.css index be59aa93..c5728882 100644 --- a/src/app/shared/filter-bar/filter-bar.component.css +++ b/src/app/shared/filter-bar/filter-bar.component.css @@ -2,11 +2,11 @@ margin: 8px; font-size: 14px; max-width: 20%; - width: 17%; /* depends on number of filters*/ + width: 14%; /* depends on number of filters*/ } .search-bar { - width: 90%; + width: 80%; } .dropdown-filters { diff --git a/src/app/shared/filter-bar/filter-bar.component.html b/src/app/shared/filter-bar/filter-bar.component.html index 3689f0b0..9c57f634 100644 --- a/src/app/shared/filter-bar/filter-bar.component.html +++ b/src/app/shared/filter-bar/filter-bar.component.html @@ -1,5 +1,5 @@ - + - + From 681860f03a7aa3801000c5805513f358befc1448 Mon Sep 17 00:00:00 2001 From: Arif Khalid <88131400+Arif-Khalid@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:02:24 +0800 Subject: [PATCH 6/6] Create release V1.2.2 (#364) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cab22df9..2276f490 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WATcher", - "version": "1.2.1", + "version": "1.2.2", "main": "main.js", "scripts": { "ng": "ng",