From 8abc6d495de2e9ee64d922c9ee5e53cb9169b640 Mon Sep 17 00:00:00 2001 From: jacekpluta <73617938+jacekpluta@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:19:31 +0200 Subject: [PATCH] [ACS-8210] Agent basic details popup (#9956) --- .../lib/agent/services/agent.service.spec.ts | 100 ++++++++++++------ .../src/lib/agent/services/agent.service.ts | 62 +++++++++-- .../api/content-rest-api/api/agents.api.ts | 11 ++ .../api/content-rest-api/docs/AgentsApi.md | 41 +++++-- .../src/api/content-rest-api/model/agent.ts | 1 + .../content-rest-api/model/agentWithAvatar.ts | 22 ++++ .../src/api/content-rest-api/model/index.ts | 1 + .../test/content-services/agentsApi.spec.ts | 12 +++ .../content-services/agent.mock.ts | 6 ++ 9 files changed, 205 insertions(+), 51 deletions(-) create mode 100644 lib/js-api/src/api/content-rest-api/model/agentWithAvatar.ts diff --git a/lib/content-services/src/lib/agent/services/agent.service.spec.ts b/lib/content-services/src/lib/agent/services/agent.service.spec.ts index 58b6f2389b..69cea0dae0 100644 --- a/lib/content-services/src/lib/agent/services/agent.service.spec.ts +++ b/lib/content-services/src/lib/agent/services/agent.service.spec.ts @@ -15,49 +15,83 @@ * limitations under the License. */ -import { AgentService } from './agent.service'; import { TestBed } from '@angular/core/testing'; -import { AgentPaging } from '@alfresco/js-api'; -import { ContentTestingModule } from '../../testing/content.testing.module'; +import { AlfrescoApiService, CoreTestingModule } from '@alfresco/adf-core'; +import { Agent, AgentPaging, AgentsApi, AgentWithAvatar } from '@alfresco/js-api'; +import { AgentService } from '@alfresco/adf-content-services'; + +const agent1: Agent = { + id: '1', + name: 'HR Agent', + description: 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' +}; + +const agent2: Agent = { + id: '2', + name: 'Policy Agent', + description: 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' +}; + +const agentPagingObjectMock: AgentPaging = { + list: { + entries: [ + { + entry: agent1 + }, + { + entry: agent2 + } + ] + } +}; + +const avatarAgentMock = 'https://res.cloudinary.com/hyld/image/upload/f_auto,c_fill,g_auto,w_1400,h_730/v1/h2/hero/blue-shirt-woman'; + +const agentWithAvatarListMock: AgentWithAvatar[] = [ + { + ...agent1, + avatar: avatarAgentMock + }, + { + ...agent2, + avatar: avatarAgentMock + } +]; describe('AgentService', () => { - let service: AgentService; + let agentService: AgentService; + let apiService: AlfrescoApiService; + let agentsApi: AgentsApi; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ContentTestingModule] + imports: [CoreTestingModule] }); - service = TestBed.inject(AgentService); - service.mocked = false; + + agentService = TestBed.inject(AgentService); + apiService = TestBed.inject(AlfrescoApiService); + agentsApi = new AgentsApi(apiService.getInstance()); + agentService.mocked = false; + + spyOn(agentsApi, 'getAgentAvatar').and.returnValue(Promise.resolve(avatarAgentMock)); + spyOn(agentService.agentsApi, 'getAgentAvatar').and.returnValue(Promise.resolve(avatarAgentMock)); }); - describe('getAgents', () => { - it('should load agents', (done) => { - const paging: AgentPaging = { - list: { - entries: [ - { - entry: { - id: '1', - name: 'HR Agent' - } - }, - { - entry: { - id: '2', - name: 'Policy Agent' - } - } - ] - } - }; - spyOn(service.agentsApi, 'getAgents').and.returnValue(Promise.resolve(paging)); + it('should load agents', (done) => { + spyOn(agentService.agentsApi, 'getAgents').and.returnValue(Promise.resolve(agentPagingObjectMock)); - service.getAgents().subscribe((pagingResponse) => { - expect(pagingResponse).toBe(paging); - expect(service.agentsApi.getAgents).toHaveBeenCalled(); - done(); - }); + agentService.getAgents().subscribe((pagingResponse) => { + expect(pagingResponse).toEqual(agentWithAvatarListMock); + expect(agentService.agentsApi.getAgents).toHaveBeenCalled(); + done(); + }); + }); + + it('should get agent avatar', (done) => { + agentService.getAgentAvatar('avatarId').subscribe((response) => { + expect(response).toEqual(avatarAgentMock); + expect(agentService.agentsApi.getAgentAvatar).toHaveBeenCalledWith('avatarId'); + done(); }); }); }); diff --git a/lib/content-services/src/lib/agent/services/agent.service.ts b/lib/content-services/src/lib/agent/services/agent.service.ts index 2fde1f55b2..73f94ee49a 100644 --- a/lib/content-services/src/lib/agent/services/agent.service.ts +++ b/lib/content-services/src/lib/agent/services/agent.service.ts @@ -16,9 +16,10 @@ */ import { Injectable } from '@angular/core'; -import { AgentPaging, AgentsApi } from '@alfresco/js-api'; +import { AgentPaging, AgentsApi, AgentWithAvatar } from '@alfresco/js-api'; import { AlfrescoApiService } from '@alfresco/adf-core'; -import { from, Observable, of } from 'rxjs'; +import { BehaviorSubject, forkJoin, from, Observable, of } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; @Injectable({ providedIn: 'root' @@ -26,6 +27,7 @@ import { from, Observable, of } from 'rxjs'; export class AgentService { private _agentsApi: AgentsApi; private _mocked = true; + private agents = new BehaviorSubject([]); get agentsApi(): AgentsApi { this._agentsApi = this._agentsApi ?? new AgentsApi(this.apiService.getInstance()); @@ -36,14 +38,42 @@ export class AgentService { this._mocked = mocked; } + agents$ = this.agents.asObservable(); + constructor(private apiService: AlfrescoApiService) {} + /** + * Gets all agents from cache. If cache is empty, fetches agents from backend. + * + * @returns AgentWithAvatar[] list containing agents. + */ + getAgents(): Observable { + return this.agents$.pipe( + switchMap((agentsList) => { + if (agentsList.length) { + return of(agentsList); + } + return this.getMockedAgents().pipe( + switchMap((paging) => { + const agents = paging.list.entries.map((agentEntry) => agentEntry.entry); + return forkJoin([of(agents), ...agents.map((agent) => this.getAgentAvatar(agent.id))]); + }), + switchMap(([agents, ...avatars]: [AgentWithAvatar[], string]) => { + const agentsWithAvatar = agents.map((agent, index) => ({ ...agent, avatar: avatars[index] })); + this.agents.next(agentsWithAvatar); + return of(agentsWithAvatar); + }) + ); + }) + ); + } + /** * Gets all agents. * * @returns AgentPaging object containing the agents. */ - getAgents(): Observable { + private getMockedAgents(): Observable { return this._mocked ? of({ list: { @@ -51,19 +81,17 @@ export class AgentService { { entry: { id: '1', - name: 'HR Agent' + name: 'HR Agent', + description: + 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' } }, { entry: { id: '2', - name: 'Policy Agent' - } - }, - { - entry: { - id: '3', - name: 'Rules & Rates Agent' + name: 'Policy Agent', + description: + 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' } } ] @@ -71,4 +99,16 @@ export class AgentService { }) : from(this.agentsApi.getAgents()); } + + /** + * Gets agent avatar by agent id. + * + * @param agentId agent unique id. + * @returns string with an image. + */ + getAgentAvatar(agentId: string): Observable { + return this._mocked + ? of('https://res.cloudinary.com/hyld/image/upload/f_auto,c_fill,g_auto,w_1400,h_730/v1/h2/hero/blue-shirt-woman') + : from(this._agentsApi.getAgentAvatar(agentId)); + } } diff --git a/lib/js-api/src/api/content-rest-api/api/agents.api.ts b/lib/js-api/src/api/content-rest-api/api/agents.api.ts index d407410db1..a906326cb9 100644 --- a/lib/js-api/src/api/content-rest-api/api/agents.api.ts +++ b/lib/js-api/src/api/content-rest-api/api/agents.api.ts @@ -32,4 +32,15 @@ export class AgentsApi extends BaseApi { path: '/agents' }); } + + /** + * Gets agent avatar by id. + * + * @returns string with an image. + */ + getAgentAvatar(agentId: string): Promise { + return this.get({ + path: `/agents/${agentId}/avatars/-default-` + }); + } } diff --git a/lib/js-api/src/api/content-rest-api/docs/AgentsApi.md b/lib/js-api/src/api/content-rest-api/docs/AgentsApi.md index 0a0960a017..0e75c18e8b 100644 --- a/lib/js-api/src/api/content-rest-api/docs/AgentsApi.md +++ b/lib/js-api/src/api/content-rest-api/docs/AgentsApi.md @@ -1,8 +1,9 @@ # AgentsApi -| Method | HTTP request | Description | -|-------------------------|-----------------|------------------| -| [getAgents](#getAgents) | **GET** /agents | Gets all agents. | +| Method | HTTP request | Description | +|-----------------------------------|----------------------------------------------|--------------------------| +| [getAgents](#getAgents) | **GET** /agents | Gets all agents. | +| [getAgentAvatar](#getAgentAvatar) | **GET** /agents/${agentId}/avatars/-default- | Gets agent avatar by id. | ## getAgents @@ -46,6 +47,31 @@ agentsApi.getAgents().then((agents) => { **Return type**: [AgentPaging](#AgentPaging) +## getAgentAvatar + +Gets agent avatar by agent id. + +**Parameters** + +| Name | Type | +|---------------|----------| +| **agentId** | string | + +**Example** + +```javascript +import { AlfrescoApi, AgentsApi } from '@alfresco/js-api'; + +const alfrescoApi = new AlfrescoApi(/*..*/); +const agentsApi = new AgentsApi(alfrescoApi); + +agentsApi.getAgentAvatar('agentId').then((agentAvatarImage) => { + console.log('API called successfully. Returned data: ' + agentAvatarImage); +}); +``` + +**Return type**: String + # Models ## AgentPaging @@ -77,7 +103,8 @@ agentsApi.getAgents().then((agents) => { **Properties** -| Name | Type | -|----------|--------| -| **id** | string | -| **name** | string | +| Name | Type | +|-----------------|--------| +| **id** | string | +| **name** | string | +| **description** | string | diff --git a/lib/js-api/src/api/content-rest-api/model/agent.ts b/lib/js-api/src/api/content-rest-api/model/agent.ts index ad0a97a868..8684990ff2 100644 --- a/lib/js-api/src/api/content-rest-api/model/agent.ts +++ b/lib/js-api/src/api/content-rest-api/model/agent.ts @@ -18,4 +18,5 @@ export interface Agent { id: string; name: string; + description: string; } diff --git a/lib/js-api/src/api/content-rest-api/model/agentWithAvatar.ts b/lib/js-api/src/api/content-rest-api/model/agentWithAvatar.ts new file mode 100644 index 0000000000..ee32489581 --- /dev/null +++ b/lib/js-api/src/api/content-rest-api/model/agentWithAvatar.ts @@ -0,0 +1,22 @@ +/*! + * @license + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Agent } from './agent'; + +export interface AgentWithAvatar extends Agent { + avatar: string; +} diff --git a/lib/js-api/src/api/content-rest-api/model/index.ts b/lib/js-api/src/api/content-rest-api/model/index.ts index a286a18262..756cf262bc 100644 --- a/lib/js-api/src/api/content-rest-api/model/index.ts +++ b/lib/js-api/src/api/content-rest-api/model/index.ts @@ -28,6 +28,7 @@ export * from './activityEntry'; export * from './activityPaging'; export * from './activityPagingList'; export * from './agent'; +export * from './agentWithAvatar'; export * from './agentEntry'; export * from './agentPaging'; export * from './agentPagingList'; diff --git a/lib/js-api/test/content-services/agentsApi.spec.ts b/lib/js-api/test/content-services/agentsApi.spec.ts index 8b81fffd16..2f568d2fb9 100644 --- a/lib/js-api/test/content-services/agentsApi.spec.ts +++ b/lib/js-api/test/content-services/agentsApi.spec.ts @@ -67,5 +67,17 @@ describe('AgentsApi', () => { done(); }); }); + + describe('getAgentAvatar', () => { + it('should get agent avatar', (done) => { + const agentId = 'agentId'; + agentMock.getAgentAvatar200Response(agentId); + + agentsApi.getAgentAvatar(agentId).then((data) => { + assert.deepStrictEqual(data, { avatarImage: 'agentAvatarImageMock' }); + done(); + }); + }); + }); }); }); diff --git a/lib/js-api/test/mockObjects/content-services/agent.mock.ts b/lib/js-api/test/mockObjects/content-services/agent.mock.ts index fc657e2193..75eae6181b 100644 --- a/lib/js-api/test/mockObjects/content-services/agent.mock.ts +++ b/lib/js-api/test/mockObjects/content-services/agent.mock.ts @@ -47,4 +47,10 @@ export class AgentMock extends BaseMock { } }); } + + getAgentAvatar200Response(agentId: string): void { + nock(this.host, { encodedQueryParams: true }) + .get(`/alfresco/api/-default-/private/hxi/versions/1/agents/${agentId}/avatars/-default-`) + .reply(200, { avatarImage: 'agentAvatarImageMock' }); + } }