mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-29 18:08:25 +00:00
add filter service and enable chart states to filter lists
This commit is contained in:
parent
cce8b60515
commit
3bdceb1d6b
@ -1,5 +1,5 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="space-between start">
|
<div fxLayout="row" fxLayoutAlign="space-between start">
|
||||||
<div></div>
|
<div></div>
|
||||||
<div>{{state}}: </div>
|
<div><a href="#">{{state}}</a>: </div>
|
||||||
<div>{{count}}</div>
|
<div>{{count}}</div>
|
||||||
</div>
|
</div>
|
@ -1,16 +1,13 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-chart-item',
|
selector: 'app-chart-item',
|
||||||
templateUrl: './chart-item.component.html',
|
templateUrl: './chart-item.component.html',
|
||||||
styleUrls: ['./chart-item.component.scss']
|
styleUrls: ['./chart-item.component.scss']
|
||||||
})
|
})
|
||||||
export class ChartItemComponent implements OnInit {
|
export class ChartItemComponent {
|
||||||
@Input() state: string;
|
@Input() state: string;
|
||||||
@Input() count: number;
|
@Input() count: number;
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
<div fxLayout="row" fxLayoutAlign="space-between stretch">
|
<div fxLayout="row" fxLayoutAlign="space-between stretch">
|
||||||
<app-donut-chart [elementID]="chartID" fxFlex="30" [title]="title"></app-donut-chart>
|
<app-donut-chart [elementID]="chartID" fxFlex="30" [title]="title"></app-donut-chart>
|
||||||
<div class="items" fxLayout="column" fxLayoutAlign="start end" fxFlex="70">
|
<div class="items" fxLayout="column" fxLayoutAlign="start end" fxFlex="70">
|
||||||
<app-chart-item *ngFor="let state of states" [state]="state.label" [count]="state.count">
|
<app-chart-item *ngFor="let state of states" (click)="onItemSelect(state.label)" [state]="state.label"
|
||||||
|
[count]="state.count">
|
||||||
</app-chart-item>
|
</app-chart-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,8 @@ import { FolderService } from 'src/app/services/folder.service';
|
|||||||
import { DonutChartComponent } from '../donut-chart/donut-chart.component';
|
import { DonutChartComponent } from '../donut-chart/donut-chart.component';
|
||||||
import { DeviceService } from 'src/app/services/device.service';
|
import { DeviceService } from 'src/app/services/device.service';
|
||||||
import Device from 'src/app/device';
|
import Device from 'src/app/device';
|
||||||
import { Type } from '../../type';
|
import { StType } from '../../type';
|
||||||
|
import { FilterService } from 'src/app/services/filter.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ import { Type } from '../../type';
|
|||||||
|
|
||||||
export class ChartComponent implements OnInit {
|
export class ChartComponent implements OnInit {
|
||||||
@ViewChild(DonutChartComponent) donutChart: DonutChartComponent;
|
@ViewChild(DonutChartComponent) donutChart: DonutChartComponent;
|
||||||
@Input() type: Type;
|
@Input() type: StType;
|
||||||
title: string;
|
title: string;
|
||||||
chartID: string;
|
chartID: string;
|
||||||
states: { label: string, count: number, color: string }[] = [];
|
states: { label: string, count: number, color: string }[] = [];
|
||||||
@ -25,16 +26,25 @@ export class ChartComponent implements OnInit {
|
|||||||
service: any;
|
service: any;
|
||||||
namespace: any;
|
namespace: any;
|
||||||
|
|
||||||
constructor(private folderService: FolderService, private deviceServce: DeviceService) { }
|
constructor(
|
||||||
|
private folderService: FolderService,
|
||||||
|
private deviceServce: DeviceService,
|
||||||
|
private filterService: FilterService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
onItemSelect(state: string) {
|
||||||
|
// Send chart item state to filter
|
||||||
|
this.filterService.changeFilter({ type: this.type, text: state });
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case Type.Folder:
|
case StType.Folder:
|
||||||
this.title = "Folders";
|
this.title = "Folders";
|
||||||
this.chartID = 'foldersChart';
|
this.chartID = 'foldersChart';
|
||||||
this.service = this.folderService;
|
this.service = this.folderService;
|
||||||
break;
|
break;
|
||||||
case Type.Device:
|
case StType.Device:
|
||||||
this.title = "Devices";
|
this.title = "Devices";
|
||||||
this.chartID = 'devicesChart';
|
this.chartID = 'devicesChart';
|
||||||
this.service = this.deviceServce;
|
this.service = this.deviceServce;
|
||||||
@ -55,10 +65,10 @@ export class ChartComponent implements OnInit {
|
|||||||
const state = t.state;
|
const state = t.state;
|
||||||
let color;
|
let color;
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case Type.Folder:
|
case StType.Folder:
|
||||||
color = Folder.stateTypeToColor(t.stateType);
|
color = Folder.stateTypeToColor(t.stateType);
|
||||||
break;
|
break;
|
||||||
case Type.Device:
|
case StType.Device:
|
||||||
color = Device.stateTypeToColor(stateType);
|
color = Device.stateTypeToColor(stateType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -73,7 +83,6 @@ export class ChartComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
console.log(color, "look!!!")
|
|
||||||
this.states.push({ label: state, count: 1, color: color });
|
this.states.push({ label: state, count: 1, color: color });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { SystemConfigService } from '../services/system-config.service';
|
import { SystemConfigService } from '../services/system-config.service';
|
||||||
import { Type } from '../type';
|
import { StType } from '../type';
|
||||||
|
import { FilterService } from '../services/filter.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrls: ['./dashboard.component.scss']
|
styleUrls: ['./dashboard.component.scss'],
|
||||||
|
providers: [FilterService]
|
||||||
})
|
})
|
||||||
export class DashboardComponent {
|
export class DashboardComponent {
|
||||||
folderChart: Type = Type.Folder;
|
folderChart: StType = StType.Folder;
|
||||||
deviceChart: Type = Type.Device;
|
deviceChart: StType = StType.Device;
|
||||||
|
|
||||||
constructor(private systemConfigService: SystemConfigService) { }
|
constructor(private systemConfigService: SystemConfigService) { }
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<mat-button-toggle-group class="tui-button-toggle" name="fontStyle" aria-label="Font Style" value="folders">
|
<mat-button-toggle-group class="tui-button-toggle" name="fontStyle" aria-label="Font Style" value="{{toggleValue}}">
|
||||||
<mat-button-toggle value="folders" (click)="onSelect(listType.Folder)">Folders</mat-button-toggle>
|
<mat-button-toggle value="folders" (click)="onSelect(listType.Folder)">Folders</mat-button-toggle>
|
||||||
<mat-button-toggle value="devices" (click)="onSelect(listType.Device)">Devices</mat-button-toggle>
|
<mat-button-toggle value="devices" (click)="onSelect(listType.Device)">Devices</mat-button-toggle>
|
||||||
</mat-button-toggle-group>
|
</mat-button-toggle-group>
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
import { Type } from '../type';
|
import { StType } from '../type';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -10,22 +10,15 @@ import { Type } from '../type';
|
|||||||
})
|
})
|
||||||
|
|
||||||
export class ListToggleComponent implements OnInit {
|
export class ListToggleComponent implements OnInit {
|
||||||
public listType = Type;
|
public listType = StType;
|
||||||
@Output() listTypeEvent = new EventEmitter<Type>();
|
public toggleValue: string = "folders";
|
||||||
|
@Output() listTypeEvent = new EventEmitter<StType>();
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelect(t: Type): void {
|
onSelect(t: StType): void {
|
||||||
this.listTypeEvent.emit(t);
|
this.listTypeEvent.emit(t);
|
||||||
switch (t) {
|
|
||||||
case Type.Folder:
|
|
||||||
console.log("folder action");
|
|
||||||
break;
|
|
||||||
case Type.Device:
|
|
||||||
console.log("Device action");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Filter</mat-label>
|
<mat-label>Filter</mat-label>
|
||||||
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Up to Date">
|
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Up to Date" value="{{filterValue}}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
||||||
<!-- Id Column -->
|
<!-- Id Column -->
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
||||||
|
|
||||||
import Device from '../../device';
|
import Device from '../../device';
|
||||||
import { SystemConfigService } from '../../services/system-config.service';
|
import { SystemConfigService } from '../../services/system-config.service';
|
||||||
|
import { FilterService } from 'src/app/services/filter.service';
|
||||||
|
import { StType } from 'src/app/type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-device-list',
|
selector: 'app-device-list',
|
||||||
@ -16,11 +18,16 @@ export class DeviceListComponent implements AfterViewInit, OnInit {
|
|||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
@ViewChild(MatTable) table: MatTable<Device>;
|
@ViewChild(MatTable) table: MatTable<Device>;
|
||||||
dataSource: MatTableDataSource<Device>;
|
dataSource: MatTableDataSource<Device>;
|
||||||
|
filterValue: string = "";
|
||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns = ['id', 'name', 'state'];
|
displayedColumns = ['id', 'name', 'state'];
|
||||||
|
|
||||||
constructor(private systemConfigService: SystemConfigService) { };
|
constructor(
|
||||||
|
private systemConfigService: SystemConfigService,
|
||||||
|
private filterService: FilterService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
|
) { };
|
||||||
|
|
||||||
applyFilter(event: Event) {
|
applyFilter(event: Event) {
|
||||||
const filterValue = (event.target as HTMLInputElement).value;
|
const filterValue = (event.target as HTMLInputElement).value;
|
||||||
@ -42,5 +49,15 @@ export class DeviceListComponent implements AfterViewInit, OnInit {
|
|||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource.paginator = this.paginator;
|
||||||
this.table.dataSource = this.dataSource;
|
this.table.dataSource = this.dataSource;
|
||||||
|
|
||||||
|
// Listen for filter changes from other components
|
||||||
|
this.filterService.filterChanged$.subscribe(
|
||||||
|
input => {
|
||||||
|
if (input.type === StType.Device) {
|
||||||
|
this.dataSource.filter = input.text.trim().toLowerCase();
|
||||||
|
this.filterValue = input.text;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Filter</mat-label>
|
<mat-label>Filter</mat-label>
|
||||||
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Up to Date">
|
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Up to Date" value="{{filterValue}}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
||||||
<!-- Id Column -->
|
<!-- Id Column -->
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { AfterViewInit, Component, OnInit, ViewChild, Input } from '@angular/core';
|
import { AfterViewInit, Component, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
||||||
|
|
||||||
import Folder from '../../folder';
|
import Folder from '../../folder';
|
||||||
import { SystemConfigService } from '../../services/system-config.service';
|
import { SystemConfigService } from '../../services/system-config.service';
|
||||||
|
import { FilterService } from 'src/app/services/filter.service';
|
||||||
|
import { StType } from 'src/app/type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-folder-list',
|
selector: 'app-folder-list',
|
||||||
@ -16,11 +18,17 @@ export class FolderListComponent implements AfterViewInit, OnInit {
|
|||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
@ViewChild(MatTable) table: MatTable<Folder>;
|
@ViewChild(MatTable) table: MatTable<Folder>;
|
||||||
dataSource: MatTableDataSource<Folder>;
|
dataSource: MatTableDataSource<Folder>;
|
||||||
|
filterValue: string = "";
|
||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns = ['id', 'label', 'path', 'state'];
|
displayedColumns = ['id', 'label', 'path', 'state'];
|
||||||
|
|
||||||
constructor(private systemConfigService: SystemConfigService) { };
|
constructor(
|
||||||
|
private systemConfigService: SystemConfigService,
|
||||||
|
private filterService: FilterService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
|
) {
|
||||||
|
};
|
||||||
|
|
||||||
applyFilter(event: Event) {
|
applyFilter(event: Event) {
|
||||||
const filterValue = (event.target as HTMLInputElement).value;
|
const filterValue = (event.target as HTMLInputElement).value;
|
||||||
@ -42,5 +50,16 @@ export class FolderListComponent implements AfterViewInit, OnInit {
|
|||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource.paginator = this.paginator;
|
||||||
this.table.dataSource = this.dataSource;
|
this.table.dataSource = this.dataSource;
|
||||||
|
|
||||||
|
// Listen for filter changes from other components
|
||||||
|
this.filterService.filterChanged$
|
||||||
|
.subscribe(
|
||||||
|
input => {
|
||||||
|
if (input.type === StType.Folder) {
|
||||||
|
this.dataSource.filter = input.text.trim().toLowerCase();
|
||||||
|
this.filterValue = input.text;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, ViewChild, AfterViewInit } from '@angular/core';
|
||||||
import { Type } from '../../type';
|
import { StType } from '../../type';
|
||||||
import { cardElevation } from '../../style';
|
import { cardElevation } from '../../style';
|
||||||
|
import { FilterService } from 'src/app/services/filter.service';
|
||||||
|
import { ListToggleComponent } from 'src/app/list-toggle/list-toggle.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -8,18 +10,33 @@ import { cardElevation } from '../../style';
|
|||||||
templateUrl: './status-list.component.html',
|
templateUrl: './status-list.component.html',
|
||||||
styleUrls: ['./status-list.component.scss']
|
styleUrls: ['./status-list.component.scss']
|
||||||
})
|
})
|
||||||
export class StatusListComponent implements OnInit {
|
export class StatusListComponent {
|
||||||
currentListType: Type = Type.Folder;
|
@ViewChild(ListToggleComponent) toggle: ListToggleComponent;
|
||||||
listType = Type; // used in html
|
currentListType: StType = StType.Folder;
|
||||||
|
listType = StType; // used in html
|
||||||
elevation: string = cardElevation;
|
elevation: string = cardElevation;
|
||||||
title: string = 'Status';
|
title: string = 'Status';
|
||||||
|
|
||||||
constructor() { }
|
constructor(private filterService: FilterService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngAfterViewInit() {
|
||||||
|
// Listen for filter changes from other components
|
||||||
|
this.filterService.filterChanged$.subscribe(
|
||||||
|
input => {
|
||||||
|
this.currentListType = input.type;
|
||||||
|
|
||||||
|
switch (input.type) {
|
||||||
|
case StType.Folder:
|
||||||
|
this.toggle.toggleValue = "folders";
|
||||||
|
break;
|
||||||
|
case StType.Device:
|
||||||
|
this.toggle.toggleValue = "devices";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggle(t: Type) {
|
onToggle(t: StType) {
|
||||||
this.currentListType = t;
|
this.currentListType = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/app/services/filter.service.spec.ts
Normal file
16
src/app/services/filter.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FilterService } from './filter.service';
|
||||||
|
|
||||||
|
describe('FilterService', () => {
|
||||||
|
let service: FilterService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(FilterService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
25
src/app/services/filter.service.ts
Normal file
25
src/app/services/filter.service.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { StType } from '../type';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
|
||||||
|
export interface FilterInput {
|
||||||
|
type: StType;
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FilterService {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
private filterChangeSource = new BehaviorSubject<FilterInput>({ type: StType.Folder, text: "" });
|
||||||
|
|
||||||
|
filterChanged$ = this.filterChangeSource.asObservable();
|
||||||
|
|
||||||
|
changeFilter(input: FilterInput) {
|
||||||
|
this.filterChangeSource.next(input);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
export enum Type {
|
export enum StType {
|
||||||
Folder = 1,
|
Folder = 1,
|
||||||
Device,
|
Device,
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user