mirror of
https://github.com/WowUp/WowUp.git
synced 2026-04-24 15:57:19 -04:00
Fix specified issues in PR
Create utility function for string filtering. Move filter and search inputs to left side of buttons. Implement sorting for get addons page. Include i18 translation for new text. Cleanup unused imports/variables in my addons and get addons components.
This commit is contained in:
@@ -11,30 +11,34 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button mat-flat-button color="primary" (click)="onRefresh()">
|
||||
{{'PAGES.GET_ADDONS.REFRESH_BUTTON' | translate}}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" (click)="onInstallFromUrl()">
|
||||
{{'PAGES.GET_ADDONS.INSTALL_FROM_URL_BUTTON' | translate}}
|
||||
</button>
|
||||
<mat-form-field class="example-form-field">
|
||||
<mat-label>{{'PAGES.GET_ADDONS.SEARCH_LABEL' | translate}}</mat-label>
|
||||
<input matInput type="text" [(ngModel)]="query" (keyup.enter)="onSearch()">
|
||||
<button mat-button color="accent" *ngIf="query" matSuffix mat-icon-button aria-label="Clear"
|
||||
(click)="onClearSearch()">
|
||||
<mat-icon>close</mat-icon>
|
||||
<div class="right-container">
|
||||
<div class="search-container">
|
||||
<mat-form-field>
|
||||
<mat-label>{{'PAGES.GET_ADDONS.SEARCH_LABEL' | translate}}</mat-label>
|
||||
<input matInput type="text" [(ngModel)]="query" (keyup.enter)="onSearch()">
|
||||
<button mat-button color="accent" *ngIf="query" matSuffix mat-icon-button aria-label="Clear"
|
||||
(click)="onClearSearch()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button mat-flat-button color="primary" (click)="onRefresh()">
|
||||
{{'PAGES.GET_ADDONS.REFRESH_BUTTON' | translate}}
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<button mat-flat-button color="primary" (click)="onInstallFromUrl()">
|
||||
{{'PAGES.GET_ADDONS.INSTALL_FROM_URL_BUTTON' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-progress-spinner *ngIf="isBusy === true"></app-progress-spinner>
|
||||
|
||||
<div class="table-container flex-grow-1" *ngIf="isBusy === false">
|
||||
<table mat-table [dataSource]="displayAddons$ | async" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="addon">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<div class="table-container flex-grow-1" [hidden]="isBusy === true">
|
||||
<table mat-table matSort [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef>
|
||||
{{'PAGES.GET_ADDONS.TABLE.ADDON_COLUMN_HEADER' | translate}}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
@@ -44,7 +48,7 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="provider">
|
||||
<th mat-header-cell *matHeaderCellDef class="provider-column">
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef class="provider-column">
|
||||
{{'PAGES.GET_ADDONS.TABLE.PROVIDER_COLUMN_HEADER' | translate}}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
@@ -53,7 +57,7 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="author">
|
||||
<th mat-header-cell *matHeaderCellDef class="author-column">
|
||||
<th mat-header-cell mat-sort-header *matHeaderCellDef class="author-column">
|
||||
{{'PAGES.GET_ADDONS.TABLE.AUTHOR_COLUMN_HEADER' | translate}}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
|
||||
@@ -10,14 +10,24 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
.right-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
.search-container {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-left: 1em;
|
||||
|
||||
button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { AddonDetailComponent } from "app/components/addon-detail/addon-detail.component";
|
||||
import { InstallFromUrlDialogComponent } from "app/components/install-from-url-dialog/install-from-url-dialog.component";
|
||||
@@ -11,8 +11,11 @@ import { ElectronService } from "app/services";
|
||||
import { AddonService } from "app/services/addons/addon.service";
|
||||
import { SessionService } from "app/services/session/session.service";
|
||||
import { WarcraftService } from "app/services/warcraft/warcraft.service";
|
||||
import { BehaviorSubject, Subscription } from "rxjs";
|
||||
import { map, tap } from "rxjs/operators";
|
||||
import { BehaviorSubject, Subject, Subscription } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@Component({
|
||||
selector: "app-get-addons",
|
||||
@@ -20,13 +23,17 @@ import { map, tap } from "rxjs/operators";
|
||||
styleUrls: ["./get-addons.component.scss"],
|
||||
})
|
||||
export class GetAddonsComponent implements OnInit, OnDestroy {
|
||||
private readonly _displayAddonsSrc = new BehaviorSubject<PotentialAddon[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
private readonly _displayAddonsSrc = new BehaviorSubject<PotentialAddon[]>([]);
|
||||
private readonly _destroyed$ = new Subject<void>();
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
public dataSource = new MatTableDataSource<PotentialAddon>([]);
|
||||
|
||||
columns: ColumnState[] = [
|
||||
{ name: "addon", display: "Addon", visible: true },
|
||||
{ name: "name", display: "Addon", visible: true },
|
||||
{ name: "author", display: "Author", visible: true },
|
||||
{ name: "provider", display: "Provider", visible: true },
|
||||
{ name: "status", display: "Status", visible: true },
|
||||
@@ -37,8 +44,6 @@ export class GetAddonsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public query = "";
|
||||
public displayAddons$ = this._displayAddonsSrc.asObservable();
|
||||
|
||||
public isBusy = false;
|
||||
public selectedClient = WowClientType.None;
|
||||
|
||||
@@ -64,9 +69,17 @@ export class GetAddonsComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
).subscribe();
|
||||
|
||||
const displayAddonSubscription = this._displayAddonsSrc
|
||||
.subscribe((items: PotentialAddon[]) => {
|
||||
this.dataSource.data = items;
|
||||
this.dataSource.sortingDataAccessor = _.get;
|
||||
this.dataSource.sort = this.sort;
|
||||
});
|
||||
|
||||
this.subscriptions = [
|
||||
selectedClientSubscription,
|
||||
addonRemovedSubscription
|
||||
addonRemovedSubscription,
|
||||
displayAddonSubscription
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
<div class="tab-container d-flex flex-col"
|
||||
[ngClass]="{'mac': electronService.isMac, 'windows': electronService.isWin }">
|
||||
<div class="control-container">
|
||||
<div class="left-container">
|
||||
<div class="select-container ">
|
||||
<mat-form-field>
|
||||
<mat-label>{{'PAGES.MY_ADDONS.CLIENT_TYPE_SELECT_LABEL' | translate}}</mat-label>
|
||||
<mat-select class="select" [(value)]="selectedClient" (selectionChange)="onClientChange()"
|
||||
[disabled]="enableControls === false">
|
||||
<mat-option [value]="clientType" *ngFor="let clientType of warcraftService.installedClientTypes$ | async">
|
||||
{{warcraftService.getClientDisplayName(clientType)}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="select-container ">
|
||||
<mat-form-field>
|
||||
<mat-label>{{'PAGES.MY_ADDONS.CLIENT_TYPE_SELECT_LABEL' | translate}}</mat-label>
|
||||
<mat-select class="select" [(value)]="selectedClient" (selectionChange)="onClientChange()"
|
||||
[disabled]="enableControls === false">
|
||||
<mat-option [value]="clientType" *ngFor="let clientType of warcraftService.installedClientTypes$ | async">
|
||||
{{warcraftService.getClientDisplayName(clientType)}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="right-container">
|
||||
<div class="filter-container" *ngIf="selectedClient !== wowClientType.None">
|
||||
<mat-form-field>
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="filterAddons($event)">
|
||||
<mat-label>{{'PAGES.MY_ADDONS.FILTER_LABEL' | translate}}</mat-label>
|
||||
<input matInput (keyup)="filterAddons()" [(ngModel)]="filter">
|
||||
<button mat-button color="accent" *ngIf="filter" matSuffix mat-icon-button aria-label="Clear"
|
||||
(click)="onClearFilter()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onUpdateAll()" (contextmenu)="onUpdateAllContext($event)">
|
||||
{{'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON' | translate}}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onRefresh()">
|
||||
{{'PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON' | translate}}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onReScan()">
|
||||
{{'PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON' | translate}}
|
||||
</button>
|
||||
<div class="button-container">
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onUpdateAll()" (contextmenu)="onUpdateAllContext($event)">
|
||||
{{'PAGES.MY_ADDONS.UPDATE_ALL_BUTTON' | translate}}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onRefresh()">
|
||||
{{'PAGES.MY_ADDONS.CHECK_UPDATES_BUTTON' | translate}}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" [matTooltip]="'PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON_TOOLTIP' | translate"
|
||||
[disabled]="enableControls === false" (click)="onReScan()">
|
||||
{{'PAGES.MY_ADDONS.RESCAN_FOLDERS_BUTTON' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,29 +5,29 @@
|
||||
flex-direction: row;
|
||||
padding: 0 1em 0 1em;
|
||||
|
||||
.left-container {
|
||||
.select-container {
|
||||
padding-top: 1em;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.right-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
|
||||
.select-container {
|
||||
padding-top: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
padding-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
.button-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-left: 1em;
|
||||
|
||||
button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
|
||||
import { Component, NgZone, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
|
||||
import { WowClientType } from '../../models/warcraft/wow-client-type';
|
||||
import { debounceTime, filter, first, map, take, takeUntil, tap } from 'rxjs/operators';
|
||||
import { from, BehaviorSubject, Observable, fromEvent, Subscription, Subject } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { from, BehaviorSubject, Subscription, Subject } from 'rxjs';
|
||||
import { Addon } from 'app/entities/addon';
|
||||
import { WarcraftService } from 'app/services/warcraft/warcraft.service';
|
||||
import { AddonService } from 'app/services/addons/addon.service';
|
||||
@@ -21,6 +21,7 @@ import { ConfirmDialogComponent } from 'app/components/confirm-dialog/confirm-di
|
||||
import { getEnumName } from 'app/utils/enum.utils';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { stringIncludes } from 'app/utils/string.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-addons',
|
||||
@@ -38,13 +39,13 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
private readonly _destroyed$ = new Subject<void>();
|
||||
|
||||
private subscriptions: Subscription[] = [];
|
||||
private sub: Subscription;
|
||||
|
||||
public spinnerMessage = 'Loading...';
|
||||
|
||||
contextMenuPosition = { x: '0px', y: '0px' };
|
||||
|
||||
public dataSource = new MatTableDataSource<MyAddonsListItem>([]);
|
||||
public filter = '';
|
||||
|
||||
columns: ColumnState[] = [
|
||||
{ name: 'addon.name', display: 'Addon', visible: true },
|
||||
@@ -76,7 +77,7 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
private _dialog: MatDialog
|
||||
) {
|
||||
|
||||
this.addonService.addonInstalled$.subscribe((evt) => {
|
||||
const addonInstalledSubscription = this.addonService.addonInstalled$.subscribe((evt) => {
|
||||
console.log('UPDATE')
|
||||
let listItems: MyAddonsListItem[] = [].concat(this._displayAddonsSrc.value);
|
||||
const listItemIdx = listItems.findIndex(li => li.addon.id === evt.addon.id);
|
||||
@@ -98,7 +99,7 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
});
|
||||
|
||||
this.addonService.addonRemoved$
|
||||
const addonRemovedSubscription = this.addonService.addonRemoved$
|
||||
.subscribe((addonId) => {
|
||||
const addons: MyAddonsListItem[] = [].concat(this._displayAddonsSrc.value);
|
||||
const listItemIdx = addons.findIndex(li => li.addon.id === addonId);
|
||||
@@ -109,23 +110,24 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
})
|
||||
|
||||
this._displayAddonsSrc
|
||||
.pipe(takeUntil(this._destroyed$))
|
||||
const displayAddonSubscription = this._displayAddonsSrc
|
||||
.subscribe((items: MyAddonsListItem[]) => {
|
||||
this.dataSource.data = items;
|
||||
this.dataSource.sortingDataAccessor = _.get;
|
||||
this.dataSource.filterPredicate = (item: MyAddonsListItem, filter: string) => {
|
||||
if (item.addon.name.trim().toLowerCase().indexOf(filter) >= 0) return true;
|
||||
if (item.addon.latestVersion && item.addon.latestVersion.trim().toLowerCase().indexOf(filter) >= 0) return true;
|
||||
if (item.addon.author && item.addon.author.trim().toLowerCase().indexOf(filter) >= 0) return true;
|
||||
if (stringIncludes(item.addon.name, filter) || stringIncludes(item.addon.latestVersion, filter) || stringIncludes(item.addon.author, filter)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.dataSource.sort = this.sort;
|
||||
});
|
||||
|
||||
this.subscriptions.concat(...[addonInstalledSubscription, addonRemovedSubscription, displayAddonSubscription]);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._sessionService.selectedClientType$
|
||||
const selectedClientSubscription = this._sessionService.selectedClientType$
|
||||
.pipe(
|
||||
map(clientType => {
|
||||
this.selectedClient = clientType;
|
||||
@@ -133,12 +135,12 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this.subscriptions.push(selectedClientSubscription);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscriptions.forEach(sub => sub.unsubscribe());
|
||||
this._destroyed$.next();
|
||||
this._destroyed$.complete();
|
||||
}
|
||||
|
||||
onRefresh() {
|
||||
@@ -180,10 +182,13 @@ export class MyAddonsComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
filterAddons(event: Event) {
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
console.log('filterValue:', filterValue);
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
filterAddons(): void {
|
||||
this.dataSource.filter = this.filter.trim().toLowerCase();
|
||||
}
|
||||
|
||||
onClearFilter(): void {
|
||||
this.filter = '';
|
||||
this.filterAddons();
|
||||
}
|
||||
|
||||
async onUpdateAll() {
|
||||
|
||||
6
wowup-electron/src/app/utils/string.utils.ts
Normal file
6
wowup-electron/src/app/utils/string.utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function stringIncludes(value: string, search: string) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return value.trim().toLowerCase().indexOf(search.trim().toLowerCase()) >= 0;
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
"CHECK_UPDATES_BUTTON": "Check Updates",
|
||||
"CHECK_UPDATES_BUTTON_TOOLTIP": "Check for latest addon updates",
|
||||
"CLIENT_TYPE_SELECT_LABEL": "World of Warcraft",
|
||||
"FILTER_LABEL": "Filter",
|
||||
"RESCAN_FOLDERS_BUTTON": "Re-Scan Folders",
|
||||
"RESCAN_FOLDERS_BUTTON_TOOLTIP": "Scan your client folder for installed addons",
|
||||
"UPDATE_ALL_BUTTON": "Update All",
|
||||
|
||||
Reference in New Issue
Block a user