diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index d849057b9..824933407 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -6,9 +6,9 @@ name: Setup Builds and Tests on: push: - branches: [main, release] + branches: [main, deploy] pull_request: - branches: [main, release] + branches: [main, deploy] jobs: linux-setup-and-tests: diff --git a/package.json b/package.json index 705609499..cab22df9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WATcher", - "version": "1.2.0", + "version": "1.2.1", "main": "main.js", "scripts": { "ng": "ng", diff --git a/src/app/core/services/filters.service.ts b/src/app/core/services/filters.service.ts index 10c486804..6179fcafb 100644 --- a/src/app/core/services/filters.service.ts +++ b/src/app/core/services/filters.service.ts @@ -72,12 +72,46 @@ export class FiltersService { ) {} private pushFiltersToUrl(): void { - const queryParams = {}; + const queryParams = { ...this.route.snapshot.queryParams }; + for (const filterName of Object.keys(this.filter$.value)) { - if (this.filter$.value[filterName] instanceof Set) { - queryParams[filterName] = JSON.stringify([...this.filter$.value[filterName]]); - } else { - queryParams[filterName] = JSON.stringify(this.filter$.value[filterName]); + const filterValue = this.filter$.value[filterName]; + + // Don't include empty or null filters + // Intended behaviour to reset to default if 0 of a certain filter are selected + switch (filterName) { + // Strings + case 'title': + case 'type': + if (!filterValue) { + delete queryParams[filterName]; + continue; + } + queryParams[filterName] = filterValue; + break; + // Arrays + case 'status': + case 'labels': + case 'milestones': + if (filterValue.length === 0) { + delete queryParams[filterName]; + continue; + } + queryParams[filterName] = filterValue; + break; + // Sets + case 'selectedLabels': + case 'deselectedLabels': + if (filterValue.size === 0) { + delete queryParams[filterName]; + } + queryParams[filterName] = [...filterValue]; + break; + // Objects + case 'sort': + queryParams[filterName] = JSON.stringify(filterValue); + break; + default: } } queryParams[FiltersService.PRESET_VIEW_QUERY_PARAM_KEY] = this.presetView$.value; @@ -85,7 +119,6 @@ export class FiltersService { this.router.navigate([], { relativeTo: this.route, queryParams, - queryParamsHandling: 'merge', replaceUrl: true }); } @@ -100,24 +133,48 @@ export class FiltersService { const queryParams = this.route.snapshot.queryParamMap; try { const presetView = queryParams.get(FiltersService.PRESET_VIEW_QUERY_PARAM_KEY); - // Use preset view if set in url if (presetView && this.presetViews.hasOwnProperty(presetView) && presetView !== 'custom') { this.updatePresetView(presetView); return; } + // No preset view and no other filters in params, use default view + if (!presetView && Object.keys(nextFilter).every((filterName) => queryParams.get(filterName) === null)) { + this.updatePresetView('currentlyActive'); + return; + } + for (const filterName of Object.keys(nextFilter)) { - const stringifiedFilterData = queryParams.get(filterName); - if (!stringifiedFilterData) { + // Check if there is no such param in url + if (queryParams.get(filterName) === null) { continue; } - const filterData = JSON.parse(stringifiedFilterData); - if (nextFilter[filterName] instanceof Set) { - nextFilter[filterName] = new Set(filterData); - } else { - nextFilter[filterName] = filterData; + const filterData = queryParams.getAll(filterName); + + switch (filterName) { + // Strings + case 'title': + case 'type': + nextFilter[filterName] = filterData[0]; + break; + // Arrays + case 'status': + case 'labels': + case 'milestones': + nextFilter[filterName] = filterData; + break; + // Sets + case 'selectedLabels': + case 'deselectedLabels': + nextFilter[filterName] = new Set(filterData); + break; + // Objects + case 'sort': + nextFilter[filterName] = JSON.parse(filterData[0]); + break; + default: } } this.updateFilters(nextFilter); @@ -227,14 +284,14 @@ export class FiltersService { getMilestonesForCurrentlyActive(): Milestone[] { const earliestOpenMilestone = this.milestoneService.getEarliestOpenMilestone(); if (earliestOpenMilestone) { - return [earliestOpenMilestone]; + return [earliestOpenMilestone, Milestone.PRWithoutMilestone]; } const latestClosedMilestone = this.milestoneService.getLatestClosedMilestone(); if (latestClosedMilestone) { - return [latestClosedMilestone]; + return [latestClosedMilestone, Milestone.PRWithoutMilestone]; } - return this.milestoneService.milestones; + return [...this.milestoneService.milestones, Milestone.PRWithoutMilestone]; } } 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 7a6b0e2fb..b1c656bef 100644 --- a/src/app/issues-viewer/card-view/card-view.component.css +++ b/src/app/issues-viewer/card-view/card-view.component.css @@ -1,5 +1,8 @@ .card-column { margin: 8px; + height: 77vh; + display: flex; + flex-direction: column; } .card { @@ -45,17 +48,10 @@ div.column-header .mat-card-header { } .scrollable-container { - height: 53vh; - overflow: auto; margin-bottom: 2px; - scrollbar-width: none; position: relative; } -.scrollable-container::-webkit-scrollbar { - display: none; -} - /* Ref: https://css-scroll-shadows.vercel.app */ .scrollable-container::before { pointer-events: none; @@ -82,6 +78,13 @@ div.column-header .mat-card-header { .scrollable-container-wrapper { position: relative; + scrollbar-width: none; + overflow: auto; + flex-grow: 1; +} + +.scrollable-container-wrapper::-webkit-scrollbar { + display: none; } .scrollable-container-wrapper::before { @@ -142,6 +145,6 @@ div.column-header .mat-card-header { display: none !important; } -:host ::ng-deep .mat-paginator-range-actions { - height: 47px; +:host ::ng-deep .pagination-hide-arrow .mat-paginator-range-actions { + display: none !important; } 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 40770db3a..37b3e98e3 100644 --- a/src/app/issues-viewer/card-view/card-view.component.html +++ b/src/app/issues-viewer/card-view/card-view.component.html @@ -6,7 +6,7 @@
- +
diff --git a/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.html b/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.html index 07ef0ccf4..4bde84f8a 100644 --- a/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.html +++ b/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.html @@ -1,4 +1,4 @@ -
- - {{ milestone.title }} +
+ + {{ milestone.state ? milestone.title : '???' }}
diff --git a/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.ts b/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.ts index 59cbb8d8c..c9772a2d5 100644 --- a/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.ts +++ b/src/app/shared/issue-pr-card/issue-pr-card-milestone/issue-pr-card-milestone.component.ts @@ -8,6 +8,7 @@ import { Milestone } from '../../../core/models/milestone.model'; }) export class IssuePrCardMilestoneComponent { @Input() milestone: Milestone; + @Input() repoHasMilestones: boolean; constructor() {} } diff --git a/src/app/shared/issue-pr-card/issue-pr-card.component.html b/src/app/shared/issue-pr-card/issue-pr-card.component.html index 9c9c36d87..5c7c50a9c 100644 --- a/src/app/shared/issue-pr-card/issue-pr-card.component.html +++ b/src/app/shared/issue-pr-card/issue-pr-card.component.html @@ -3,7 +3,10 @@ - + diff --git a/src/app/shared/issue-pr-card/issue-pr-card.component.ts b/src/app/shared/issue-pr-card/issue-pr-card.component.ts index 47fbf1a8f..4db045ee5 100644 --- a/src/app/shared/issue-pr-card/issue-pr-card.component.ts +++ b/src/app/shared/issue-pr-card/issue-pr-card.component.ts @@ -4,6 +4,7 @@ import { Filter } from '../../core/services/filters.service'; import { GithubService } from '../../core/services/github.service'; import { LabelService } from '../../core/services/label.service'; import { LoggingService } from '../../core/services/logging.service'; +import { MilestoneService } from '../../core/services/milestone.service'; @Component({ selector: 'app-issue-pr-card', @@ -14,7 +15,12 @@ export class IssuePrCardComponent { @Input() issue: Issue; @Input() filter?: Filter; - constructor(private logger: LoggingService, private githubService: GithubService, public labelService: LabelService) {} + constructor( + private logger: LoggingService, + private githubService: GithubService, + public labelService: LabelService, + public milestoneService: MilestoneService + ) {} /** Opens issue in new window */ viewIssueInBrowser(event: Event) { diff --git a/src/app/shared/layout/header.component.css b/src/app/shared/layout/header.component.css new file mode 100644 index 000000000..02c8f9c82 --- /dev/null +++ b/src/app/shared/layout/header.component.css @@ -0,0 +1,32 @@ +.repo-menu-footer { + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + bottom: 0; + z-index: 1; + padding: 10px; +} + +.new-repo-button { + flex-grow: 1; +} + +.keep-filter-button { + margin-left: 2px; +} + +.repo-options { + max-height: 300px; + overflow-y: auto; +} + +.repo-options button { + font-size: 17px; +} + +/* Overwrite the width of the menu */ +::ng-deep .repo-menu { + width: fit-content !important; + min-width: 320px !important; +} diff --git a/src/app/shared/layout/header.component.html b/src/app/shared/layout/header.component.html index a914c0229..e0b8c0cf0 100644 --- a/src/app/shared/layout/header.component.html +++ b/src/app/shared/layout/header.component.html @@ -11,8 +11,8 @@ WATcher v{{ this.getVersion() }} - - ({{ this.presetViews[this.filtersService.presetView$.value] }}) + + {{ this.presetViews[this.filtersService.presetView$.value] }} @@ -37,19 +37,17 @@
- +
+ +
@@ -62,14 +60,40 @@ {{ this.currentRepo || 'No Repository Set' }}
+ +
+
+ +
+
+ + +
+