feat: adds table view
feat: adds table view
This commit is contained in:
@@ -22,8 +22,8 @@ const routes: Routes = [
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'followings',
|
||||
loadChildren: () => import('./followings/followings.module').then(m => m.FollowingsModule),
|
||||
path: 'list',
|
||||
loadChildren: () => import('./followings-list/followings-list.module').then(m => m.FollowingsListModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
@@ -31,6 +31,11 @@ const routes: Routes = [
|
||||
loadChildren: () => import('./followings-matrix/followings-matrix.module').then(m => m.FollowingsMatrixModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'table',
|
||||
loadChildren: () => import('./followings-table/followings-table.module').then(m => m.FollowingsTableModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {Component, isDevMode} from '@angular/core';
|
||||
import {select, Store} from "@ngrx/store";
|
||||
import {Store} from "@ngrx/store";
|
||||
import {MastodonApiActions} from "./shared/state/store/actions";
|
||||
import {Observable, tap} from "rxjs";
|
||||
import {selectLoadingPercentage} from "./shared/state/store/selectors";
|
||||
import {PersistentStore} from "./shared/state/persistent/persistent-store.service";
|
||||
|
||||
@Component({
|
||||
@@ -16,8 +14,9 @@ export class AppComponent {
|
||||
navigationItems = [
|
||||
{title: 'Authorize', link: '/auth'},
|
||||
{title: 'Stats', link: '/sync'},
|
||||
{title: 'List view', link: '/followings'},
|
||||
{title: 'List view', link: '/list'},
|
||||
{title: 'Matrix View', link: '/matrix'},
|
||||
{title: 'Table View', link: '/table'},
|
||||
];
|
||||
|
||||
constructor(private store: Store, private persistentStore: PersistentStore) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {FollowingsComponent} from "./followings/followings.component";
|
||||
import {ListComponent} from "./list/list.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: FollowingsComponent
|
||||
component: ListComponent
|
||||
}
|
||||
];
|
||||
|
||||
@@ -13,5 +13,5 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class FollowingsRoutingModule {
|
||||
export class FollowingsListRoutingModule {
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {FollowingsComponent} from './followings/followings.component';
|
||||
import {ListComponent} from './list/list.component';
|
||||
import {SharedModule} from '../shared/shared.module';
|
||||
import {FollowingsRoutingModule} from './followings-routing.module';
|
||||
import {FollowingsListRoutingModule} from './followings-list-routing.module';
|
||||
import {NbListModule, NbToggleModule} from "@nebular/theme";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
FollowingsComponent
|
||||
ListComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
FollowingsRoutingModule,
|
||||
FollowingsListRoutingModule,
|
||||
// Nebula
|
||||
NbListModule,
|
||||
NbToggleModule,
|
||||
]
|
||||
})
|
||||
export class FollowingsModule {
|
||||
export class FollowingsListModule {
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FollowingsComponent } from './followings.component';
|
||||
import { ListComponent } from './list.component';
|
||||
|
||||
describe('FollowingsComponent', () => {
|
||||
let component: FollowingsComponent;
|
||||
let fixture: ComponentFixture<FollowingsComponent>;
|
||||
let component: ListComponent;
|
||||
let fixture: ComponentFixture<ListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FollowingsComponent ]
|
||||
declarations: [ ListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(FollowingsComponent);
|
||||
fixture = TestBed.createComponent(ListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -9,11 +9,11 @@ import {selectFilteredFollowingsWithLists, selectFollowings, selectFollowingsWit
|
||||
import {FiltersActions, ListActions, MastodonApiActions} from "../../shared/state/store/actions";
|
||||
|
||||
@Component({
|
||||
selector: 'app-followings',
|
||||
templateUrl: './followings.component.html',
|
||||
styleUrls: ['./followings.component.scss']
|
||||
selector: 'app-list',
|
||||
templateUrl: './list.component.html',
|
||||
styleUrls: ['./list.component.scss']
|
||||
})
|
||||
export class FollowingsComponent {
|
||||
export class ListComponent {
|
||||
followings$: Observable<ReadonlyArray<Account>>;
|
||||
lists$: Observable<ReadonlyArray<List>>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
table {
|
||||
display: block;
|
||||
height: max(600px, calc(100vh - 300px));
|
||||
width: 1080px;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
border: none;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {TableComponent} from "./table/table.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: TableComponent
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class FollowingsTableRoutingModule {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {TableComponent} from './table/table.component';
|
||||
import {SharedModule} from "../shared/shared.module";
|
||||
import {FollowingsTableRoutingModule} from "./followings-table-routing.module";
|
||||
import {NbUserModule} from "@nebular/theme";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
TableComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
FollowingsTableRoutingModule,
|
||||
// Nebular
|
||||
NbUserModule,
|
||||
]
|
||||
})
|
||||
export class FollowingsTableModule {
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<nb-card>
|
||||
<nb-card-header style="position: relative;">
|
||||
<h1>Table View for Followings</h1>
|
||||
<div class="divider"></div>
|
||||
<app-filters></app-filters>
|
||||
</nb-card-header>
|
||||
<nb-card-body>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Notes</th>
|
||||
<th>Fields</th>
|
||||
<th>Lists</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<tr *ngFor="let row of rows$ |async">
|
||||
<td>
|
||||
<a [href]="row.url">
|
||||
<nb-user
|
||||
size="medium"
|
||||
shape="semi-round"
|
||||
[name]="row.displayName"
|
||||
[title]="row.username"
|
||||
[picture]="row.avatar"
|
||||
>
|
||||
</nb-user>
|
||||
</a>
|
||||
</td>
|
||||
<td><span [innerHTML]="row.note"></span></td>
|
||||
<td><span [innerHTML]="row.fields"></span></td>
|
||||
<td>
|
||||
<div *ngFor="let list of row.lists">
|
||||
{{list.title}}
|
||||
<nb-icon icon="person-remove-outline" (click)="removeAccountFromList(row.id, list.id)">
|
||||
Remove Account from list
|
||||
</nb-icon>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="actions">
|
||||
<select class="list-select" #listSelect>
|
||||
<option *ngFor="let list of lists$ | async" [value]="list.id">{{list.title}}</option>
|
||||
</select>
|
||||
<nb-icon icon="person-add-outline" (click)="addAccountToSelectedList(row.id, listSelect.value)">
|
||||
Add Account to list
|
||||
</nb-icon>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
table {
|
||||
display: block;
|
||||
height: max(600px, calc(100vh - 300px));
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
border: none;
|
||||
|
||||
th {
|
||||
border: 1pt solid #101426;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1pt solid #101426;
|
||||
}
|
||||
}
|
||||
|
||||
div.actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
select {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TableComponent } from './table.component';
|
||||
|
||||
describe('TableComponent', () => {
|
||||
let component: TableComponent;
|
||||
let fixture: ComponentFixture<TableComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ TableComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {map, Observable} from "rxjs";
|
||||
import {Account} from "../../../../../mastodon-api/src/lib/interfaces/public/account";
|
||||
import {List} from "../../../../../mastodon-api/src/lib/interfaces/public/list";
|
||||
import {select, Store} from "@ngrx/store";
|
||||
import {selectFilteredFollowingsWithLists, selectLists} from "../../shared/state/store/selectors";
|
||||
import {ListActions} from "../../shared/state/store/actions";
|
||||
|
||||
interface DataGridRow {
|
||||
id: string;
|
||||
url: string;
|
||||
displayName: string;
|
||||
username: string;
|
||||
avatar: string;
|
||||
note: string;
|
||||
fields: string;
|
||||
lists: List[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-table',
|
||||
templateUrl: './table.component.html',
|
||||
styleUrls: ['./table.component.scss']
|
||||
})
|
||||
export class TableComponent {
|
||||
rows$: Observable<DataGridRow[]>;
|
||||
lists$: Observable<ReadonlyArray<List>>;
|
||||
|
||||
constructor(private store: Store) {
|
||||
this.rows$ = this.store
|
||||
.pipe(
|
||||
select(selectFilteredFollowingsWithLists),
|
||||
map((accounts: ReadonlyArray<Account>) => {
|
||||
return accounts.map((account) => {
|
||||
return {
|
||||
id: account.id,
|
||||
username: `@${account.username}`,
|
||||
displayName: account.displayName,
|
||||
url: account.url,
|
||||
avatar: account.avatar,
|
||||
note: account.note,
|
||||
fields: account.fields.map(field => `${field.name}: ${field.value}`).join('<br>'),
|
||||
lists: account.lists,
|
||||
} as DataGridRow;
|
||||
});
|
||||
}),
|
||||
);
|
||||
this.lists$ = this.store.pipe(select(selectLists));
|
||||
}
|
||||
|
||||
addAccountToSelectedList(accountId: string, listId: string) {
|
||||
this.store.dispatch(ListActions.addAccountToList({accountId, listId}));
|
||||
}
|
||||
|
||||
removeAccountFromList(accountId: string, listId: string) {
|
||||
this.store.dispatch(ListActions.removeAccountFromList({accountId, listId}));
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
<ul>
|
||||
<li><a [routerLink]="['/auth']">Authorize</a> with your instance</li>
|
||||
<li><a [routerLink]="['/sync']">Sync</a> your lists and followings to local storage</li>
|
||||
<li>Select the <a [routerLink]="['/followings']">List view</a> to add and remove users from lists</li>
|
||||
<li>Select the <a [routerLink]="['/list']">List view</a> to add and remove users from lists</li>
|
||||
<li>... or use the experimental <a [routerLink]="['/matrix']">Matrix view</a></li>
|
||||
</ul>
|
||||
</nb-card-body>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div *ngIf="(lists$ | async) && (followings$ | async)">
|
||||
<p>Now you can:</p>
|
||||
<ul>
|
||||
<li>Select the <a [routerLink]="['/followings']">List view</a> to add and remove users from lists</li>
|
||||
<li>Select the <a [routerLink]="['/list']">List view</a> to add and remove users from lists</li>
|
||||
<li>... or use the experimental <a [routerLink]="['/matrix']">Matrix view</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ $nb-themes: nb-register-theme(
|
||||
(
|
||||
font-family-primary: 'Inter',
|
||||
font-family-secondary: 'Inter',
|
||||
layout-content-width: 1200px,
|
||||
layout-content-width: 100vw,
|
||||
),
|
||||
dark,
|
||||
dark
|
||||
|
||||
Reference in New Issue
Block a user