retriever renamed, added token to calls
This commit is contained in:
parent
8a8f486eb5
commit
dbe1ab4588
12
angular.json
12
angular.json
|
|
@ -61,6 +61,15 @@
|
|||
"with": "src/environments/environment.development.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"staging": {
|
||||
"outputHashing": "all",
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.staging.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
|
|
@ -73,6 +82,9 @@
|
|||
},
|
||||
"development": {
|
||||
"buildTarget": "humainFlow-gui-a21:build:development"
|
||||
},
|
||||
"staging": {
|
||||
"buildTarget": "humainFlow-gui-a21:build:staging"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { authTokenInterceptor } from './interceptors/auth-token.interceptor';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideHttpClient(withInterceptors([authTokenInterceptor])),
|
||||
provideRouter(routes)
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import { HttpInterceptorFn } from '@angular/common/http';
|
||||
import { Authorization } from '@services/authorization/authorization';
|
||||
|
||||
export const authTokenInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
const token = getToken();
|
||||
if (!token) return next(req);
|
||||
|
||||
const requestPath = req.url.split('?')[0];
|
||||
const isAuthEndpoint =
|
||||
requestPath.endsWith('/auth/login') ||
|
||||
requestPath.endsWith('/auth/register');
|
||||
if (isAuthEndpoint) {
|
||||
return next(req);
|
||||
}
|
||||
|
||||
if (req.headers.has('Authorization')) {
|
||||
return next(req);
|
||||
}
|
||||
|
||||
return next(
|
||||
req.clone({
|
||||
setHeaders: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
function getToken(): string | null {
|
||||
const directToken = localStorage.getItem(Authorization.TOKEN_STORAGE_KEY);
|
||||
if (directToken) return directToken;
|
||||
|
||||
const rawUser = localStorage.getItem(Authorization.USER_STORAGE_KEY);
|
||||
if (!rawUser) return null;
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(rawUser) as { token?: unknown };
|
||||
return typeof parsed?.token === 'string' && parsed.token.length > 0 ? parsed.token : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
export type User = {
|
||||
username: string;
|
||||
email: string;
|
||||
token?: string;
|
||||
};
|
||||
|
||||
export type UserRegistration = User & {
|
||||
password: string;
|
||||
fullname: string;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,48 @@
|
|||
import { AuthorizationCallServiceBase } from "./authorization-call.base";
|
||||
import { User, UserRegistration } from "@models/user";
|
||||
import { Observable } from "rxjs";
|
||||
import { map, Observable } from "rxjs";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { inject } from "@angular/core";
|
||||
import { environment } from "@environment";
|
||||
|
||||
export class AuthorizationCallService extends AuthorizationCallServiceBase {
|
||||
override login(_username: string, _password: string): Observable<User> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
override register(_userRegistration: UserRegistration): Observable<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
|
||||
private readonly http = inject(HttpClient);
|
||||
|
||||
override login(username: string, password: string): Observable<User> {
|
||||
return this.http
|
||||
.post<unknown>(`${environment.apiUrl}/auth/login`, { username, password })
|
||||
.pipe(
|
||||
map((raw) => {
|
||||
const payload = (raw ?? {}) as Record<string, unknown>;
|
||||
const userSource =
|
||||
(payload["user"] as Record<string, unknown> | undefined)
|
||||
?? (payload["profile"] as Record<string, unknown> | undefined)
|
||||
?? payload;
|
||||
const token = this.extractToken(payload, userSource);
|
||||
|
||||
return {
|
||||
username: String(userSource["username"] ?? username),
|
||||
email: String(userSource["email"] ?? ''),
|
||||
token: typeof token === "string" && token.length > 0 ? token : undefined
|
||||
} satisfies User;
|
||||
})
|
||||
);
|
||||
}
|
||||
override register(userRegistration: UserRegistration): Observable<void> {
|
||||
return this.http.post<void>(`${environment.apiUrl}/auth/register`, userRegistration);
|
||||
}
|
||||
|
||||
private extractToken(...sources: Array<Record<string, unknown> | undefined>): unknown {
|
||||
const tokenKeys = ['token', 'accessToken', 'access_token', 'jwt', 'id_token'];
|
||||
for (const source of sources) {
|
||||
if (!source) continue;
|
||||
for (const key of tokenKeys) {
|
||||
const value = source[key];
|
||||
if (typeof value === 'string' && value.length > 0) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import { take, tap } from 'rxjs';
|
|||
providedIn: 'root',
|
||||
})
|
||||
export class Authorization {
|
||||
static readonly USER_STORAGE_KEY = 'loggedInUser';
|
||||
static readonly TOKEN_STORAGE_KEY = 'authToken';
|
||||
|
||||
private user = signal<User | null>(null);
|
||||
|
||||
|
|
@ -20,7 +22,12 @@ export class Authorization {
|
|||
take(1),
|
||||
tap(res => {
|
||||
this.user.set(res);
|
||||
localStorage.setItem('loggedInUser', JSON.stringify(res));
|
||||
localStorage.setItem(Authorization.USER_STORAGE_KEY, JSON.stringify(res));
|
||||
if (res.token) {
|
||||
localStorage.setItem(Authorization.TOKEN_STORAGE_KEY, res.token);
|
||||
} else {
|
||||
localStorage.removeItem(Authorization.TOKEN_STORAGE_KEY);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -32,12 +39,17 @@ export class Authorization {
|
|||
}
|
||||
|
||||
logout() {
|
||||
localStorage.removeItem('loggedInUser');
|
||||
localStorage.removeItem(Authorization.USER_STORAGE_KEY);
|
||||
localStorage.removeItem(Authorization.TOKEN_STORAGE_KEY);
|
||||
this.user.set(null);
|
||||
}
|
||||
|
||||
token(): string | null {
|
||||
return localStorage.getItem(Authorization.TOKEN_STORAGE_KEY);
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
const storedUser = localStorage.getItem('loggedInUser');
|
||||
const storedUser = localStorage.getItem(Authorization.USER_STORAGE_KEY);
|
||||
this.user.set(storedUser != null ? JSON.parse(storedUser) : null);
|
||||
return storedUser != null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,15 @@ export function flowFromApi(raw: unknown): Flow {
|
|||
};
|
||||
}
|
||||
|
||||
export function toFlowCreateRequest(name: string) {
|
||||
return { name };
|
||||
export function toFlowCreateRequest(name: string, description?: string, flow?: FlowData) {
|
||||
return {
|
||||
name,
|
||||
description: description ?? '',
|
||||
flow: flow ?? {
|
||||
blocks: [],
|
||||
connections: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function toFlowUpdateRequest(flow: Flow) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Observable } from "rxjs";
|
||||
|
||||
export abstract class FieldRetreiverCallServiceBase {
|
||||
export abstract class FieldRetrieverCallServiceBase {
|
||||
abstract retrieveValues(
|
||||
blockType: string,
|
||||
key: string,
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Observable, of } from "rxjs";
|
||||
import { FieldRetreiverCallServiceBase } from "./field-retreiver-call.base";
|
||||
import { FieldRetrieverCallServiceBase } from "./field-retriever-call.base";
|
||||
|
||||
export class FieldRetreiverCallServiceFake extends FieldRetreiverCallServiceBase {
|
||||
export class FieldRetrieverCallServiceFake extends FieldRetrieverCallServiceBase {
|
||||
private readonly providersByBlockType: Record<string, string[]> = {
|
||||
LLM: ["OpenAI", "Anthropic", "OllamaTestProvider"],
|
||||
};
|
||||
|
|
@ -2,21 +2,34 @@ import { HttpClient, HttpParams } from "@angular/common/http";
|
|||
import { inject } from "@angular/core";
|
||||
import { environment } from "@environment";
|
||||
import { Observable } from "rxjs";
|
||||
import { FieldRetreiverCallServiceBase } from "./field-retreiver-call.base";
|
||||
import { FieldRetrieverCallServiceBase } from "./field-retriever-call.base";
|
||||
|
||||
export class FieldRetreiverCallService extends FieldRetreiverCallServiceBase {
|
||||
export class FieldRetrieverCallService extends FieldRetrieverCallServiceBase {
|
||||
private readonly http = inject(HttpClient);
|
||||
|
||||
private buildParams(context?: Record<string, string>) {
|
||||
let params = new HttpParams();
|
||||
const entries = Object.entries(context ?? {});
|
||||
|
||||
if (!entries.length) {
|
||||
// New API marks `params` as required even when empty.
|
||||
return params.set('params', '{}');
|
||||
}
|
||||
|
||||
for (const [ctxKey, ctxValue] of entries) {
|
||||
params = params.set(`params[${ctxKey}]`, ctxValue);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
override retrieveValues(
|
||||
blockType: string,
|
||||
key: string,
|
||||
context?: Record<string, string>
|
||||
): Observable<string[]> {
|
||||
const url = `${environment.apiUrl}/retriever/${encodeURIComponent(blockType)}/${encodeURIComponent(key)}`;
|
||||
let params = new HttpParams();
|
||||
for (const [ctxKey, ctxValue] of Object.entries(context ?? {})) {
|
||||
params = params.set(ctxKey, ctxValue);
|
||||
}
|
||||
const params = this.buildParams(context);
|
||||
return this.http.get<string[]>(url, { params });
|
||||
}
|
||||
|
||||
|
|
@ -26,10 +39,7 @@ export class FieldRetreiverCallService extends FieldRetreiverCallServiceBase {
|
|||
context?: Record<string, string>
|
||||
): Observable<boolean> {
|
||||
const url = `${environment.apiUrl}/retriever/${encodeURIComponent(blockType)}/${encodeURIComponent(key)}/required`;
|
||||
let params = new HttpParams();
|
||||
for (const [ctxKey, ctxValue] of Object.entries(context ?? {})) {
|
||||
params = params.set(ctxKey, ctxValue);
|
||||
}
|
||||
const params = this.buildParams(context);
|
||||
return this.http.get<boolean>(url, { params });
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FieldRetreiver } from './field-retreiver';
|
||||
import { FieldRetriever } from './field-retriever';
|
||||
|
||||
describe('FieldRetreiver', () => {
|
||||
let service: FieldRetreiver;
|
||||
describe('FieldRetriever', () => {
|
||||
let service: FieldRetriever;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(FieldRetreiver);
|
||||
service = TestBed.inject(FieldRetriever);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '@environment';
|
||||
import { catchError, throwError } from 'rxjs';
|
||||
import { FieldRetreiverCallServiceBase } from './field-retreiver-call.base';
|
||||
import { FieldRetrieverCallServiceBase } from './field-retriever-call.base';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FieldRetreiver {
|
||||
fieldRetreiverCallService: FieldRetreiverCallServiceBase = new environment.fieldRetreiverCallService();
|
||||
export class FieldRetriever {
|
||||
fieldRetrieverCallService: FieldRetrieverCallServiceBase = new environment.fieldRetrieverCallService();
|
||||
|
||||
retrieveValues(
|
||||
blockType: string,
|
||||
key: string,
|
||||
context?: Record<string, string>
|
||||
) {
|
||||
return this.fieldRetreiverCallService.retrieveValues(blockType, key, context).pipe(
|
||||
return this.fieldRetrieverCallService.retrieveValues(blockType, key, context).pipe(
|
||||
catchError((err) => {
|
||||
console.error('Field retrieval failed', err);
|
||||
return throwError(() => err);
|
||||
|
|
@ -27,7 +27,7 @@ export class FieldRetreiver {
|
|||
key: string,
|
||||
context?: Record<string, string>
|
||||
) {
|
||||
return this.fieldRetreiverCallService.isFieldRequired(blockType, key, context).pipe(
|
||||
return this.fieldRetrieverCallService.isFieldRequired(blockType, key, context).pipe(
|
||||
catchError((err) => {
|
||||
console.error('Field required check failed', err);
|
||||
return throwError(() => err);
|
||||
|
|
@ -5,7 +5,7 @@ import { ClassicPreset } from 'rete';
|
|||
import { ReteModule } from 'rete-angular-plugin/21';
|
||||
import { NodeSettingsDialogService } from '@services/dialogs/node-settings-dialog';
|
||||
import { EditorStateHolder } from '@stores/flow-editor';
|
||||
import { FieldRetreiver as FieldRetriever } from '@services/retreiver/field-retreiver';
|
||||
import { FieldRetriever } from '@services/retriever/field-retriever';
|
||||
import { BlocksService } from '@services/blocks/blocks';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ConditionalRequiredField, extractSchemaRequirements, SchemaRequirements } from '../schema-requirements';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { AuthorizationCallFakeService } from "@services/authorization/authorization-call.fake";
|
||||
import { BlocksCallServiceFake } from "@services/blocks/blocks-call.fake";
|
||||
import { FlowsCallServiceFake } from "@services/flows/flows-call.fake";
|
||||
import { FieldRetreiverCallServiceFake } from "@services/retreiver/field-retreiver-call.fake";
|
||||
import { FieldRetrieverCallServiceFake } from "@services/retriever/field-retriever-call.fake";
|
||||
import { TaskExecutionsCallServiceFake } from "@services/task-executions/task-executions-call.fake";
|
||||
|
||||
export const environment = {
|
||||
|
|
@ -10,6 +10,6 @@ export const environment = {
|
|||
authorizationCallService: AuthorizationCallFakeService, // Assign the appropriate service here
|
||||
flowsCallService: FlowsCallServiceFake,
|
||||
blocksCallService: BlocksCallServiceFake,
|
||||
fieldRetreiverCallService: FieldRetreiverCallServiceFake,
|
||||
fieldRetrieverCallService: FieldRetrieverCallServiceFake,
|
||||
taskExecutionsCallService: TaskExecutionsCallServiceFake
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import { AuthorizationCallService } from "@services/authorization/authorization-call";
|
||||
import { BlocksCallService } from "@services/blocks/blocks-call";
|
||||
import { FlowsCallService } from "@services/flows/flows-call";
|
||||
import { FieldRetrieverCallService } from "@services/retriever/field-retriever-call";
|
||||
import { TaskExecutionsCallService } from "@services/task-executions/task-executions-call";
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl: 'http://localhost:8080',
|
||||
authorizationCallService: AuthorizationCallService,
|
||||
flowsCallService: FlowsCallService,
|
||||
blocksCallService: BlocksCallService,
|
||||
fieldRetrieverCallService: FieldRetrieverCallService,
|
||||
taskExecutionsCallService: TaskExecutionsCallService
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { AuthorizationCallService } from "@services/authorization/authorization-call";
|
||||
import { BlocksCallService } from "@services/blocks/blocks-call";
|
||||
import { FlowsCallService } from "@services/flows/flows-call";
|
||||
import { FieldRetreiverCallService } from "@services/retreiver/field-retreiver-call";
|
||||
import { FieldRetrieverCallService } from "@services/retriever/field-retriever-call";
|
||||
import { TaskExecutionsCallService } from "@services/task-executions/task-executions-call";
|
||||
|
||||
export const environment = {
|
||||
|
|
@ -10,6 +10,6 @@ export const environment = {
|
|||
authorizationCallService: AuthorizationCallService,
|
||||
flowsCallService: FlowsCallService,
|
||||
blocksCallService: BlocksCallService,
|
||||
fieldRetreiverCallService: FieldRetreiverCallService,
|
||||
fieldRetrieverCallService: FieldRetrieverCallService,
|
||||
taskExecutionsCallService: TaskExecutionsCallService
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue