-
Notifications
You must be signed in to change notification settings - Fork 36
feat(frontend): per-tab persisted table state + returnUrl round-trip #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2acd306
47e4b04
9babb00
1ed5f1b
1fe6335
9e3e9c6
92ed92a
3bbef32
2bb9e0f
7ce85b6
1f3b314
9e159bf
ab06198
f297938
51d5335
65a66f6
cf6f669
436f229
779a590
be3585c
b7a0476
a4f74dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; | ||
| import { AfterViewInit, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; | ||
| import { Table, TableModule } from 'primeng/table'; | ||
| import { FormsModule } from '@angular/forms'; | ||
| import { InputText, InputTextModule } from 'primeng/inputtext'; | ||
|
|
@@ -34,6 +34,10 @@ import { combineLatest, skip } from 'rxjs'; | |
| import { Tag } from '@buf/xskydev_go-money-pb.bufbuild_es/gomoneypb/v1/tag_pb'; | ||
| import { TagsService } from '@buf/xskydev_go-money-pb.bufbuild_es/gomoneypb/tags/v1/tags_pb'; | ||
| import { FancyTagComponent } from '../../shared/components/fancy-tag/fancy-tag.component'; | ||
| import { ReturnUrlHelper } from '../../shared/helpers/return-url.helper'; | ||
| import { TableQueryStateHelper } from '../../shared/helpers/table-query-state.helper'; | ||
| import { TableStatePersistence } from '../../shared/helpers/table-state-persistence.helper'; | ||
| import { TabSessionService } from '../../shared/services/tab-session.service'; | ||
|
|
||
| @Component({ | ||
| selector: 'app-account-list', | ||
|
|
@@ -62,7 +66,7 @@ import { FancyTagComponent } from '../../shared/components/fancy-tag/fancy-tag.c | |
| } | ||
| ` | ||
| }) | ||
| export class AccountsListComponent implements OnInit { | ||
| export class AccountsListComponent implements OnInit, AfterViewInit { | ||
| @ViewChild('dt1', { static: false }) table!: Table; | ||
|
|
||
| statuses: any[] = []; | ||
|
|
@@ -93,13 +97,15 @@ export class AccountsListComponent implements OnInit { | |
| @ViewChild('filter') filter!: ElementRef; | ||
| public analyticsMap: { [accountId: number]: GetDebitsAndCreditsSummaryResponse_SummaryItem } = {}; | ||
| public serverConfig: GetConfigurationResponse = create(GetConfigurationResponseSchema, {}); | ||
| public initialGlobalFilter: string = ''; | ||
|
|
||
| constructor( | ||
| @Inject(TRANSPORT_TOKEN) private transport: Transport, | ||
| private messageService: MessageService, | ||
| public router: Router, | ||
| route: ActivatedRoute, | ||
| private selectedDateService: SelectedDateService | ||
| private selectedDateService: SelectedDateService, | ||
| private tabSession: TabSessionService | ||
| ) { | ||
| this.accountService = createClient(AccountsService, this.transport); | ||
| this.analyticsService = createClient(AnalyticsService, this.transport); | ||
|
|
@@ -113,12 +119,62 @@ export class AccountsListComponent implements OnInit { | |
| } | ||
| } | ||
| } | ||
|
|
||
| if (route.snapshot.queryParamMap.get('restore') === '1') { | ||
| const stored = TableStatePersistence.read(this.stateKey, this.tabSession.id); | ||
| if (stored) { | ||
| if (stored.filters) this.filters = { ...this.filters, ...(stored.filters as { [s: string]: FilterMetadata }) }; | ||
| if (stored.sort && stored.sort.length > 0) this.multiSortMeta = stored.sort; | ||
| if (stored.global) this.initialGlobalFilter = stored.global; | ||
| const tagIds = stored.extra?.['tagIds']; | ||
| if (Array.isArray(tagIds)) this.selectedTagIds = tagIds as number[]; | ||
| } | ||
| TableStatePersistence.clear(this.stateKey, this.tabSession.id); | ||
| this.router.navigate([], { relativeTo: route, queryParams: { restore: null }, queryParamsHandling: 'merge', replaceUrl: true }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
|
|
||
| const queryState = TableQueryStateHelper.decode(route.snapshot.queryParams); | ||
| if (queryState.filters) { | ||
| this.filters = { ...this.filters, ...(queryState.filters as { [s: string]: FilterMetadata }) }; | ||
| } | ||
| if (queryState.sort && queryState.sort.length > 0) { | ||
| this.multiSortMeta = queryState.sort; | ||
| } | ||
| if (queryState.global) { | ||
| this.initialGlobalFilter = queryState.global; | ||
| } | ||
|
skynet2 marked this conversation as resolved.
|
||
| } | ||
|
Comment on lines
+123
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic for restoring table state from |
||
|
|
||
| private readonly stateKey = 'accounts'; | ||
|
|
||
| ngAfterViewInit() { | ||
| if (this.initialGlobalFilter && this.table) { | ||
| if (this.filter?.nativeElement) { | ||
| this.filter.nativeElement.value = this.initialGlobalFilter; | ||
| } | ||
| this.table.filterGlobal(this.initialGlobalFilter, 'contains'); | ||
| } | ||
| } | ||
|
Comment on lines
+150
to
+157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling ngAfterViewInit() {
if (this.initialGlobalFilter && this.table) {
setTimeout(() => {
if (this.filter?.nativeElement) {
this.filter.nativeElement.value = this.initialGlobalFilter;
}
this.table.filterGlobal(this.initialGlobalFilter, 'contains');
});
}
} |
||
|
|
||
| syncStateToUrl(): void { | ||
| if (!this.table) return; | ||
| const globalVal = (this.table.filters as any)?.['global']?.value; | ||
| TableStatePersistence.write(this.stateKey, this.tabSession.id, { | ||
| filters: this.table.filters as { [f: string]: FilterMetadata | FilterMetadata[] }, | ||
| sort: this.table.multiSortMeta ?? [], | ||
| global: typeof globalVal === 'string' ? globalVal : undefined, | ||
| extra: { tagIds: this.selectedTagIds }, | ||
| }); | ||
| } | ||
|
|
||
| getAccountUrl(account: ListAccountsResponse_AccountItem): string { | ||
| return this.router.createUrlTree(['/', 'accounts', account.account!.id.toString()]).toString(); | ||
| } | ||
|
|
||
| public get currentReturnUrl(): string { | ||
| return ReturnUrlHelper.build(this.router); | ||
| } | ||
|
|
||
| async ngOnInit() { | ||
| await this.loadTags(); | ||
| await this.loadConfig(); | ||
|
|
@@ -153,6 +209,7 @@ export class AccountsListComponent implements OnInit { | |
| } | ||
|
|
||
| async onTagFilterChange() { | ||
| this.syncStateToUrl(); | ||
| await this.loadAccounts(); | ||
| await this.loadAnalytics(); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.