added state to filters

This commit is contained in:
Lucio Lelii 2026-01-19 12:50:41 +01:00
parent 76e7806d3d
commit 240de8a6e2
7 changed files with 145 additions and 16 deletions

View File

@ -4,6 +4,7 @@ import { FlowsList } from '@shared/flows-list/flows-list';
import { EditorStateHolder } from '@stores/flow-editor';
import { CommonModule } from '@angular/common';
import { FlowsService } from '@services/flows/flows';
import { ListState } from '@stores/list-state';
type OpenedId = 'flows' | 'blocks';
@ -12,6 +13,7 @@ type OpenedId = 'flows' | 'blocks';
imports: [GroupHolder, FlowsList, CommonModule],
templateUrl: './editor-sidebar.html',
styleUrl: './editor-sidebar.css',
providers:[ListState]
})
export class EditorSidebar {

View File

@ -41,7 +41,7 @@
</div>
<div class="flex pt-2 pb-1 text-sm w-full items-center text-center justify-center">
<app-ordering [orderFields]="orderFields" (orderChanged)="onOrderChanged($event)"></app-ordering>
<app-ordering [orderFields]="orderFields" [orderView]="orderView" (orderChanged)="onOrderChanged($event)" ></app-ordering>
</div>
@if (filteredFlows().length === 0) {
<div class="text-gray-400 text-center mt-10 flex flex-col flex-1 pt-10">

View File

@ -1,10 +1,11 @@
import { CommonModule } from '@angular/common';
import { Component, computed, inject, model, output, signal, Signal, WritableSignal } from '@angular/core';
import { Component, computed, effect, inject, model, output, signal, Signal, WritableSignal } from '@angular/core';
import { Flow } from '@models/flow';
import { FlowsService } from '@services/flows/flows';
import { FlowItem } from './flow-item/flow-item';
import { FormsModule } from '@angular/forms';
import { OrderEvent, OrderField, Ordering } from "@shared/ordering/ordering";
import { ListStateViewHolder, OrderViewState } from '@utilities/list-state-holder';
type FlowFilter = 'all' | 'public' | 'private';
@ -14,42 +15,71 @@ type FlowFilter = 'all' | 'public' | 'private';
templateUrl: './flows-list.html',
styleUrl: './flows-list.css',
})
export class FlowsList {
export class FlowsList extends ListStateViewHolder<Flow> {
filter = signal<FlowFilter>('all');
orderFields : OrderField[] = [
orderFields: OrderField[] = [
{ field: 'name', label: 'Name' },
{ field: 'updatedAt', label: 'Last Update Date' },
{ field: 'createdAt', label: 'Creation Date' }
];
searchTerm = model<string>('');
private flowsService = inject(FlowsService);
loading: WritableSignal<boolean> = signal(true);
flows: Signal<Flow[] | null> = signal(null);
get orderView() {
const existingState = this.view;
return existingState.order;
}
flows?: Signal<Flow[]>;
detailOpenedId = signal<string | null>(null);
ngOnInit() {
this.flowsService.getAllFlows().then(flowsSignal => {
this.flows = flowsSignal;
this.loading.set(false);
constructor() {
super('flowsList', {defaultOrder: { orderBy: 'name', orderDir: 'asc' } as OrderViewState, defaultFilter: 'all'});
effect(() => {
if (!!this.filter && this.filter() != null)
this.view.filter = this.filter();
});
}
ngOnInit() {
const existingState = this.view;
if (existingState.list) {
this.flows = existingState.list;
this.loading.set(false);
if (existingState.filter)
this.filter.set(existingState.filter as FlowFilter || 'all');
console.log('FlowsList loaded from ListState');
} else {
this.flowsService.getAllFlows().then(flowsSignal => {
this.flows = flowsSignal;
this.loading.set(false);
this.view.list = this.flows;
console.log('FlowsList initialized from service');
});
}
}
filteredFlows = computed(() => {
const flows = this.flows();
const flows = this.flows ? this.flows() : [];
if (!flows) return [];
const filteredFlows = flows.filter(f => f.name.toLowerCase().includes(this.searchTerm().toLowerCase()));
if (this.filter() === 'all') return filteredFlows;
return filteredFlows.filter(f => f.visibility === this.filter());
});
onOrderChanged(event: OrderEvent) {
const { orderBy, orderDir } = event;
this.view.order = { orderBy, orderDir };
const flows = this.filteredFlows();
if (!orderBy) return flows;
return flows.sort((a, b) => {
@ -58,7 +88,7 @@ export class FlowsList {
if (aValue < bValue) return orderDir === 'asc' ? -1 : 1;
if (aValue > bValue) return orderDir === 'asc' ? 1 : -1;
return 0;
});
});
}
}

View File

@ -1,6 +1,6 @@
import { Component, effect, input, model, output } from '@angular/core';
import { Component, effect, Input, input, model, output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { OrderViewState } from '@utilities/list-state-holder';
export type OrderEvent = { orderBy: string | null; orderDir: orderDirType };
export type orderDirType = 'asc' | 'desc';
@ -15,6 +15,8 @@ export type OrderField = { field: string; label?: string };
})
export class Ordering {
@Input({required : true}) orderView!: OrderViewState;
constructor() {
effect(() => {
this.orderChanged.emit({ orderBy: this.orderBy(), orderDir: this.orderDir() });
@ -27,6 +29,13 @@ export class Ordering {
orderBy = model<string | null>(null);
ngOnInit() {
if (this.orderView.orderBy) {
this.orderBy.set(this.orderView.orderBy);
this.orderDir.set(this.orderView.orderDir);
}
}
orderChanged = output<OrderEvent>();
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ListState } from './list-state';
describe('ListState', () => {
let service: ListState;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ListState);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,34 @@
import { Injectable, Signal, signal } from '@angular/core';
import { ListView, OrderViewState } from '@utilities/list-state-holder';
@Injectable()
export class ListState {
private states = new Map<string, ListView<any>>();
get<T>(kind?: string): ListView<T> | null {
if (!this.states.has(kind || 'default')) {
return null;
}
return this.states.get(kind || 'default')!;
}
create<T>(kind?: string, options?: {defaultOrder?: OrderViewState, defaultFilter?: string}) {
if (!this.states.has(kind || 'default')) {
const view = new ListView<T>();
if (options) {
if (options.defaultOrder) {
view.order = options.defaultOrder;
}
if (options.defaultFilter) {
view.filter = options.defaultFilter;
}
}
this.states.set(kind || 'default', view);
}
}
}

View File

@ -0,0 +1,38 @@
import { inject, signal, Signal } from "@angular/core";
import { ListState } from "@stores/list-state";
export class OrderViewState {
orderBy: string | null = null;
orderDir: 'asc' | 'desc' = 'asc';
}
export class ListView<T> {
filter?: string;
list?: Signal<T[]>;
order: OrderViewState = new OrderViewState();
}
export class ListStateViewHolder<T> {
private state: ListView<T> = new ListView<T>();
listName?: string;
constructor(listName?: string, options?: {defaultOrder?: OrderViewState, defaultFilter?: string}) {
this.listName = listName;
const listState = inject(ListState);
if (listState.get<T>(this.listName) == null) {
listState.create<T>(this.listName, options);
}
this.state = listState.get<T>(this.listName)!;
}
get view(): ListView<T> {
return this.state;
}
create() {
this.state = new ListView<T>();
}
}