diff --git a/package-lock.json b/package-lock.json index 89dc67a..0825001 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@angular/common": "^21.0.4", "@angular/compiler": "^21.0.4", "@angular/core": "^21.0.4", + "@angular/elements": "^21.0.8", "@angular/forms": "^21.0.4", "@angular/platform-browser": "^21.0.4", "@angular/platform-browser-dynamic": "^21.0.4", @@ -22,6 +23,8 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-angular": "^0.561.0", + "rete-angular-plugin": "^2.6.0", + "rete-render-utils": "^2.0.3", "rxjs": "~7.8.0", "tailwind-merge": "^3.4.0", "tslib": "^2.3.0" @@ -597,6 +600,22 @@ } } }, + "node_modules/@angular/elements": { + "version": "21.0.8", + "resolved": "https://registry.npmjs.org/@angular/elements/-/elements-21.0.8.tgz", + "integrity": "sha512-eOvxX5eQw5u5Dp1UT6hhv7OSH6P/xzWb4MwiKS8fZhAJs0CNY3WtJfKTJCFJ3vwIk0zIoqz52OV1lrT6fuozHQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.0.8", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/@angular/forms": { "version": "21.0.5", "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.0.5.tgz", @@ -1001,6 +1020,15 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -8207,6 +8235,62 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/rete": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/rete/-/rete-2.0.6.tgz", + "integrity": "sha512-kPmlKCGFES2VWtY7Y7SCB8ZeXRMsgX5deza9cu4OwmfM/ZUimd461kC3hRyccoyVxE4POlHUx0gg2jcGfusHFg==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + } + }, + "node_modules/rete-angular-plugin": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/rete-angular-plugin/-/rete-angular-plugin-2.6.0.tgz", + "integrity": "sha512-0GdYJbuo2V6mmN1ylzW/WUOetncAPWmZPpj+l2yw9sPUPpr/QtfBnXxUXje4cnY1ws7foq2gYeWsNnoClutUSw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">= 12 < 22", + "@angular/core": ">= 12 < 22", + "@angular/elements": ">= 12 < 22", + "rete": "^2.0.1", + "rete-area-plugin": "^2.0.0", + "rete-render-utils": "^2.0.0", + "rxjs": ">=6.6.0", + "zone.js": "~0.11.4 || ~0.12.0 || ~0.13.0 || ~0.14.0 || ~0.15.0 || ~0.16.0" + } + }, + "node_modules/rete-area-plugin": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/rete-area-plugin/-/rete-area-plugin-2.1.5.tgz", + "integrity": "sha512-iquEvwkQlcsO4cmgM3Z37TG0AWaE536dfA+lCJAze5YJzVx4RBaViUCqdB4dUA/utSytpBCkiDC4D3ztM9akGQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "peerDependencies": { + "rete": "^2.0.0" + } + }, + "node_modules/rete-render-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/rete-render-utils/-/rete-render-utils-2.0.3.tgz", + "integrity": "sha512-Oz4W2PNayHocRvlzadb5BCNf+tDzJ8RhTwB3ucBPCdCLKZ974wWDiTSCRfA287L2hmHVzRfBdyAwC03K9eP+4g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "peerDependencies": { + "rete": "^2.0.0", + "rete-area-plugin": "^2.0.0" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -10155,6 +10239,13 @@ "peerDependencies": { "zod": "^3.25 || ^4" } + }, + "node_modules/zone.js": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.16.0.tgz", + "integrity": "sha512-LqLPpIQANebrlxY6jKcYKdgN5DTXyyHAKnnWWjE5pPfEQ4n7j5zn7mOEEpwNZVKGqx3kKKmvplEmoBrvpgROTA==", + "license": "MIT", + "peer": true } } } diff --git a/package.json b/package.json index 4f270ca..6cacd68 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@angular/common": "^21.0.4", "@angular/compiler": "^21.0.4", "@angular/core": "^21.0.4", + "@angular/elements": "^21.0.8", "@angular/forms": "^21.0.4", "@angular/platform-browser": "^21.0.4", "@angular/platform-browser-dynamic": "^21.0.4", @@ -37,6 +38,8 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-angular": "^0.561.0", + "rete-angular-plugin": "^2.6.0", + "rete-render-utils": "^2.0.3", "rxjs": "~7.8.0", "tailwind-merge": "^3.4.0", "tslib": "^2.3.0" diff --git a/src/app/layouts/flow-editor/flow-editor.html b/src/app/layouts/flow-editor/flow-editor.html index b7e28cf..909a776 100644 --- a/src/app/layouts/flow-editor/flow-editor.html +++ b/src/app/layouts/flow-editor/flow-editor.html @@ -7,15 +7,13 @@
-
- -
- + +
@if (flow()) {
-

{{ flow()?.name }}

+
} @else { diff --git a/src/app/layouts/flow-editor/flow-editor.ts b/src/app/layouts/flow-editor/flow-editor.ts index bab1f96..e36a39d 100644 --- a/src/app/layouts/flow-editor/flow-editor.ts +++ b/src/app/layouts/flow-editor/flow-editor.ts @@ -2,10 +2,11 @@ import { Component, inject } from '@angular/core'; import { Flow } from '@models/flow'; import { EditorSidebar } from "@pages/main/editor-sidebar/editor-sidebar"; import { EditorStateHolder } from 'app/stores/editor'; +import { TitleToolbar } from "@shared/title-toolbar/title-toolbar"; @Component({ selector: 'app-flow-editor', - imports: [EditorSidebar], + imports: [EditorSidebar, TitleToolbar], templateUrl: './flow-editor.html', styleUrl: './flow-editor.css', }) diff --git a/src/app/pages/main/editor-sidebar/editor-sidebar.css b/src/app/pages/main/editor-sidebar/editor-sidebar.css index e69de29..a791298 100644 --- a/src/app/pages/main/editor-sidebar/editor-sidebar.css +++ b/src/app/pages/main/editor-sidebar/editor-sidebar.css @@ -0,0 +1,3 @@ +.enabled:hover { + background-color: var(--color-gray-100) ; +} \ No newline at end of file diff --git a/src/app/pages/main/editor-sidebar/editor-sidebar.html b/src/app/pages/main/editor-sidebar/editor-sidebar.html index 7dc558d..15cc7b2 100644 --- a/src/app/pages/main/editor-sidebar/editor-sidebar.html +++ b/src/app/pages/main/editor-sidebar/editor-sidebar.html @@ -1,13 +1,55 @@ - - - + \ No newline at end of file diff --git a/src/app/pages/main/editor-sidebar/editor-sidebar.ts b/src/app/pages/main/editor-sidebar/editor-sidebar.ts index 0b6bea4..2800ce7 100644 --- a/src/app/pages/main/editor-sidebar/editor-sidebar.ts +++ b/src/app/pages/main/editor-sidebar/editor-sidebar.ts @@ -1,26 +1,35 @@ -import { Component } from '@angular/core'; -import { Accordion } from '@shared/accordion/accordion'; +import { Component, computed, inject, signal } from '@angular/core'; +import { GroupHolder } from '@shared/group-holder/group-holder'; import { FlowsList } from '@shared/flows-list/flows-list'; +import { EditorStateHolder } from 'app/stores/editor'; +import { CommonModule } from '@angular/common'; -type AccordionId = 'flows' | 'blocks'; +type OpenedId = 'flows' | 'blocks'; @Component({ selector: 'app-editor-sidebar', - imports: [Accordion, FlowsList], + imports: [GroupHolder, FlowsList, CommonModule], templateUrl: './editor-sidebar.html', styleUrl: './editor-sidebar.css', }) export class EditorSidebar { - collapsed = false; + flowState = inject(EditorStateHolder); - openAccordion: AccordionId | null = null; + blockDisabled = computed(() => !this.flowState.hasFlow()); + + collapsed = signal(true); + + open: OpenedId | null = null; + + + openSide(id: OpenedId) { + this.open = id; + this.collapsed.set(false); + } collapse() { - this.collapsed = !this.collapsed; - } - - toggle(id: AccordionId) { - this.openAccordion = this.openAccordion === id ? null : id; + this.collapsed.set(true); } + } diff --git a/src/app/services/flows/flows-call.base.ts b/src/app/services/flows/flows-call.base.ts new file mode 100644 index 0000000..076a0f2 --- /dev/null +++ b/src/app/services/flows/flows-call.base.ts @@ -0,0 +1,10 @@ +import { Flow } from "@models/flow"; +import { Observable } from "rxjs"; + +export abstract class FlowsCallServiceBase { + + abstract retrieveAllFlows() : Observable; + + abstract updateFlow(flow: Flow) : Observable; + +} \ No newline at end of file diff --git a/src/app/services/flows/flows-call.fake.ts b/src/app/services/flows/flows-call.fake.ts new file mode 100644 index 0000000..2d2e135 --- /dev/null +++ b/src/app/services/flows/flows-call.fake.ts @@ -0,0 +1,20 @@ +import { Flow } from "@models/flow"; +import { FlowsCallServiceBase } from "./flows-call.base"; +import { BehaviorSubject, of } from "rxjs"; + +export class FlowsCallServiceFake extends FlowsCallServiceBase { + + private data: Record = { + '1': { id: '1', name: 'Test Flow 1', data: {}, visibility: 'public' }, + '2': { id: '2', name: 'Test Flow 2', data: {}, visibility: 'private' }, + }; + + retrieveAllFlows() { + return of(Object.values(this.data)); + } + + updateFlow(flow: Flow) { + this.data[flow.id] = flow; + return of(void 0); + } +} diff --git a/src/app/services/flows/flows-call.ts b/src/app/services/flows/flows-call.ts new file mode 100644 index 0000000..5cfb05d --- /dev/null +++ b/src/app/services/flows/flows-call.ts @@ -0,0 +1,13 @@ +import { Flow } from "@models/flow"; +import { FlowsCallServiceBase } from "./flows-call.base"; +import { Observable } from "rxjs"; + +export class FlowsCallService extends FlowsCallServiceBase { + override retrieveAllFlows(): Observable { + throw new Error("Method not implemented."); + } + override updateFlow(flow: Flow): Observable { + throw new Error("Method not implemented."); + } + +} \ No newline at end of file diff --git a/src/app/services/flows/flows.spec.ts b/src/app/services/flows/flows.spec.ts new file mode 100644 index 0000000..583c80a --- /dev/null +++ b/src/app/services/flows/flows.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { Flows } from './flows'; + +describe('Flows', () => { + let service: Flows; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(Flows); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/flows/flows.ts b/src/app/services/flows/flows.ts new file mode 100644 index 0000000..fa47a16 --- /dev/null +++ b/src/app/services/flows/flows.ts @@ -0,0 +1,45 @@ +import { Injectable, signal } from '@angular/core'; +import { environment } from '@environment'; +import { Flow } from '@models/flow'; +import { FlowsCallServiceBase } from './flows-call.base'; +import { BehaviorSubject, catchError, tap, throwError } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class FlowsService { + + flowsCallService: FlowsCallServiceBase = new environment.flowsCallService(); + + toInit: boolean = true; + + private _flows = signal([]); + + async getAllFlows() { + console.log('Flows signal accessed'); + if (this.toInit) { + this.refresh(); + this.toInit = false; + + } + + return this._flows.asReadonly(); + } + + refresh() { + this.flowsCallService.retrieveAllFlows().subscribe(flows => { + this._flows.set(flows); + }); + } + + updateFlow(flow: Flow) { + return this.flowsCallService.updateFlow(flow).pipe( + tap(() => this.refresh()), + catchError(err => { + console.error('Update flow failed', err); + return throwError(() => err); + }) + ); + } + +} diff --git a/src/app/shared/accordion/accordion.html b/src/app/shared/accordion/accordion.html deleted file mode 100644 index 5887c3c..0000000 --- a/src/app/shared/accordion/accordion.html +++ /dev/null @@ -1,38 +0,0 @@ -
- - - - - -
- -
- -
- -
-
diff --git a/src/app/shared/accordion/accordion.ts b/src/app/shared/accordion/accordion.ts deleted file mode 100644 index ca6faa7..0000000 --- a/src/app/shared/accordion/accordion.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, EventEmitter, input, Input, Output } from '@angular/core'; - -@Component({ - selector: 'app-accordion', - imports: [], - templateUrl: './accordion.html', - styleUrl: './accordion.css', -}) -export class Accordion { - @Input() title = ''; - @Input() icon = ''; - open = input(false); - @Output() toggle = new EventEmitter(); -} diff --git a/src/app/shared/confirm-dialog/confirm-dialog.html b/src/app/shared/confirm-dialog/confirm-dialog.html index 7b33132..98ff590 100644 --- a/src/app/shared/confirm-dialog/confirm-dialog.html +++ b/src/app/shared/confirm-dialog/confirm-dialog.html @@ -1,6 +1,6 @@ @if(!!this.state()) { -
+
diff --git a/src/app/shared/flows-list/flows-list.html b/src/app/shared/flows-list/flows-list.html index d1b4666..0dc0ef0 100644 --- a/src/app/shared/flows-list/flows-list.html +++ b/src/app/shared/flows-list/flows-list.html @@ -1,29 +1,36 @@ +@if (loading()) { +
+
+ Loading... +
+
+} @else if (filteredFlows.length === 0) {
- - -
- @for (flow of filteredFlows; track flow.id) { + @for (flow of filteredFlows(); track flow.id) {
+ bg-indigo-50 border-indigo-200 select-none" (dblclick)="open(flow)">
@@ -45,4 +52,5 @@
} -
\ No newline at end of file +
+} \ No newline at end of file diff --git a/src/app/shared/flows-list/flows-list.ts b/src/app/shared/flows-list/flows-list.ts index fcae93c..47001ea 100644 --- a/src/app/shared/flows-list/flows-list.ts +++ b/src/app/shared/flows-list/flows-list.ts @@ -1,6 +1,7 @@ import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, computed, inject, signal, Signal, WritableSignal } from '@angular/core'; import { Flow } from '@models/flow'; +import { FlowsService } from '@services/flows/flows'; import { EditorStateHolder } from 'app/stores/editor'; type FlowFilter = 'all' | 'public' | 'private'; @@ -12,21 +13,27 @@ type FlowFilter = 'all' | 'public' | 'private'; styleUrl: './flows-list.css', }) export class FlowsList { - filter: FlowFilter = 'all'; + filter = signal('all'); private editorState = inject(EditorStateHolder); + private flowsService = inject(FlowsService); - flows : Flow[] = [ - { id: '1', name: 'Flow One', visibility: 'public', data: {} }, - { id: '2', name: 'Flow Two', visibility: 'private', data: {} }, - { id: '3', name: 'Flow Three', visibility: 'public', data: {} }, - { id: '4', name: 'Flow Four', visibility: 'private', data: {} }, - ] + loading: WritableSignal = signal(true); - get filteredFlows() { - if (this.filter === 'all') return this.flows; - return this.flows.filter(f => f.visibility === this.filter); + flows: Signal | undefined; + + ngOnInit() { + this.flowsService.getAllFlows().then(flowsSignal => { + this.flows = flowsSignal; + this.loading.set(false); + }); } + + filteredFlows = computed(() => { + if (!this.flows) return []; + if (this.filter() === 'all') return this.flows(); + return this.flows().filter(f => f.visibility === this.filter()); + }); open(flow: Flow) { console.log('Opening flow:', flow); diff --git a/src/app/shared/accordion/accordion.css b/src/app/shared/group-holder/group-holder.css similarity index 100% rename from src/app/shared/accordion/accordion.css rename to src/app/shared/group-holder/group-holder.css diff --git a/src/app/shared/group-holder/group-holder.html b/src/app/shared/group-holder/group-holder.html new file mode 100644 index 0000000..89860c8 --- /dev/null +++ b/src/app/shared/group-holder/group-holder.html @@ -0,0 +1,29 @@ +
+ + +
+ +
+ + {{ title }} +
+
+ +
+ +
+ +
+ +
+
diff --git a/src/app/shared/accordion/accordion.spec.ts b/src/app/shared/group-holder/group-holder.spec.ts similarity index 58% rename from src/app/shared/accordion/accordion.spec.ts rename to src/app/shared/group-holder/group-holder.spec.ts index fa15d4c..af5f00e 100644 --- a/src/app/shared/accordion/accordion.spec.ts +++ b/src/app/shared/group-holder/group-holder.spec.ts @@ -1,18 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Accordion } from './accordion'; +import { GroupHolder } from './group-holder'; -describe('Accordion', () => { - let component: Accordion; - let fixture: ComponentFixture; +describe('GroupHolder', () => { + let component: GroupHolder; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Accordion] + imports: [GroupHolder] }) .compileComponents(); - fixture = TestBed.createComponent(Accordion); + fixture = TestBed.createComponent(GroupHolder); component = fixture.componentInstance; await fixture.whenStable(); }); diff --git a/src/app/shared/group-holder/group-holder.ts b/src/app/shared/group-holder/group-holder.ts new file mode 100644 index 0000000..912adb0 --- /dev/null +++ b/src/app/shared/group-holder/group-holder.ts @@ -0,0 +1,12 @@ +import { Component, EventEmitter, input, Input, Output } from '@angular/core'; + +@Component({ + selector: 'app-group-holder', + imports: [], + templateUrl: './group-holder.html', + styleUrl: './group-holder.css', +}) +export class GroupHolder { + @Input() title = ''; + @Input() icon = ''; +} diff --git a/src/app/shared/title-toolbar/title-toolbar.css b/src/app/shared/title-toolbar/title-toolbar.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/title-toolbar/title-toolbar.html b/src/app/shared/title-toolbar/title-toolbar.html new file mode 100644 index 0000000..6d2a02a --- /dev/null +++ b/src/app/shared/title-toolbar/title-toolbar.html @@ -0,0 +1,67 @@ +
+ + +
+ +

+ +

+ @if (unsaved()) { + not saved + } +
+ + + +
+ + + + + + +
+ + +
+
diff --git a/src/app/shared/title-toolbar/title-toolbar.spec.ts b/src/app/shared/title-toolbar/title-toolbar.spec.ts new file mode 100644 index 0000000..a80c9da --- /dev/null +++ b/src/app/shared/title-toolbar/title-toolbar.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TitleToolbar } from './title-toolbar'; + +describe('TitleToolbar', () => { + let component: TitleToolbar; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TitleToolbar] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TitleToolbar); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/title-toolbar/title-toolbar.ts b/src/app/shared/title-toolbar/title-toolbar.ts new file mode 100644 index 0000000..42cd9b2 --- /dev/null +++ b/src/app/shared/title-toolbar/title-toolbar.ts @@ -0,0 +1,53 @@ +import { Component, computed, ElementRef, inject, linkedSignal, ViewChild, WritableSignal } from '@angular/core'; +import { EditorStateHolder } from 'app/stores/editor'; + +@Component({ + selector: 'app-title-toolbar', + imports: [], + templateUrl: './title-toolbar.html', + styleUrl: './title-toolbar.css', +}) +export class TitleToolbar { + + @ViewChild('titleInput') myInputRef!: ElementRef; + + private editorState: EditorStateHolder = inject(EditorStateHolder); + title = computed(() => { + const flow = this.editorState.currentFlow(); + return flow ? flow.name : 'No Flow Opened'; + }); + + tempTitle: WritableSignal = linkedSignal(() =>null); + + titleWidth = computed(() => { + const temp = this.tempTitle(); + if (temp !== null) { + return Math.max(temp.length-1, 4) + } + const len = this.title().length || 4; + return Math.min(len, 20)-2; + }); + + unsaved = computed(() => this.editorState.isDirty()); + + + changeTitle(value: string) { + this.tempTitle.set(null); + const trimmed = value.trim(); + if (value === this.title()) return; + if (trimmed.length < 4) { + this.myInputRef.nativeElement.value = this.title(); + return; + } + console.log('Updating flow title to:', trimmed); + const flow = this.editorState.currentFlow()!; + this.editorState.updateFlow({ ...flow, name: trimmed }); + } + + save() { + this.editorState.save().subscribe( + err => console.error('Save failed', err) + ); + } + +} diff --git a/src/app/stores/editor.ts b/src/app/stores/editor.ts index b8fa857..bfef24a 100644 --- a/src/app/stores/editor.ts +++ b/src/app/stores/editor.ts @@ -1,6 +1,9 @@ -import { computed, Injectable, signal } from '@angular/core'; +import { computed, inject, Injectable, signal } from '@angular/core'; import { Flow } from '@models/flow'; import { ConfirmDialogService } from '@services/dialogs/confirm-dialog'; +import { FlowsService } from '@services/flows/flows'; +import { FlowsCallService } from '@services/flows/flows-call'; +import { tap } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class EditorStateHolder { @@ -12,16 +15,20 @@ export class EditorStateHolder { /** Derived state */ readonly hasFlow = computed(() => !!this.currentFlow()); + flowsService: FlowsService = inject(FlowsService); + constructor(private confirm: ConfirmDialogService) { } + /** Intent: open document */ async openDocument(doc: Flow): Promise { - const confirmed = await this.confirm.open( - 'You have unsaved changes. Open another document?' - ); - - if (!confirmed) return false; + if (this.isDirty()) { + const confirmed = await this.confirm.open( + 'You have unsaved changes. Open another document?' + ); + if (!confirmed) return false; + } this.currentFlow.set(doc); this.isDirty.set(false); @@ -29,12 +36,12 @@ export class EditorStateHolder { } /** Intent: mark editor dirty */ - markDirty() { + private markDirty() { this.isDirty.set(true); } /** Intent: save document */ - markSaved() { + private markSaved() { this.isDirty.set(false); } @@ -43,4 +50,15 @@ export class EditorStateHolder { this.currentFlow.set(null); this.isDirty.set(false); } + + updateFlow(updated: Flow) { + this.currentFlow.set(updated); + this.markDirty(); + } + + save() { + return this.flowsService.updateFlow(this.currentFlow()!).pipe( + tap(() => this.markSaved()) + ) + } } diff --git a/src/environments/environment.development.ts b/src/environments/environment.development.ts index 5c6a7a9..2a3fc0c 100644 --- a/src/environments/environment.development.ts +++ b/src/environments/environment.development.ts @@ -1,7 +1,9 @@ import { AuthorizationCallFakeService } from "@services/authorization/authorization-call.fake"; +import { FlowsCallServiceFake } from "@services/flows/flows-call.fake"; export const environment = { production: false, apiUrl: 'http://localhost:8080', authorizationCallService: AuthorizationCallFakeService, // Assign the appropriate service here + flowsCallService: FlowsCallServiceFake }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index f31dbab..49efb80 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,7 +1,9 @@ import { AuthorizationCallService } from "@services/authorization/authorization-call"; +import { FlowsCallService } from "@services/flows/flows-call"; export const environment = { apiUrl: '/api', production: true, authorizationCallService: AuthorizationCallService, + flowsCallService: FlowsCallService };