diff --git a/docs/content-services/services/tag.service.md b/docs/content-services/services/tag.service.md
index 5ad49b779f..18e22d2ae5 100644
--- a/docs/content-services/services/tag.service.md
+++ b/docs/content-services/services/tag.service.md
@@ -18,9 +18,10 @@ Manages tags in Content Services.
- _nodeId:_ `string` - ID of the target node
- _tagName:_ `string` - Name of the tag to add
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagEntry.md)`>` - TagEntry object (defined in JS-API) with details of the new tag
-- **getAllTheTags**(opts?: `any`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagPaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagPaging.md)`>`
+- **getAllTheTags**(opts?: `any`, includedCounts?: `boolean`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagPaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagPaging.md)`>`
Gets a list of all the tags already defined in the repository.
- _opts:_ `any` - (Optional) Options supported by JS-API
+ - _includedCounts:_ `boolean` - (Optional) True if count field should be included in response object for each tag, false otherwise.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagPaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagPaging.md)`>` - TagPaging object (defined in JS-API) containing the tags
- **getTagsByNodeId**(nodeId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagPaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagPaging.md)`>`
Gets a list of tags added to a node.
@@ -44,11 +45,13 @@ Manages tags in Content Services.
- _tagId:_ `string` - The identifier of a tag.
- _tagBody:_ `TagBody` - The updated tag.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`` - Updated tag.
-- **searchTags**(name: `string`, skipCount: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)``
+- **searchTags**(name: `string`, sorting?: `{ orderBy: string, direction: string }`, includedCounts?: `boolean`, skipCount: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)``
Find tags which name contains searched name.
- - _name:_ `string` - Value for name which should be used during searching tags.
- - _skipCount:_ `number` - Specify how many first results should be skipped. Default 0.
- - _maxItems:_ `number` - Specify max number of returned tags. Default is specified by UserPreferencesService.
+ - _name:_ `string` - Value for name which should be used during searching tags.
+ - _sorting:_ `{ orderBy: string, direction: string }` - Object which configures sorting. OrderBy field specifies field used for sorting, direction specified ascending or descending direction. Default sorting is ascending by tag field.
+ - _includedCounts:_ `boolean` - True if count field should be included in response object for each tag, false otherwise.
+ - _skipCount:_ `number` - Specify how many first results should be skipped. Default 0.
+ - _maxItems:_ `number` - Specify max number of returned tags. Default is specified by UserPreferencesService.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`` - Found tags which name contains searched name.
- **getCountersForTags**(tags: `string[]`): [`Observable`](http://reactivex.io/documentation/observable.html)``
Get usage counters for passed tags.
diff --git a/lib/content-services/src/lib/tag/services/tag.service.spec.ts b/lib/content-services/src/lib/tag/services/tag.service.spec.ts
index e6a204d11e..f3b3a8b1f0 100644
--- a/lib/content-services/src/lib/tag/services/tag.service.spec.ts
+++ b/lib/content-services/src/lib/tag/services/tag.service.spec.ts
@@ -21,22 +21,7 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { throwError } from 'rxjs';
-import {
- Pagination,
- RequestQuery,
- RequestSortDefinitionInner,
- ResultNode,
- ResultSetContext,
- ResultSetContextFacetQueries,
- ResultSetPaging,
- ResultSetPagingList,
- ResultSetRowEntry,
- Tag,
- TagBody,
- TagEntry,
- TagPaging,
- TagPagingList
-} from '@alfresco/js-api';
+import { Pagination, Tag, TagBody, TagEntry, TagPaging, TagPagingList } from '@alfresco/js-api';
describe('TagService', () => {
@@ -44,6 +29,18 @@ describe('TagService', () => {
let logService: LogService;
let userPreferencesService: UserPreferencesService;
+ const mockTagPaging = (): TagPaging => {
+ const tagPaging = new TagPaging();
+ tagPaging.list = new TagPagingList();
+ const tag = new TagEntry();
+ tag.entry = new Tag();
+ tag.entry.id = 'some id';
+ tag.entry.tag = 'some name';
+ tagPaging.list.entries = [tag];
+ tagPaging.list.pagination = new Pagination();
+ return tagPaging;
+ };
+
setupTestBed({
imports: [
TranslateModule.forRoot(),
@@ -135,58 +132,44 @@ describe('TagService', () => {
}));
});
- describe('searchTags', () => {
- let result: ResultSetPaging;
+ describe('getAllTheTags', () => {
+ let result: TagPaging;
beforeEach(() => {
- result = new ResultSetPaging();
- result.list = new ResultSetPagingList();
- const tag = new ResultSetRowEntry();
- tag.entry = new ResultNode();
- tag.entry.id = 'some id';
- tag.entry.name = 'some name';
- result.list.entries = [tag];
- result.list.pagination = new Pagination();
+ result = mockTagPaging();
});
- it('should call search on searchApi with correct parameters', () => {
- const searchSpy = spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
- const name = 'test';
- const maxItems = 25;
- spyOnProperty(userPreferencesService, 'paginationSize').and.returnValue(maxItems);
+ it('should call listTags on TagsApi with correct parameters when includedCounts is true', () => {
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
+ const skipCount = 10;
- const sortingByName = new RequestSortDefinitionInner();
- sortingByName.field = 'cm:name';
- sortingByName.ascending = true;
- sortingByName.type = RequestSortDefinitionInner.TypeEnum.FIELD;
+ service.getAllTheTags({
+ skipCount
+ }, true);
+ expect(service.tagsApi.listTags).toHaveBeenCalledWith({
+ include: ['count'],
+ skipCount
+ });
+ });
- service.searchTags(name);
- expect(searchSpy).toHaveBeenCalledWith({
- query: {
- language: RequestQuery.LanguageEnum.Afts,
- query: `PATH:"/cm:categoryRoot/cm:taggable/*" AND cm:name:"*${name}*"`
- },
- paging: {
- skipCount: 0,
- maxItems
- },
- sort: [sortingByName]
+ it('should call listTags on TagsApi with correct parameters when includedCounts is false', () => {
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
+ const skipCount = 10;
+
+ service.getAllTheTags({
+ skipCount
+ }, false);
+ expect(service.tagsApi.listTags).toHaveBeenCalledWith({
+ include: undefined,
+ skipCount
});
});
it('should return observable which emits paging object for tags', fakeAsync(() => {
- spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
- service.searchTags('test').subscribe((tagsResult) => {
- const tagPaging = new TagPaging();
- tagPaging.list = new TagPagingList();
- const tagEntry = new TagEntry();
- tagEntry.entry = new Tag();
- tagEntry.entry.id = 'some id';
- tagEntry.entry.tag = 'some name';
- tagPaging.list.entries = [tagEntry];
- tagPaging.list.pagination = new Pagination();
- expect(tagsResult).toEqual(tagPaging);
+ service.getAllTheTags().subscribe((tagsResult) => {
+ expect(tagsResult).toEqual(result);
});
tick();
}));
@@ -194,7 +177,78 @@ describe('TagService', () => {
it('should call error on logService when error occurs during fetching paging object for tags', fakeAsync(() => {
spyOn(logService, 'error');
const error: string = 'Some error';
- spyOn(service.searchApi, 'search').and.returnValue(Promise.reject(error));
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.reject(error));
+ service.getAllTheTags().subscribe({
+ error: () => {
+ expect(logService.error).toHaveBeenCalledWith(error);
+ }
+ });
+ tick();
+ }));
+ });
+
+ describe('searchTags', () => {
+ let result: TagPaging;
+
+ beforeEach(() => {
+ result = mockTagPaging();
+ });
+
+ it('should call listTags on TagsApi with correct default parameters', () => {
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
+ const name = 'test';
+ const maxItems = 25;
+ spyOnProperty(userPreferencesService, 'paginationSize').and.returnValue(maxItems);
+
+ service.searchTags(name);
+ expect(service.tagsApi.listTags).toHaveBeenCalledWith({
+ tag: `*${name}*`,
+ skipCount: 0,
+ maxItems,
+ sorting: {
+ orderBy: 'tag',
+ direction: 'asc'
+ },
+ matching: true,
+ include: undefined
+ });
+ });
+
+ it('should call listTags on TagsApi with correct specified parameters', () => {
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
+ const name = 'test';
+ spyOnProperty(userPreferencesService, 'paginationSize').and.returnValue(25);
+ const maxItems = 100;
+ const skipCount = 200;
+ const sorting = {
+ orderBy: 'id',
+ direction: 'asc'
+ };
+
+ service.searchTags(name, sorting, true, skipCount, maxItems);
+ expect(service.tagsApi.listTags).toHaveBeenCalledWith({
+ tag: `*${name}*`,
+ skipCount,
+ maxItems,
+ sorting,
+ matching: true,
+ include: ['count']
+ });
+ });
+
+ it('should return observable which emits paging object for tags', fakeAsync(() => {
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.resolve(result));
+
+ service.searchTags('test').subscribe((tagsResult) => {
+ expect(tagsResult).toEqual(result);
+ });
+ tick();
+ }));
+
+ it('should call error on logService when error occurs during fetching paging object for tags', fakeAsync(() => {
+ spyOn(logService, 'error');
+ const error: string = 'Some error';
+ spyOn(service.tagsApi, 'listTags').and.returnValue(Promise.reject(error));
service.searchTags('test').subscribe({
error: () => {
expect(logService.error).toHaveBeenCalledWith(error);
@@ -244,83 +298,6 @@ describe('TagService', () => {
}));
});
- describe('getCountersForTags', () => {
- let result: ResultSetPaging;
- const tag1 = 'tag 1';
-
- beforeEach(() => {
- result = new ResultSetPaging();
- result.list = new ResultSetPagingList();
- result.list.context = new ResultSetContext();
- const facetQuery = new ResultSetContextFacetQueries();
- facetQuery.count = 2;
- facetQuery.label = tag1;
- facetQuery.filterQuery = `TAG:"${tag1}"`;
- result.list.context.facetQueries = [facetQuery];
- });
-
- it('should call search on searchApi with correct parameters', () => {
- const tag2 = 'tag 2';
- spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
-
- service.getCountersForTags([tag1, tag2]);
- expect(service.searchApi.search).toHaveBeenCalledWith({
- query: {
- language: RequestQuery.LanguageEnum.Afts,
- query: `*`
- },
- facetQueries: [{
- query: `TAG:"${tag1}"`,
- label: tag1
- }, {
- query: `TAG:"${tag2}"`,
- label: tag2
- }]
- });
- });
-
- it('should return observable which emits facet queries with counters for tags', (done) => {
- spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
- service.getCountersForTags([tag1]).subscribe((counters) => {
- expect(counters).toBe(result.list.context.facetQueries);
- done();
- });
- });
-
- it('should return observable which emits undefined if context is not present', (done) => {
- result.list.context = undefined;
-
- spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
- service.getCountersForTags([tag1]).subscribe((counters) => {
- expect(counters).toBeUndefined();
- done();
- });
- });
-
- it('should return observable which emits undefined if list is not present', (done) => {
- result.list = undefined;
-
- spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve(result));
- service.getCountersForTags([tag1]).subscribe((counters) => {
- expect(counters).toBeUndefined();
- done();
- });
- });
-
- it('should call error on logService when error occurs during fetching counters for tags', fakeAsync(() => {
- spyOn(logService, 'error');
- const error = 'Some error';
- spyOn(service.searchApi, 'search').and.returnValue(Promise.reject(error));
-
- service.getCountersForTags([tag1]).subscribe({
- error: () => {
- expect(logService.error).toHaveBeenCalledWith(error);
- }
- });
- tick();
- }));
- });
-
describe('findTagByName', () => {
let tagPaging: TagPaging;
const tagName = 'some tag';
@@ -335,7 +312,8 @@ describe('TagService', () => {
service.findTagByName(tagName);
expect(service.tagsApi.listTags).toHaveBeenCalledWith({
- name: tagName
+ tag: tagName,
+ include: undefined
});
});
diff --git a/lib/content-services/src/lib/tag/services/tag.service.ts b/lib/content-services/src/lib/tag/services/tag.service.ts
index c93a8a6fb7..ff0747d270 100644
--- a/lib/content-services/src/lib/tag/services/tag.service.ts
+++ b/lib/content-services/src/lib/tag/services/tag.service.ts
@@ -19,18 +19,7 @@ import { AlfrescoApiService, LogService, UserPreferencesService } from '@alfresc
import { EventEmitter, Injectable, Output } from '@angular/core';
import { from, Observable, throwError } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
-import {
- RequestQuery,
- RequestSortDefinitionInner,
- ResultSetContextFacetQueries,
- SearchApi,
- Tag,
- TagBody,
- TagEntry,
- TagPaging,
- TagPagingList,
- TagsApi
-} from '@alfresco/js-api';
+import { TagBody, TagEntry, TagPaging, TagsApi } from '@alfresco/js-api';
@Injectable({
providedIn: 'root'
@@ -43,12 +32,6 @@ export class TagService {
return this._tagsApi;
}
- private _searchApi: SearchApi;
- get searchApi(): SearchApi {
- this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance());
- return this._searchApi;
- }
-
/** Emitted when tag information is updated. */
@Output()
refresh = new EventEmitter();
@@ -74,11 +57,14 @@ export class TagService {
* Gets a list of all the tags already defined in the repository.
*
* @param opts Options supported by JS-API
+ * @param includedCounts True if count field should be included in response object for each tag, false otherwise.
* @returns TagPaging object (defined in JS-API) containing the tags
*/
- getAllTheTags(opts?: any): Observable {
- return from(this.tagsApi.listTags(opts))
- .pipe(catchError((err) => this.handleError(err)));
+ getAllTheTags(opts?: any, includedCounts?: boolean): Observable {
+ return from(this.tagsApi.listTags({
+ include: includedCounts ? ['count'] : undefined,
+ ...opts
+ })).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -157,61 +143,25 @@ export class TagService {
* Find tags which name contains searched name.
*
* @param name Value for name which should be used during searching tags.
+ * @param sorting Object which configures sorting. OrderBy field specifies field used for sorting, direction specified ascending or descending direction.
+ * Default sorting is ascending by tag field.
+ * @param includedCounts True if count field should be included in response object for each tag, false otherwise.
* @param skipCount Specify how many first results should be skipped. Default 0.
* @param maxItems Specify max number of returned tags. Default is specified by UserPreferencesService.
* @returns Found tags which name contains searched name.
*/
- searchTags(name: string, skipCount = 0, maxItems?: number): Observable {
+ searchTags(name: string, sorting = {
+ orderBy: 'tag',
+ direction: 'asc'
+ }, includedCounts?: boolean, skipCount = 0, maxItems?: number): Observable {
maxItems = maxItems || this.userPreferencesService.paginationSize;
- const sortingByName: RequestSortDefinitionInner = new RequestSortDefinitionInner();
- sortingByName.field = 'cm:name';
- sortingByName.ascending = true;
- sortingByName.type = RequestSortDefinitionInner.TypeEnum.FIELD;
- return from(this.searchApi.search({
- query: {
- language: RequestQuery.LanguageEnum.Afts,
- query: `PATH:"/cm:categoryRoot/cm:taggable/*" AND cm:name:"*${name}*"`
- },
- paging: {
- skipCount,
- maxItems
- },
- sort: [sortingByName]
- })).pipe(map((resultSetPaging) => {
- const tagPaging = new TagPaging();
- tagPaging.list = new TagPagingList();
- tagPaging.list.pagination = resultSetPaging.list.pagination;
- tagPaging.list.entries = resultSetPaging.list.entries.map((resultEntry) => {
- const tagEntry = new TagEntry();
- tagEntry.entry = new Tag();
- tagEntry.entry.tag = resultEntry.entry.name;
- tagEntry.entry.id = resultEntry.entry.id;
- return tagEntry;
- });
- return tagPaging;
- }), catchError((error) => this.handleError(error)));
- }
-
- /**
- * Get usage counters for passed tags.
- *
- * @param tags Array of tags names for which there should be returned counters.
- * @returns Array of usage counters for specified tags.
- */
- getCountersForTags(tags: string[]): Observable {
- return from(this.searchApi.search({
- query: {
- language: RequestQuery.LanguageEnum.Afts,
- query: `*`
- },
- facetQueries: tags.map((tag) => ({
- query: `TAG:"${tag}"`,
- label: tag
- }))
- })).pipe(
- map((paging) => paging.list?.context?.facetQueries),
- catchError((error) => this.handleError(error))
- );
+ return this.getAllTheTags({
+ tag: `*${name}*`,
+ skipCount,
+ maxItems,
+ sorting,
+ matching: true
+ }, includedCounts).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -221,7 +171,7 @@ export class TagService {
* @returns Found tag which name matches exactly to passed name.
*/
findTagByName(name: string): Observable {
- return this.getAllTheTags({ name }).pipe(
+ return this.getAllTheTags({ tag: name }).pipe(
map((result) => result.list.entries[0]),
catchError((error) => this.handleError(error))
);