diff --git a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.html b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.html index d8b2068d2..db360ac63 100644 --- a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.html +++ b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.html @@ -18,7 +18,7 @@
- +
@@ -105,3 +105,9 @@ *ngIf="hasError"> + + +
+
+
+
diff --git a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.scss b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.scss index 93b6f1630..e2d9f3ff0 100644 --- a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.scss +++ b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.scss @@ -29,16 +29,58 @@ } .aca-search-ai-response-container { + padding: 18px 20px; display: flex; flex-direction: column; border: 1px solid var(--adf-card-view-border-color); border-radius: 12px; margin: 16px 0 75px; - padding: 14px 40px 36px 35px; + + &-references-container-header { + padding-left: 8px; + } + + .adf-skeleton { + position: relative; + background-image: linear-gradient( + to left, + var(--theme-light-grey-1-color) 0%, + var(--theme-light-grey-2-color) 20%, + var(--theme-light-grey-3-color) 40%, + var(--theme-light-grey-1-color) 100% + ); + background-size: 200%; + display: inline-block; + height: 1em; + overflow: hidden; + width: 100%; + margin-bottom: 0.5rem; + border-radius: 0.25rem; + + &-half { + width: 50%; + margin-bottom: 8px; + } + + &::after { + position: absolute; + inset: 0; + transform: translateX(-100%); + background-image: linear-gradient(90deg, rgba(white, 0) 0, rgba(white, 0.2) 20%, rgba(white, 0.5) 60%, rgba(white, 0)); + animation: shimmer 2s infinite; + content: ''; + } + + @keyframes shimmer { + 100% { + transform: translateX(100%); + } + } + } &-error { border-color: var(--adf-error-color); - padding: 21px 19px 27px 18px; + padding: 32px 18px; &-message { display: flex; @@ -58,12 +100,8 @@ } &-body { - width: 100%; - &-response { - margin: 17px 0; - padding-left: 6px; - padding-right: 5px; + margin-bottom: 17px; overflow-wrap: break-word; &-action { diff --git a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.spec.ts b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.spec.ts index 7cf823da7..44f8aedf8 100644 --- a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.spec.ts +++ b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.spec.ts @@ -25,11 +25,13 @@ import { TestBed, ComponentFixture } from '@angular/core/testing'; import { SearchAiResultsComponent } from './search-ai-results.component'; import { ActivatedRoute, Params } from '@angular/router'; -import { Subject } from 'rxjs'; +import { of, Subject } from 'rxjs'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { UserPreferencesService } from '@alfresco/adf-core'; -import { AppTestingModule } from '../../../../testing/app-testing.module'; import { MatDialogModule } from '@angular/material/dialog'; +import { AppTestingModule } from '../../../../testing/app-testing.module'; +import { MatIconTestingModule } from '@angular/material/icon/testing'; +import { SearchAiService } from '@alfresco/adf-content-services'; describe('SearchAiResultsComponent', () => { const knowledgeRetrievalNodes = '{"isEmpty":"false","nodes":[{"entry":{"id": "someId","isFolder":"true"}}]}'; @@ -40,7 +42,7 @@ describe('SearchAiResultsComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AppTestingModule, SearchAiResultsComponent, MatSnackBarModule, MatDialogModule], + imports: [AppTestingModule, SearchAiResultsComponent, MatSnackBarModule, MatDialogModule, MatIconTestingModule], providers: [ { provide: ActivatedRoute, @@ -99,4 +101,47 @@ describe('SearchAiResultsComponent', () => { expect(component.hasError).toBeTrue(); }); }); + + describe('skeleton loader', () => { + let searchAiService: SearchAiService; + + const getSkeletonElementsLength = (): number => { + return fixture.nativeElement.querySelectorAll('.adf-skeleton').length; + }; + + beforeEach(() => { + searchAiService = TestBed.inject(SearchAiService); + spyOn(userPreferencesService, 'get').and.returnValue(knowledgeRetrievalNodes); + }); + + it('should display skeleton when loading is true', () => { + mockQueryParams.next({ query: 'test', agentId: 'agentId1' }); + + component.performAiSearch(); + fixture.detectChanges(); + + expect(component.loading).toBeTrue(); + expect(getSkeletonElementsLength()).toBe(3); + }); + + it('should not display skeleton when loading is false', () => { + mockQueryParams.next({ query: 'test', agentId: 'agentId1' }); + + spyOn(searchAiService, 'ask').and.returnValue(of({ question: 'test', questionId: 'testId', restrictionQuery: '' })); + spyOn(searchAiService, 'getAnswer').and.returnValue( + of({ + list: { + entries: [], + pagination: { hasMoreItems: false, maxItems: 0, totalItems: 0, skipCount: 0 } + } + }) + ); + + component.performAiSearch(); + fixture.detectChanges(); + + expect(component.loading).toBeFalse(); + expect(getSkeletonElementsLength()).toBe(0); + }); + }); }); diff --git a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.ts b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.ts index 547565280..a9232ed52 100644 --- a/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.ts +++ b/projects/aca-content/src/lib/components/knowledge-retrieval/search-ai/search-ai-results/search-ai-results.component.ts @@ -130,7 +130,6 @@ export class SearchAiResultsComponent extends PageComponent implements OnInit, O this._agentId = params.agentId; this._searchQuery = params.query ? decodeURIComponent(params.query) : ''; this._selectedNodesState = JSON.parse(this.userPreferencesService.get('knowledgeRetrievalNodes')); - if (!this.searchQuery || !this._selectedNodesState?.nodes?.length || !this.agentId) { this._hasError = true; return; diff --git a/projects/aca-content/src/lib/ui/variables/variables.scss b/projects/aca-content/src/lib/ui/variables/variables.scss index 626e95f81..ad1fbe316 100644 --- a/projects/aca-content/src/lib/ui/variables/variables.scss +++ b/projects/aca-content/src/lib/ui/variables/variables.scss @@ -49,6 +49,9 @@ $search-highlight-background-color: #ffd180; $info-snackbar-background: #1f74db; $text-light-color: rgba(33, 35, 40, 0.7); $card-background-grey-color: rgb(248, 248, 248); +$light-grey-1: #d5d5d5; +$light-grey-2: #d9d9d9; +$light-grey-3: #dedede; // CSS Variables $defaults: ( @@ -102,7 +105,10 @@ $defaults: ( --theme-secondary-text: $secondary-text, --theme-search-highlight-background-color: $search-highlight-background-color, --theme-text-light-color: $text-light-color, - --theme-card-background-grey-color: $card-background-grey-color + --theme-card-background-grey-color: $card-background-grey-color, + --theme-light-grey-1-color: $light-grey-1, + --theme-light-grey-2-color: $light-grey-2, + --theme-light-grey-3-color: $light-grey-3 ); // propagates SCSS variables into the CSS variables scope