|  | /** | 
|  | * @license | 
|  | * Copyright 2025 Google LLC | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  | import {BehaviorSubject, combineLatest, from, Observable, of} from 'rxjs'; | 
|  | import {catchError, map, shareReplay, switchMap} from 'rxjs/operators'; | 
|  | import {ChangeModel} from '../change/change-model'; | 
|  | import {FlowInfo, FlowInput} from '../../api/rest-api'; | 
|  | import {Model} from '../base/model'; | 
|  | import {define} from '../dependency'; | 
|  |  | 
|  | import {NumericChangeId} from '../../types/common'; | 
|  | import {getAppContext} from '../../services/app-context'; | 
|  |  | 
|  | export interface FlowsState { | 
|  | isEnabled: boolean; | 
|  | flows: FlowInfo[]; | 
|  | loading: boolean; | 
|  | errorMessage?: string; | 
|  | } | 
|  |  | 
|  | export const flowsModelToken = define<FlowsModel>('flows-model'); | 
|  |  | 
|  | export class FlowsModel extends Model<FlowsState> { | 
|  | readonly flows$ = this.state$.pipe(map(s => s.flows)); | 
|  |  | 
|  | readonly loading$ = this.state$.pipe(map(s => s.loading)); | 
|  |  | 
|  | readonly enabled$: Observable<boolean>; | 
|  |  | 
|  | private readonly reload$ = new BehaviorSubject<void>(undefined); | 
|  |  | 
|  | private changeNum?: NumericChangeId; | 
|  |  | 
|  | private readonly restApiService = getAppContext().restApiService; | 
|  |  | 
|  | constructor(private readonly changeModel: ChangeModel) { | 
|  | super({ | 
|  | isEnabled: false, | 
|  | flows: [], | 
|  | loading: true, | 
|  | }); | 
|  |  | 
|  | this.enabled$ = this.changeModel.changeNum$.pipe( | 
|  | switchMap(changeNum => { | 
|  | if (!changeNum) { | 
|  | return of(false); | 
|  | } | 
|  | return from(this.restApiService.getIfFlowsIsEnabled(changeNum)).pipe( | 
|  | map(res => res?.enabled ?? false), | 
|  | catchError(() => of(false)) | 
|  | ); | 
|  | }), | 
|  | shareReplay(1) | 
|  | ); | 
|  |  | 
|  | this.subscriptions.push( | 
|  | this.enabled$.subscribe(isEnabled => { | 
|  | this.setState({...this.getState(), isEnabled}); | 
|  | }) | 
|  | ); | 
|  |  | 
|  | this.subscriptions.push( | 
|  | this.changeModel.changeNum$.subscribe(changeNum => { | 
|  | this.changeNum = changeNum; | 
|  | }) | 
|  | ); | 
|  |  | 
|  | this.subscriptions.push( | 
|  | combineLatest([this.changeModel.changeNum$, this.reload$, this.enabled$]) | 
|  | .pipe( | 
|  | switchMap(([changeNum, _, enabled]) => { | 
|  | if (!changeNum || !enabled) return of([]); | 
|  | this.setState({...this.getState(), loading: true}); | 
|  | return from(this.restApiService.listFlows(changeNum)).pipe( | 
|  | catchError(err => { | 
|  | this.setState({ | 
|  | ...this.getState(), | 
|  | errorMessage: `Failed to load flows: ${err}`, | 
|  | loading: false, | 
|  | }); | 
|  | return of([]); | 
|  | }) | 
|  | ); | 
|  | }) | 
|  | ) | 
|  | .subscribe(flows => { | 
|  | this.setState({ | 
|  | ...this.getState(), | 
|  | flows: flows ?? [], | 
|  | loading: false, | 
|  | }); | 
|  | }) | 
|  | ); | 
|  | } | 
|  |  | 
|  | reload() { | 
|  | this.reload$.next(); | 
|  | } | 
|  |  | 
|  | async deleteFlow(flowId: string) { | 
|  | if (!this.changeNum) return; | 
|  | if (!this.getState().isEnabled) return; | 
|  | await this.restApiService.deleteFlow(this.changeNum, flowId); | 
|  | this.reload(); | 
|  | } | 
|  |  | 
|  | async createFlow(flowInput: FlowInput) { | 
|  | if (!this.changeNum) return; | 
|  | if (!this.getState().isEnabled) return; | 
|  | await this.restApiService.createFlow(this.changeNum, flowInput); | 
|  | this.reload(); | 
|  | } | 
|  | } |