mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACS-5991] ESLint fixes and code quality improvements (#8893)
* prefer-optional-chain: core * prefer-optional-chain: content, fix typings * prefer-optional-chain: process, fix typings * prefer-optional-chain: process-cloud, fix typings, fix ts configs and eslint * [ci: force] sonar errors fixes, insights lib * [ci:force] fix security issues * [ci:force] fix metadata e2e bug, js assignment bugs * [ci:force] fix lint issue * [ci:force] fix tests
This commit is contained in:
@@ -62,10 +62,6 @@
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"brace-style": [
|
||||
"error",
|
||||
"1tbs"
|
||||
],
|
||||
"comma-dangle": "error",
|
||||
"default-case": "error",
|
||||
"import/order": "off",
|
||||
|
@@ -18,33 +18,24 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import {
|
||||
AuditApi,
|
||||
AuditAppPaging,
|
||||
AuditAppEntry,
|
||||
AuditApp,
|
||||
AuditBodyUpdate,
|
||||
AuditEntryPaging,
|
||||
AuditEntryEntry
|
||||
} from '@alfresco/js-api';
|
||||
import { AuditApi, AuditAppPaging, AuditAppEntry, AuditApp, AuditBodyUpdate, AuditEntryPaging, AuditEntryEntry } from '@alfresco/js-api';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuditService {
|
||||
|
||||
private _auditApi: AuditApi;
|
||||
get auditApi(): AuditApi {
|
||||
this._auditApi = this._auditApi ?? new AuditApi(this.apiService.getInstance());
|
||||
return this._auditApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
|
||||
|
||||
/**
|
||||
* Gets a list of audit applications.
|
||||
*
|
||||
* @param opts Options.
|
||||
* @returns a list of the audit applications.
|
||||
*/
|
||||
@@ -53,14 +44,12 @@ export class AuditService {
|
||||
skipCount: 0
|
||||
};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.listAuditApps(queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.listAuditApps(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get audit application info.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param opts Options.
|
||||
* @returns status of an audit application.
|
||||
@@ -70,14 +59,12 @@ export class AuditService {
|
||||
auditApplicationId
|
||||
};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.getAuditApp(queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.getAuditApp(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update audit application info.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param auditAppBodyUpdate The audit application to update.
|
||||
* @param opts Options.
|
||||
@@ -86,14 +73,14 @@ export class AuditService {
|
||||
updateAuditApp(auditApplicationId: string, auditAppBodyUpdate: boolean, opts?: any): Observable<AuditApp | any> {
|
||||
const defaultOptions = {};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.updateAuditApp(auditApplicationId, new AuditBodyUpdate({ isEnabled: auditAppBodyUpdate }), queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.updateAuditApp(auditApplicationId, new AuditBodyUpdate({ isEnabled: auditAppBodyUpdate }), queryOptions)).pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List audit entries for an audit application.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param opts Options.
|
||||
* @returns a list of audit entries.
|
||||
@@ -104,14 +91,14 @@ export class AuditService {
|
||||
maxItems: 100
|
||||
};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.listAuditEntriesForAuditApp(auditApplicationId, queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.listAuditEntriesForAuditApp(auditApplicationId, queryOptions)).pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get audit entry.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param auditEntryId The identifier of an audit entry.
|
||||
* @param opts Options.
|
||||
@@ -120,14 +107,14 @@ export class AuditService {
|
||||
getAuditEntry(auditApplicationId: string, auditEntryId: string, opts?: any): Observable<AuditEntryEntry> {
|
||||
const defaultOptions = {};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.getAuditEntry(auditApplicationId, auditEntryId, queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.getAuditEntry(auditApplicationId, auditEntryId, queryOptions)).pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List audit entries for a node.
|
||||
*
|
||||
* @param nodeId The identifier of a node.
|
||||
* @param opts Options.
|
||||
* @returns
|
||||
@@ -137,36 +124,29 @@ export class AuditService {
|
||||
nodeId
|
||||
};
|
||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||
return from(this.auditApi.listAuditEntriesForNode(queryOptions))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.listAuditEntriesForNode(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently delete audit entries for an audit application.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param where Audit entries to permanently delete for an audit application, given an inclusive time period or range of ids.
|
||||
* @returns
|
||||
*/
|
||||
deleteAuditEntries(auditApplicationId: string, where: string): Observable<any> {
|
||||
return from(this.auditApi.deleteAuditEntriesForAuditApp(auditApplicationId, where))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.deleteAuditEntriesForAuditApp(auditApplicationId, where)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently delete an audit entry.
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param auditEntryId The identifier of an audit entry.
|
||||
* @returns
|
||||
*/
|
||||
deleteAuditEntry(auditApplicationId: string, auditEntryId: string): Observable<any> {
|
||||
return from(this.auditApi.deleteAuditEntry(auditApplicationId, auditEntryId))
|
||||
.pipe(
|
||||
catchError((err: any) => this.handleError(err))
|
||||
);
|
||||
return from(this.auditApi.deleteAuditEntry(auditApplicationId, auditEntryId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
}
|
||||
|
||||
private handleError(error: any): any {
|
||||
|
@@ -129,7 +129,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
parseRoute(node: Node): PathElement[] {
|
||||
if (node && node.path) {
|
||||
if (node?.path) {
|
||||
const route = (node.path.elements || []).slice();
|
||||
|
||||
route.push({
|
||||
|
@@ -43,27 +43,27 @@ export class EcmUserModel {
|
||||
capabilities?: Capabilities;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id || null;
|
||||
this.firstName = obj && obj.firstName;
|
||||
this.lastName = obj && obj.lastName;
|
||||
this.description = obj && obj.description || null;
|
||||
this.avatarId = obj && obj.avatarId || null;
|
||||
this.email = obj && obj.email || null;
|
||||
this.skypeId = obj && obj.skypeId;
|
||||
this.googleId = obj && obj.googleId;
|
||||
this.instantMessageId = obj && obj.instantMessageId;
|
||||
this.jobTitle = obj && obj.jobTitle || null;
|
||||
this.location = obj && obj.location || null;
|
||||
this.company = obj && obj.company;
|
||||
this.mobile = obj && obj.mobile;
|
||||
this.telephone = obj && obj.telephone;
|
||||
this.statusUpdatedAt = obj && obj.statusUpdatedAt;
|
||||
this.userStatus = obj && obj.userStatus;
|
||||
this.enabled = obj && obj.enabled;
|
||||
this.emailNotificationsEnabled = obj && obj.emailNotificationsEnabled;
|
||||
this.aspectNames = obj && obj.aspectNames;
|
||||
this.properties = obj && obj.properties;
|
||||
this.capabilities = obj && obj.capabilities;
|
||||
this.id = obj?.id || null;
|
||||
this.firstName = obj?.firstName;
|
||||
this.lastName = obj?.lastName;
|
||||
this.description = obj?.description || null;
|
||||
this.avatarId = obj?.avatarId || null;
|
||||
this.email = obj?.email || null;
|
||||
this.skypeId = obj?.skypeId;
|
||||
this.googleId = obj?.googleId;
|
||||
this.instantMessageId = obj?.instantMessageId;
|
||||
this.jobTitle = obj?.jobTitle || null;
|
||||
this.location = obj?.location || null;
|
||||
this.company = obj?.company;
|
||||
this.mobile = obj?.mobile;
|
||||
this.telephone = obj?.telephone;
|
||||
this.statusUpdatedAt = obj?.statusUpdatedAt;
|
||||
this.userStatus = obj?.userStatus;
|
||||
this.enabled = obj?.enabled;
|
||||
this.emailNotificationsEnabled = obj?.emailNotificationsEnabled;
|
||||
this.aspectNames = obj?.aspectNames;
|
||||
this.properties = obj?.properties;
|
||||
this.capabilities = obj?.capabilities;
|
||||
}
|
||||
|
||||
isAdmin(): boolean {
|
||||
|
@@ -89,7 +89,7 @@ export class ContentService {
|
||||
(currentPermission) => currentPermission.authorityId === userId
|
||||
);
|
||||
if (permissions.length) {
|
||||
if (permission && permission.startsWith('!')) {
|
||||
if (permission?.startsWith('!')) {
|
||||
hasPermissions = !permissions.find((currentPermission) => currentPermission.name === permission.replace('!', ''));
|
||||
} else {
|
||||
hasPermissions = !!permissions.find((currentPermission) => currentPermission.name === permission);
|
||||
@@ -99,7 +99,7 @@ export class ContentService {
|
||||
hasPermissions = true;
|
||||
} else if (permission === PermissionsEnum.NOT_CONSUMER) {
|
||||
hasPermissions = false;
|
||||
} else if (permission && permission.startsWith('!')) {
|
||||
} else if (permission?.startsWith('!')) {
|
||||
hasPermissions = true;
|
||||
}
|
||||
}
|
||||
@@ -117,8 +117,8 @@ export class ContentService {
|
||||
hasAllowableOperations(node: Node, allowableOperation: AllowableOperationsEnum | string): boolean {
|
||||
let hasAllowableOperations = false;
|
||||
|
||||
if (node && node.allowableOperations) {
|
||||
if (allowableOperation && allowableOperation.startsWith('!')) {
|
||||
if (node?.allowableOperations) {
|
||||
if (allowableOperation?.startsWith('!')) {
|
||||
hasAllowableOperations = !node.allowableOperations.find(
|
||||
(currentOperation) => currentOperation === allowableOperation.replace('!', '')
|
||||
);
|
||||
@@ -126,7 +126,7 @@ export class ContentService {
|
||||
hasAllowableOperations = !!node.allowableOperations.find((currentOperation) => currentOperation === allowableOperation);
|
||||
}
|
||||
} else {
|
||||
if (allowableOperation && allowableOperation.startsWith('!')) {
|
||||
if (allowableOperation?.startsWith('!')) {
|
||||
hasAllowableOperations = true;
|
||||
}
|
||||
}
|
||||
|
@@ -221,7 +221,7 @@ export class NodesApiService {
|
||||
private cleanMetadataFromSemicolon(nodeEntry: NodeEntry): NodeMetadata {
|
||||
const metadata = {};
|
||||
|
||||
if (nodeEntry && nodeEntry.entry.properties) {
|
||||
if (nodeEntry?.entry.properties) {
|
||||
for (const key in nodeEntry.entry.properties) {
|
||||
if (key) {
|
||||
if (key.indexOf(':') !== -1) {
|
||||
|
@@ -135,7 +135,7 @@ export class SitesService {
|
||||
*/
|
||||
getSiteNameFromNodePath(node: Node): string {
|
||||
let siteName = '';
|
||||
if (node.path && node.path.elements) {
|
||||
if (node.path?.elements) {
|
||||
const foundNode = node.path.elements.find((pathNode) => pathNode.nodeType === 'st:site' && pathNode.name !== 'Sites');
|
||||
siteName = foundNode ? foundNode.name : '';
|
||||
}
|
||||
|
@@ -18,12 +18,7 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { Minimatch } from 'minimatch';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
FileUploadCompleteEvent,
|
||||
FileUploadDeleteEvent,
|
||||
FileUploadErrorEvent,
|
||||
FileUploadEvent
|
||||
} from '../events/file.event';
|
||||
import { FileUploadCompleteEvent, FileUploadDeleteEvent, FileUploadErrorEvent, FileUploadEvent } from '../events/file.event';
|
||||
import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model';
|
||||
import { AppConfigService, AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { filter } from 'rxjs/operators';
|
||||
@@ -81,12 +76,11 @@ export class UploadService {
|
||||
constructor(
|
||||
protected apiService: AlfrescoApiService,
|
||||
private appConfigService: AppConfigService,
|
||||
private discoveryApiService: DiscoveryApiService) {
|
||||
|
||||
this.discoveryApiService.ecmProductInfo$.pipe(filter(info => !!info))
|
||||
.subscribe(({status}) => {
|
||||
this.isThumbnailGenerationEnabled = status.isThumbnailGenerationEnabled;
|
||||
});
|
||||
private discoveryApiService: DiscoveryApiService
|
||||
) {
|
||||
this.discoveryApiService.ecmProductInfo$.pipe(filter((info) => !!info)).subscribe(({ status }) => {
|
||||
this.isThumbnailGenerationEnabled = status.isThumbnailGenerationEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
@@ -108,8 +102,17 @@ export class UploadService {
|
||||
* @returns True if files in the queue are still uploading, false otherwise
|
||||
*/
|
||||
isUploading(): boolean {
|
||||
const finishedFileStates = [FileUploadStatus.Complete, FileUploadStatus.Cancelled, FileUploadStatus.Aborted, FileUploadStatus.Error, FileUploadStatus.Deleted];
|
||||
return this.queue.reduce((stillUploading: boolean, currentFile: FileModel) => stillUploading || finishedFileStates.indexOf(currentFile.status) === -1, false);
|
||||
const finishedFileStates = [
|
||||
FileUploadStatus.Complete,
|
||||
FileUploadStatus.Cancelled,
|
||||
FileUploadStatus.Aborted,
|
||||
FileUploadStatus.Error,
|
||||
FileUploadStatus.Deleted
|
||||
];
|
||||
return this.queue.reduce(
|
||||
(stillUploading: boolean, currentFile: FileModel) => stillUploading || finishedFileStates.indexOf(currentFile.status) === -1,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,9 +131,7 @@ export class UploadService {
|
||||
* @returns Array of files that were not blocked from upload by the ignore list
|
||||
*/
|
||||
addToQueue(...files: FileModel[]): FileModel[] {
|
||||
const allowedFiles = files.filter((currentFile) =>
|
||||
this.filterElement(currentFile)
|
||||
);
|
||||
const allowedFiles = files.filter((currentFile) => this.filterElement(currentFile));
|
||||
this.queue = this.queue.concat(allowedFiles);
|
||||
this.queueChanged.next(this.queue);
|
||||
return allowedFiles;
|
||||
@@ -217,7 +218,7 @@ export class UploadService {
|
||||
opts.renditions = 'doclib';
|
||||
}
|
||||
|
||||
if (file.options && file.options.versioningEnabled !== undefined) {
|
||||
if (file.options?.versioningEnabled !== undefined) {
|
||||
opts.versioningEnabled = file.options.versioningEnabled;
|
||||
}
|
||||
|
||||
@@ -240,13 +241,7 @@ export class UploadService {
|
||||
const nodeBody: NodeBodyCreate = { ...file.options, name: file.name, nodeType: file.options.nodeType };
|
||||
delete nodeBody['versioningEnabled'];
|
||||
|
||||
return this.uploadApi.uploadFile(
|
||||
file.file,
|
||||
file.options.path,
|
||||
file.options.parentId,
|
||||
nodeBody,
|
||||
opts
|
||||
);
|
||||
return this.uploadApi.uploadFile(file.file, file.options.path, file.options.parentId, nodeBody, opts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +254,7 @@ export class UploadService {
|
||||
}
|
||||
|
||||
const files = this.queue
|
||||
.filter(toUpload => !cached.includes(toUpload.name) && toUpload.status === FileUploadStatus.Pending)
|
||||
.filter((toUpload) => !cached.includes(toUpload.name) && toUpload.status === FileUploadStatus.Pending)
|
||||
.slice(0, threadsCount);
|
||||
|
||||
return files;
|
||||
@@ -274,13 +269,13 @@ export class UploadService {
|
||||
.on('abort', () => {
|
||||
this.onUploadAborted(file);
|
||||
if (successEmitter) {
|
||||
successEmitter.emit({value: 'File aborted'});
|
||||
successEmitter.emit({ value: 'File aborted' });
|
||||
}
|
||||
})
|
||||
.on('error', (err) => {
|
||||
this.onUploadError(file, err);
|
||||
if (errorEmitter) {
|
||||
errorEmitter.emit({value: 'Error file uploaded'});
|
||||
errorEmitter.emit({ value: 'Error file uploaded' });
|
||||
}
|
||||
})
|
||||
.on('success', (data) => {
|
||||
@@ -292,17 +287,16 @@ export class UploadService {
|
||||
this.deleteAbortedNodeVersion(data.entry.id, data.entry.properties['cm:versionLabel']);
|
||||
}
|
||||
if (successEmitter) {
|
||||
successEmitter.emit({value: 'File deleted'});
|
||||
successEmitter.emit({ value: 'File deleted' });
|
||||
}
|
||||
} else {
|
||||
this.onUploadComplete(file, data);
|
||||
if (successEmitter) {
|
||||
successEmitter.emit({value: data});
|
||||
successEmitter.emit({ value: data });
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
.catch(() => {});
|
||||
|
||||
return promise;
|
||||
}
|
||||
@@ -316,10 +310,7 @@ export class UploadService {
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadProgress(
|
||||
file: FileModel,
|
||||
progress: FileUploadProgress
|
||||
): void {
|
||||
private onUploadProgress(file: FileModel, progress: FileUploadProgress): void {
|
||||
if (file) {
|
||||
file.progress = progress;
|
||||
file.status = FileUploadStatus.Progress;
|
||||
@@ -330,9 +321,9 @@ export class UploadService {
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadError(file: FileModel, error: any): void {
|
||||
private onUploadError(file: FileModel, error: { status?: number }): void {
|
||||
if (file) {
|
||||
file.errorCode = (error || {}).status;
|
||||
file.errorCode = error?.status;
|
||||
file.status = FileUploadStatus.Error;
|
||||
this.totalError++;
|
||||
|
||||
@@ -341,11 +332,7 @@ export class UploadService {
|
||||
delete this.cache[file.name];
|
||||
}
|
||||
|
||||
const event = new FileUploadErrorEvent(
|
||||
file,
|
||||
error,
|
||||
this.totalError
|
||||
);
|
||||
const event = new FileUploadErrorEvent(file, error, this.totalError);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadError.next(event);
|
||||
}
|
||||
@@ -361,12 +348,7 @@ export class UploadService {
|
||||
delete this.cache[file.name];
|
||||
}
|
||||
|
||||
const event = new FileUploadCompleteEvent(
|
||||
file,
|
||||
this.totalComplete,
|
||||
data,
|
||||
this.totalAborted
|
||||
);
|
||||
const event = new FileUploadCompleteEvent(file, this.totalComplete, data, this.totalAborted);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadComplete.next(event);
|
||||
}
|
||||
@@ -415,20 +397,15 @@ export class UploadService {
|
||||
}
|
||||
|
||||
private deleteAbortedNode(nodeId: string) {
|
||||
this.nodesApi.deleteNode(nodeId, {permanent: true})
|
||||
.then(() => (this.abortedFile = undefined));
|
||||
this.nodesApi.deleteNode(nodeId, { permanent: true }).then(() => (this.abortedFile = undefined));
|
||||
}
|
||||
|
||||
private deleteAbortedNodeVersion(nodeId: string, versionId: string) {
|
||||
this.versionsApi.deleteVersion(nodeId, versionId)
|
||||
.then(() => (this.abortedFile = undefined));
|
||||
this.versionsApi.deleteVersion(nodeId, versionId).then(() => (this.abortedFile = undefined));
|
||||
}
|
||||
|
||||
private isSaveToAbortFile(file: FileModel): boolean {
|
||||
return (
|
||||
file.size > MIN_CANCELLABLE_FILE_SIZE &&
|
||||
file.progress.percent < MAX_CANCELLABLE_FILE_PERCENTAGE
|
||||
);
|
||||
return file.size > MIN_CANCELLABLE_FILE_SIZE && file.progress.percent < MAX_CANCELLABLE_FILE_PERCENTAGE;
|
||||
}
|
||||
|
||||
private filterElement(file: FileModel) {
|
||||
@@ -454,12 +431,12 @@ export class UploadService {
|
||||
const fileRelativePath = currentFile.webkitRelativePath ? currentFile.webkitRelativePath : file.options.path;
|
||||
if (currentFile && fileRelativePath) {
|
||||
isAllowed =
|
||||
this.excludedFoldersList.filter((folderToExclude) => fileRelativePath
|
||||
.split('/')
|
||||
.some((pathElement) => {
|
||||
this.excludedFoldersList.filter((folderToExclude) =>
|
||||
fileRelativePath.split('/').some((pathElement) => {
|
||||
const minimatch = new Minimatch(folderToExclude, this.folderMatchingOptions);
|
||||
return minimatch.match(pathElement);
|
||||
})).length === 0;
|
||||
})
|
||||
).length === 0;
|
||||
}
|
||||
return isAllowed;
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@ import { AllowableOperationsEnum } from '../../../common/models/allowable-operat
|
||||
host: { class: 'adf-content-metadata-card' }
|
||||
})
|
||||
export class ContentMetadataCardComponent implements OnChanges {
|
||||
|
||||
/** (required) The node entity to fetch metadata about */
|
||||
@Input()
|
||||
node: Node;
|
||||
@@ -101,12 +100,16 @@ export class ContentMetadataCardComponent implements OnChanges {
|
||||
|
||||
editAspectSupported = false;
|
||||
|
||||
constructor(private contentService: ContentService, private nodeAspectService: NodeAspectService, private versionCompatibilityService: VersionCompatibilityService) {
|
||||
constructor(
|
||||
private contentService: ContentService,
|
||||
private nodeAspectService: NodeAspectService,
|
||||
private versionCompatibilityService: VersionCompatibilityService
|
||||
) {
|
||||
this.editAspectSupported = this.versionCompatibilityService.isVersionSupported('7');
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.displayAspect && changes.displayAspect.currentValue) {
|
||||
if (changes.displayAspect?.currentValue) {
|
||||
this.expanded = true;
|
||||
}
|
||||
}
|
||||
|
@@ -407,7 +407,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
private isExcludedSiteContent(row: ShareDataRow): boolean {
|
||||
const entry = row.node.entry;
|
||||
if (this._excludeSiteContent && this._excludeSiteContent.length && entry && entry.properties && entry.properties['st:componentId']) {
|
||||
if (this._excludeSiteContent?.length && entry && entry.properties?.['st:componentId']) {
|
||||
const excludedItem = this._excludeSiteContent.find((id: string) => entry.properties['st:componentId'] === id);
|
||||
return !!excludedItem;
|
||||
}
|
||||
@@ -489,7 +489,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (this.customResourcesService.hasCorrespondingNodeIds(this.siteId)) {
|
||||
this.customResourcesService.getCorrespondingNodeIds(this.siteId).subscribe((nodeIds) => {
|
||||
if (nodeIds && nodeIds.length) {
|
||||
if (nodeIds?.length) {
|
||||
nodeIds
|
||||
.filter((id) => id !== this.siteId)
|
||||
.forEach((extraId) => {
|
||||
|
@@ -15,14 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
Inject,
|
||||
OnInit,
|
||||
ViewEncapsulation,
|
||||
ViewChild,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
||||
@@ -43,11 +36,10 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
selector: 'adf-share-dialog',
|
||||
templateUrl: './content-node-share.dialog.html',
|
||||
styleUrls: ['./content-node-share.dialog.scss'],
|
||||
host: {class: 'adf-share-dialog'},
|
||||
host: { class: 'adf-share-dialog' },
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
minDate = add(new Date(), { days: 1 });
|
||||
sharedId: string;
|
||||
fileName: string;
|
||||
@@ -57,16 +49,16 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
isLinkWithExpiryDate = false;
|
||||
form: UntypedFormGroup = new UntypedFormGroup({
|
||||
sharedUrl: new UntypedFormControl(''),
|
||||
time: new UntypedFormControl({value: '', disabled: true})
|
||||
time: new UntypedFormControl({ value: '', disabled: true })
|
||||
});
|
||||
type: DatePickerType = 'date';
|
||||
maxDebounceTime = 500;
|
||||
isExpiryDateToggleChecked: boolean;
|
||||
|
||||
@ViewChild('slideToggleExpirationDate', {static: true})
|
||||
@ViewChild('slideToggleExpirationDate', { static: true })
|
||||
slideToggleExpirationDate;
|
||||
|
||||
@ViewChild('datePickerInput', {static: true})
|
||||
@ViewChild('datePickerInput', { static: true })
|
||||
datePickerInput;
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
@@ -78,17 +70,16 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
private contentService: ContentService,
|
||||
private renditionService: RenditionService,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeShareSettings
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.data.node && this.data.node.entry) {
|
||||
if (this.data.node?.entry) {
|
||||
this.fileName = this.data.node.entry.name;
|
||||
this.baseShareUrl = this.data.baseShareUrl;
|
||||
|
||||
const properties = this.data.node.entry.properties;
|
||||
|
||||
if (!properties || !properties['qshare:sharedId']) {
|
||||
if (!properties?.['qshare:sharedId']) {
|
||||
this.createSharedLinks(this.data.node.entry.id);
|
||||
} else {
|
||||
this.sharedId = properties['qshare:sharedId'];
|
||||
@@ -100,12 +91,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
this.time.valueChanges
|
||||
.pipe(
|
||||
debounceTime(this.maxDebounceTime),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe(value => this.onTimeChanged(value));
|
||||
this.time.valueChanges.pipe(debounceTime(this.maxDebounceTime), takeUntil(this.onDestroy$)).subscribe((value) => this.onTimeChanged(value));
|
||||
}
|
||||
|
||||
onTimeChanged(date: Date) {
|
||||
@@ -130,9 +116,9 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get canUpdate() {
|
||||
const {entry} = this.data.node;
|
||||
const { entry } = this.data.node;
|
||||
|
||||
if (entry && entry.allowableOperations) {
|
||||
if (entry?.allowableOperations) {
|
||||
return this.contentService.hasAllowableOperations(entry, 'update');
|
||||
}
|
||||
|
||||
@@ -214,28 +200,25 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
deleteSharedLink(sharedId: string, dialogOpenFlag?: boolean) {
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService
|
||||
.deleteSharedLink(sharedId)
|
||||
.subscribe((response: any) => {
|
||||
if (response instanceof Error) {
|
||||
this.isDisabled = false;
|
||||
this.isFileShared = true;
|
||||
this.handleError(response);
|
||||
} else {
|
||||
if (this.data.node.entry.properties) {
|
||||
this.data.node.entry.properties['qshare:sharedId'] = null;
|
||||
this.data.node.entry.properties['qshare:expiryDate'] = null;
|
||||
}
|
||||
if (dialogOpenFlag) {
|
||||
this.createSharedLinks(this.data.node.entry.id);
|
||||
this.isExpiryDateToggleChecked = false;
|
||||
this.isLinkWithExpiryDate = false;
|
||||
} else {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
}
|
||||
this.sharedLinksApiService.deleteSharedLink(sharedId).subscribe((response: any) => {
|
||||
if (response instanceof Error) {
|
||||
this.isDisabled = false;
|
||||
this.isFileShared = true;
|
||||
this.handleError(response);
|
||||
} else {
|
||||
if (this.data.node.entry.properties) {
|
||||
this.data.node.entry.properties['qshare:sharedId'] = null;
|
||||
this.data.node.entry.properties['qshare:expiryDate'] = null;
|
||||
}
|
||||
);
|
||||
if (dialogOpenFlag) {
|
||||
this.createSharedLinks(this.data.node.entry.id);
|
||||
this.isExpiryDateToggleChecked = false;
|
||||
this.isLinkWithExpiryDate = false;
|
||||
} else {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private handleError(error: Error) {
|
||||
@@ -244,8 +227,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
try {
|
||||
statusCode = JSON.parse(error.message).error.statusCode;
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
|
||||
if (statusCode === 403) {
|
||||
message = 'SHARE.UNSHARE_PERMISSION_ERROR';
|
||||
@@ -258,17 +240,20 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private updateForm(): Date {
|
||||
const {entry} = this.data.node;
|
||||
const { entry } = this.data.node;
|
||||
let expiryDate = null;
|
||||
|
||||
if (entry && entry.properties) {
|
||||
if (entry?.properties) {
|
||||
expiryDate = entry.properties['qshare:expiryDate'];
|
||||
}
|
||||
|
||||
this.form.setValue({
|
||||
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
||||
time: expiryDate ? new Date(expiryDate) : null
|
||||
}, { emitEvent: false });
|
||||
this.form.setValue(
|
||||
{
|
||||
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
||||
time: expiryDate ? new Date(expiryDate) : null
|
||||
},
|
||||
{ emitEvent: false }
|
||||
);
|
||||
|
||||
return expiryDate;
|
||||
}
|
||||
@@ -279,25 +264,25 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
if (this.type === 'date') {
|
||||
expiryDate = format(endOfDay(new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
} else {
|
||||
expiryDate = format((new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
expiryDate = format(new Date(date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||
}
|
||||
} else {
|
||||
expiryDate = null;
|
||||
}
|
||||
|
||||
if (this.sharedId && expiryDate) {
|
||||
this.isDisabled = true;
|
||||
this.isDisabled = true;
|
||||
|
||||
this.sharedLinksApiService.deleteSharedLink(this.sharedId).subscribe((response: any) => {
|
||||
if (response instanceof Error) {
|
||||
this.isDisabled = false;
|
||||
this.isFileShared = true;
|
||||
this.handleError(response);
|
||||
} else {
|
||||
this.sharedLinkWithExpirySettings(expiryDate as Date);
|
||||
this.isLinkWithExpiryDate = true;
|
||||
this.updateEntryExpiryDate(date);
|
||||
}
|
||||
this.sharedLinksApiService.deleteSharedLink(this.sharedId).subscribe((response: any) => {
|
||||
if (response instanceof Error) {
|
||||
this.isDisabled = false;
|
||||
this.isFileShared = true;
|
||||
this.handleError(response);
|
||||
} else {
|
||||
this.sharedLinkWithExpirySettings(expiryDate as Date);
|
||||
this.isLinkWithExpiryDate = true;
|
||||
this.updateEntryExpiryDate(date);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -311,12 +296,10 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private updateEntryExpiryDate(date: Date) {
|
||||
const {properties} = this.data.node.entry;
|
||||
const { properties } = this.data.node.entry;
|
||||
|
||||
if (properties) {
|
||||
properties['qshare:expiryDate'] = date
|
||||
? new Date(date)
|
||||
: null;
|
||||
properties['qshare:expiryDate'] = date ? new Date(date) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,12 +29,11 @@ import { takeUntil } from 'rxjs/operators';
|
||||
exportAs: 'adfShare'
|
||||
})
|
||||
export class NodeSharedDirective implements OnChanges, OnDestroy {
|
||||
|
||||
isFile: boolean = false;
|
||||
isShared: boolean = false;
|
||||
|
||||
/** Node to share. */
|
||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||
@Input('adf-share')
|
||||
node: NodeEntry;
|
||||
|
||||
@@ -50,11 +49,7 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
||||
return this._nodesApi;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private zone: NgZone,
|
||||
private alfrescoApiService: AlfrescoApiService) {
|
||||
}
|
||||
constructor(private dialog: MatDialog, private zone: NgZone, private alfrescoApiService: AlfrescoApiService) {}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
@@ -62,7 +57,7 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
shareNode(nodeEntry: NodeEntry) {
|
||||
if (nodeEntry && nodeEntry.entry && nodeEntry.entry.isFile) {
|
||||
if (nodeEntry?.entry?.isFile) {
|
||||
// shared and favorite
|
||||
const nodeId = nodeEntry.entry['nodeId'] || nodeEntry.entry['guid'];
|
||||
|
||||
@@ -96,14 +91,12 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.zone.onStable
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
if (this.node && this.node.entry) {
|
||||
this.isFile = this.node.entry.isFile;
|
||||
this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false;
|
||||
}
|
||||
});
|
||||
this.zone.onStable.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||
if (this.node?.entry) {
|
||||
this.isFile = this.node.entry.isFile;
|
||||
this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
|
@@ -46,7 +46,7 @@ export class DownloadZipDialogComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.data && this.data.nodeIds && this.data.nodeIds.length > 0) {
|
||||
if (this.data?.nodeIds?.length > 0) {
|
||||
if (!this.cancelled) {
|
||||
this.downloadZip(this.data.nodeIds);
|
||||
} else {
|
||||
@@ -64,7 +64,7 @@ export class DownloadZipDialogComponent implements OnInit {
|
||||
downloadZip(nodeIds: string[]) {
|
||||
if (nodeIds && nodeIds.length > 0) {
|
||||
this.downloadZipService.createDownload({ nodeIds }).subscribe((data: DownloadEntry) => {
|
||||
if (data && data.entry && data.entry.id) {
|
||||
if (data?.entry?.id) {
|
||||
const url = this.contentService.getContentUrl(data.entry.id, true);
|
||||
|
||||
this.nodeService.getNode(data.entry.id).subscribe((downloadNode) => {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter } from '@angular/core';
|
||||
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter, SimpleChanges } from '@angular/core';
|
||||
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { LibraryEntity } from '../interfaces/library-entity.interface';
|
||||
@@ -59,7 +59,7 @@ export class LibraryFavoriteDirective implements OnChanges {
|
||||
|
||||
constructor(private alfrescoApiService: AlfrescoApiService) {}
|
||||
|
||||
ngOnChanges(changes) {
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!changes.library.currentValue) {
|
||||
this.targetLibrary = null;
|
||||
return;
|
||||
@@ -70,7 +70,7 @@ export class LibraryFavoriteDirective implements OnChanges {
|
||||
}
|
||||
|
||||
isFavorite(): boolean {
|
||||
return this.targetLibrary && this.targetLibrary.isFavorite;
|
||||
return this.targetLibrary?.isFavorite;
|
||||
}
|
||||
|
||||
private async markFavoriteLibrary(library: LibraryEntity) {
|
||||
|
@@ -16,17 +16,11 @@
|
||||
*/
|
||||
|
||||
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import {
|
||||
SiteEntry,
|
||||
SiteMembershipRequestBodyCreate,
|
||||
SiteMemberEntry,
|
||||
SiteMembershipRequestEntry,
|
||||
SitesApi
|
||||
} from '@alfresco/js-api';
|
||||
import { SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api';
|
||||
import { BehaviorSubject, from, Observable } from 'rxjs';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { LibraryMembershipToggleEvent } from '../interfaces/library-membership-toggle-event.interface';
|
||||
import { LibraryMembershipErrorEvent} from '../interfaces/library-membership-error-event.interface';
|
||||
import { LibraryMembershipErrorEvent } from '../interfaces/library-membership-error-event.interface';
|
||||
import { VersionCompatibilityService } from '../version-compatibility/version-compatibility.service';
|
||||
import { SitesService } from '../common/services/sites.service';
|
||||
|
||||
@@ -39,7 +33,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
|
||||
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
||||
_sitesApi: SitesApi;
|
||||
private _sitesApi: SitesApi;
|
||||
get sitesApi(): SitesApi {
|
||||
this._sitesApi = this._sitesApi ?? new SitesApi(this.alfrescoApiService.getInstance());
|
||||
return this._sitesApi;
|
||||
@@ -69,11 +63,10 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private sitesService: SitesService,
|
||||
private versionCompatibilityService: VersionCompatibilityService
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!changes.selection.currentValue || !changes.selection.currentValue.entry) {
|
||||
if (!changes.selection.currentValue?.entry) {
|
||||
this.targetSite = null;
|
||||
|
||||
return;
|
||||
@@ -115,7 +108,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
this.targetSite.joinRequested = true;
|
||||
this.isJoinRequested.next(true);
|
||||
|
||||
if (createdMembership.entry && createdMembership.entry.site && createdMembership.entry.site.role) {
|
||||
if (createdMembership.entry?.site?.role) {
|
||||
const info = {
|
||||
shouldReload: true,
|
||||
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
||||
@@ -154,8 +147,8 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
|
||||
if (this.isAdmin) {
|
||||
this.joinLibrary().subscribe(
|
||||
(createdMembership: SiteMemberEntry) => {
|
||||
if (createdMembership.entry && createdMembership.entry.role) {
|
||||
(createdMembership) => {
|
||||
if (createdMembership.entry?.role) {
|
||||
const info = {
|
||||
shouldReload: true,
|
||||
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
||||
@@ -223,7 +216,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
});
|
||||
}
|
||||
|
||||
private cancelJoinRequest() {
|
||||
private cancelJoinRequest(): Observable<void> {
|
||||
return from(this.sitesApi.deleteSiteMembershipRequestForPerson('-me-', this.targetSite.id));
|
||||
}
|
||||
|
||||
|
@@ -78,10 +78,7 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
this.process(this.selection);
|
||||
}
|
||||
|
||||
constructor(private alfrescoApiService: AlfrescoApiService,
|
||||
private translation: TranslationService,
|
||||
private elementRef: ElementRef) {
|
||||
}
|
||||
constructor(private alfrescoApiService: AlfrescoApiService, private translation: TranslationService, private elementRef: ElementRef) {}
|
||||
|
||||
ngOnChanges() {
|
||||
if (!this.selection || (this.selection && this.selection.length === 0)) {
|
||||
@@ -98,23 +95,21 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
}
|
||||
|
||||
private process(selection: NodeEntry[] | DeletedNodeEntry[]) {
|
||||
if (selection && selection.length) {
|
||||
|
||||
if (selection?.length) {
|
||||
const batch = this.getDeleteNodesBatch(selection);
|
||||
|
||||
forkJoin(...batch)
|
||||
.subscribe((data: ProcessedNodeData[]) => {
|
||||
const processedItems: ProcessStatus = this.processStatus(data);
|
||||
const message = this.getMessage(processedItems);
|
||||
forkJoin(...batch).subscribe((data: ProcessedNodeData[]) => {
|
||||
const processedItems: ProcessStatus = this.processStatus(data);
|
||||
const message = this.getMessage(processedItems);
|
||||
|
||||
if (message) {
|
||||
this.delete.emit(message);
|
||||
}
|
||||
});
|
||||
if (message) {
|
||||
this.delete.emit(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getDeleteNodesBatch(selection: any): Observable<ProcessedNodeData>[] {
|
||||
private getDeleteNodesBatch(selection: NodeEntry[] | DeletedNodeEntry[]): Observable<ProcessedNodeData>[] {
|
||||
return selection.map((node) => this.deleteNode(node));
|
||||
}
|
||||
|
||||
@@ -135,10 +130,12 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
entry: node.entry,
|
||||
status: 1
|
||||
})),
|
||||
catchError(() => of({
|
||||
entry: node.entry,
|
||||
status: 0
|
||||
}))
|
||||
catchError(() =>
|
||||
of({
|
||||
entry: node.entry,
|
||||
status: 0
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -147,10 +144,10 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
success: [],
|
||||
failed: [],
|
||||
get someFailed() {
|
||||
return !!(this.failed.length);
|
||||
return !!this.failed.length;
|
||||
},
|
||||
get someSucceeded() {
|
||||
return !!(this.success.length);
|
||||
return !!this.success.length;
|
||||
},
|
||||
get oneFailed() {
|
||||
return this.failed.length === 1;
|
||||
@@ -166,18 +163,15 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
}
|
||||
};
|
||||
|
||||
return data.reduce(
|
||||
(acc, next) => {
|
||||
if (next.status === 1) {
|
||||
acc.success.push(next);
|
||||
} else {
|
||||
acc.failed.push(next);
|
||||
}
|
||||
return data.reduce((acc, next) => {
|
||||
if (next.status === 1) {
|
||||
acc.success.push(next);
|
||||
} else {
|
||||
acc.failed.push(next);
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
deleteStatus
|
||||
);
|
||||
return acc;
|
||||
}, deleteStatus);
|
||||
}
|
||||
|
||||
private getMessage(status: ProcessStatus): string | null {
|
||||
@@ -198,37 +192,25 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
}
|
||||
|
||||
if (status.someFailed && status.someSucceeded && !status.oneSucceeded) {
|
||||
return this.translation.instant(
|
||||
'CORE.DELETE_NODE.PARTIAL_PLURAL',
|
||||
{
|
||||
success: status.success.length,
|
||||
failed: status.failed.length
|
||||
}
|
||||
);
|
||||
return this.translation.instant('CORE.DELETE_NODE.PARTIAL_PLURAL', {
|
||||
success: status.success.length,
|
||||
failed: status.failed.length
|
||||
});
|
||||
}
|
||||
|
||||
if (status.someFailed && status.oneSucceeded) {
|
||||
return this.translation.instant(
|
||||
'CORE.DELETE_NODE.PARTIAL_SINGULAR',
|
||||
{
|
||||
success: status.success.length,
|
||||
failed: status.failed.length
|
||||
}
|
||||
);
|
||||
return this.translation.instant('CORE.DELETE_NODE.PARTIAL_SINGULAR', {
|
||||
success: status.success.length,
|
||||
failed: status.failed.length
|
||||
});
|
||||
}
|
||||
|
||||
if (status.oneFailed && !status.someSucceeded) {
|
||||
return this.translation.instant(
|
||||
'CORE.DELETE_NODE.ERROR_SINGULAR',
|
||||
{ name: status.failed[0].entry.name }
|
||||
);
|
||||
return this.translation.instant('CORE.DELETE_NODE.ERROR_SINGULAR', { name: status.failed[0].entry.name });
|
||||
}
|
||||
|
||||
if (status.oneSucceeded && !status.someFailed) {
|
||||
return this.translation.instant(
|
||||
'CORE.DELETE_NODE.SINGULAR',
|
||||
{ name: status.success[0].entry.name }
|
||||
);
|
||||
return this.translation.instant('CORE.DELETE_NODE.SINGULAR', { name: status.success[0].entry.name });
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@@ -29,7 +29,6 @@ import { ContentApi, NodeEntry, VersionEntry } from '@alfresco/js-api';
|
||||
selector: '[adfNodeDownload]'
|
||||
})
|
||||
export class NodeDownloadDirective {
|
||||
|
||||
_contentApi: ContentApi;
|
||||
get contentApi(): ContentApi {
|
||||
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
|
||||
@@ -49,11 +48,7 @@ export class NodeDownloadDirective {
|
||||
this.downloadNodes(this.nodes);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private downloadService: DownloadService,
|
||||
private dialog: MatDialog) {
|
||||
}
|
||||
constructor(private apiService: AlfrescoApiService, private downloadService: DownloadService, private dialog: MatDialog) {}
|
||||
|
||||
/**
|
||||
* Downloads multiple selected nodes.
|
||||
@@ -62,7 +57,6 @@ export class NodeDownloadDirective {
|
||||
* @param selection Multiple selected nodes to download
|
||||
*/
|
||||
downloadNodes(selection: NodeEntry | Array<NodeEntry>) {
|
||||
|
||||
if (!this.isSelectionValid(selection)) {
|
||||
return;
|
||||
}
|
||||
@@ -84,7 +78,7 @@ export class NodeDownloadDirective {
|
||||
* @param node Node to download
|
||||
*/
|
||||
downloadNode(node: NodeEntry) {
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
const entry = node.entry;
|
||||
|
||||
if (entry.isFile) {
|
||||
@@ -107,12 +101,12 @@ export class NodeDownloadDirective {
|
||||
}
|
||||
|
||||
private downloadFile(node: NodeEntry) {
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
// nodeId for Shared node
|
||||
const id = (node.entry as any).nodeId || node.entry.id;
|
||||
|
||||
let url;
|
||||
let fileName;
|
||||
let url: string;
|
||||
let fileName: string;
|
||||
if (this.version) {
|
||||
url = this.contentApi.getVersionContentUrl(id, this.version.entry.id, true);
|
||||
fileName = this.version.entry.name;
|
||||
@@ -128,7 +122,7 @@ export class NodeDownloadDirective {
|
||||
private downloadZip(selection: Array<NodeEntry>) {
|
||||
if (selection && selection.length > 0) {
|
||||
// nodeId for Shared node
|
||||
const nodeIds = selection.map((node: any) => (node.entry.nodeId || node.entry.id));
|
||||
const nodeIds = selection.map((node: any) => node.entry.nodeId || node.entry.id);
|
||||
|
||||
this.dialog.open(DownloadZipDialogComponent, {
|
||||
width: '600px',
|
||||
|
@@ -130,7 +130,7 @@ export class NodeFavoriteDirective implements OnChanges {
|
||||
const node: Node | SharedLink = selected.entry;
|
||||
|
||||
// ACS 6.x with 'isFavorite' include
|
||||
if (node && node.hasOwnProperty('isFavorite')) {
|
||||
if (node?.hasOwnProperty('isFavorite')) {
|
||||
return of(selected);
|
||||
}
|
||||
|
||||
|
@@ -19,8 +19,20 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import {
|
||||
AfterContentInit, Component, ContentChild, ElementRef, EventEmitter, HostListener, Input,
|
||||
OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild, ViewEncapsulation
|
||||
AfterContentInit,
|
||||
Component,
|
||||
ContentChild,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { ContentService } from '../../common/services/content.service';
|
||||
|
||||
@@ -75,15 +87,17 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
|
||||
selector: 'adf-document-list',
|
||||
templateUrl: './document-list.component.html',
|
||||
styleUrls: ['./document-list.component.scss'],
|
||||
providers:[{
|
||||
provide: ADF_DOCUMENT_PARENT_COMPONENT,
|
||||
useExisting: DocumentListComponent
|
||||
}, DataTableService],
|
||||
providers: [
|
||||
{
|
||||
provide: ADF_DOCUMENT_PARENT_COMPONENT,
|
||||
useExisting: DocumentListComponent
|
||||
},
|
||||
DataTableService
|
||||
],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-document-list' }
|
||||
})
|
||||
export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, AfterContentInit, PaginatedComponent, NavigableComponentInterface {
|
||||
|
||||
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
||||
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
||||
|
||||
@@ -94,10 +108,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
totalItems: 0
|
||||
});
|
||||
|
||||
DEFAULT_SORTING: DataSorting[] = [
|
||||
new DataSorting('name', 'asc'),
|
||||
new DataSorting('isFolder', 'desc')
|
||||
];
|
||||
DEFAULT_SORTING: DataSorting[] = [new DataSorting('name', 'asc'), new DataSorting('isFolder', 'desc')];
|
||||
|
||||
@ContentChild(DataColumnListComponent)
|
||||
columnList: DataColumnListComponent;
|
||||
@@ -362,34 +373,33 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
return this._nodesApi;
|
||||
}
|
||||
|
||||
constructor(private documentListService: DocumentListService,
|
||||
private elementRef: ElementRef,
|
||||
private appConfig: AppConfigService,
|
||||
private userPreferencesService: UserPreferencesService,
|
||||
private contentService: ContentService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private nodeService: NodesApiService,
|
||||
private dataTableService: DataTableService,
|
||||
private lockService: LockService,
|
||||
private dialog: MatDialog) {
|
||||
|
||||
this.nodeService.nodeUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((node) => {
|
||||
this.dataTableService.rowUpdate.next({id: node.id, obj: {entry: node}});
|
||||
});
|
||||
constructor(
|
||||
private documentListService: DocumentListService,
|
||||
private elementRef: ElementRef,
|
||||
private appConfig: AppConfigService,
|
||||
private userPreferencesService: UserPreferencesService,
|
||||
private contentService: ContentService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private nodeService: NodesApiService,
|
||||
private dataTableService: DataTableService,
|
||||
private lockService: LockService,
|
||||
private dialog: MatDialog
|
||||
) {
|
||||
this.nodeService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||
this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } });
|
||||
});
|
||||
|
||||
this.userPreferencesService
|
||||
.select(UserPreferenceValues.PaginationSize)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(pagSize => {
|
||||
.subscribe((pagSize) => {
|
||||
this.maxItems = this._pagination.maxItems = pagSize;
|
||||
});
|
||||
}
|
||||
|
||||
getContextActions(node: NodeEntry) {
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
const actions = this.getNodeActions(node);
|
||||
if (actions && actions.length > 0) {
|
||||
return actions.map((currentAction: ContentActionModel) => ({
|
||||
@@ -403,7 +413,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
private get hasCustomLayout(): boolean {
|
||||
return this.columnList && this.columnList.columns && this.columnList.columns.length > 0;
|
||||
return this.columnList?.columns?.length > 0;
|
||||
}
|
||||
|
||||
private getDefaultSorting(): DataSorting {
|
||||
@@ -433,8 +443,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
ngOnInit() {
|
||||
this.rowMenuCache = {};
|
||||
this.loadLayoutPresets();
|
||||
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, null, this.getDefaultSorting(),
|
||||
this.sortingMode, this.allowDropFiles);
|
||||
this.data = new ShareDataTableAdapter(
|
||||
this.thumbnailService,
|
||||
this.contentService,
|
||||
null,
|
||||
this.getDefaultSorting(),
|
||||
this.sortingMode,
|
||||
this.allowDropFiles
|
||||
);
|
||||
this.data.thumbnails = this.thumbnails;
|
||||
this.data.permissionsStyle = this.permissionsStyle;
|
||||
|
||||
@@ -446,9 +462,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
this.data.setImageResolver(this.imageResolver);
|
||||
}
|
||||
|
||||
this.contextActionHandler
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(val => this.contextActionCallback(val));
|
||||
this.contextActionHandler.pipe(takeUntil(this.onDestroy$)).subscribe((val) => this.contextActionCallback(val));
|
||||
|
||||
this.enforceSingleClickNavigationForMobile();
|
||||
if (this.filterValue && Object.keys(this.filterValue).length > 0) {
|
||||
@@ -458,9 +472,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
|
||||
ngAfterContentInit() {
|
||||
if (this.columnList) {
|
||||
this.columnList.columns.changes
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => this.setTableSchema());
|
||||
this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.setTableSchema());
|
||||
}
|
||||
this.setTableSchema();
|
||||
}
|
||||
@@ -517,7 +529,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
if (this.data) {
|
||||
if (changes.node && changes.node.currentValue) {
|
||||
if (changes.node?.currentValue) {
|
||||
const merge = this._pagination ? this._pagination.merge : false;
|
||||
this.data.loadPage(changes.node.currentValue, merge, null);
|
||||
this.preserveExistingSelection();
|
||||
@@ -555,7 +567,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
getNodeActions(node: NodeEntry | any): ContentActionModel[] {
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
let target = null;
|
||||
|
||||
if (node.entry.isFile) {
|
||||
@@ -575,9 +587,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
|
||||
const actionsByTarget = this.actions
|
||||
.filter((entry) => {
|
||||
const isVisible = (typeof entry.visible === 'function')
|
||||
? entry.visible(node)
|
||||
: entry.visible;
|
||||
const isVisible = typeof entry.visible === 'function' ? entry.visible(node) : entry.visible;
|
||||
|
||||
return isVisible && entry.target.toLowerCase() === target;
|
||||
})
|
||||
@@ -613,10 +623,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
return action.disabled(node);
|
||||
}
|
||||
|
||||
if ((action.permission &&
|
||||
action.disableWithNoPermission &&
|
||||
!this.contentService.hasAllowableOperations(node.entry, action.permission)) ||
|
||||
this.lockService.isLocked(node.entry)) {
|
||||
if (
|
||||
(action.permission && action.disableWithNoPermission && !this.contentService.hasAllowableOperations(node.entry, action.permission)) ||
|
||||
this.lockService.isLocked(node.entry)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return action.disabled;
|
||||
@@ -654,8 +664,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
private isLinkFolder(node: Node) {
|
||||
return node.nodeType === 'app:folderlink' && node.properties &&
|
||||
node.properties['cm:destination'];
|
||||
return node.nodeType === 'app:folderlink' && node.properties && node.properties['cm:destination'];
|
||||
}
|
||||
|
||||
private updateCustomSourceData(nodeId: string): void {
|
||||
@@ -669,13 +678,11 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
* @param action Action to be executed against the context.
|
||||
*/
|
||||
executeContentAction(node: NodeEntry, action: ContentActionModel) {
|
||||
if (node && node.entry && action) {
|
||||
const handlerSub = (typeof action.handler === 'function') ? action.handler(node, this, action.permission) : of(true);
|
||||
if (node?.entry && action) {
|
||||
const handlerSub = typeof action.handler === 'function' ? action.handler(node, this, action.permission) : of(true);
|
||||
|
||||
if (typeof action.execute === 'function' && handlerSub) {
|
||||
handlerSub
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => action.execute(node));
|
||||
handlerSub.pipe(takeUntil(this.onDestroy$)).subscribe(() => action.execute(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -710,16 +717,18 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
this.updateCustomSourceData(this.currentFolderId);
|
||||
}
|
||||
|
||||
this.documentListService.loadFolderByNodeId(this.currentFolderId, this._pagination, this.includeFields, this.where, this.orderBy)
|
||||
.subscribe((documentNode: DocumentLoaderNode) => {
|
||||
this.documentListService.loadFolderByNodeId(this.currentFolderId, this._pagination, this.includeFields, this.where, this.orderBy).subscribe(
|
||||
(documentNode: DocumentLoaderNode) => {
|
||||
if (documentNode.currentNode) {
|
||||
this.folderNode = documentNode.currentNode.entry;
|
||||
this.$folderNode.next(documentNode.currentNode.entry);
|
||||
}
|
||||
this.onPageLoaded(documentNode.children);
|
||||
}, (err) => {
|
||||
},
|
||||
(err) => {
|
||||
this.handleError(err);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
resetSelection() {
|
||||
@@ -751,10 +760,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
private buildOrderByArray(currentKey: string, currentDirection: string): string[] {
|
||||
return [
|
||||
`${this.additionalSorting.key} ${this.additionalSorting.direction}`,
|
||||
`${currentKey} ${currentDirection}`
|
||||
];
|
||||
return [`${this.additionalSorting.key} ${this.additionalSorting.direction}`, `${currentKey} ${currentDirection}`];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -801,7 +807,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
this.executeActionClick(nodeEntry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onNodeDblClick(nodeEntry: NodeEntry) {
|
||||
@@ -825,7 +830,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
executeActionClick(nodeEntry: NodeEntry) {
|
||||
if (nodeEntry && nodeEntry.entry) {
|
||||
if (nodeEntry?.entry) {
|
||||
if (nodeEntry.entry.isFile) {
|
||||
this.onPreviewFile(nodeEntry);
|
||||
}
|
||||
@@ -839,10 +844,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
include: this.includeFields
|
||||
};
|
||||
|
||||
this.nodesApi.getNode(nodeEntry.entry['guid'], options)
|
||||
.then((node: NodeEntry) => {
|
||||
this.navigateTo(node.entry);
|
||||
});
|
||||
this.nodesApi.getNode(nodeEntry.entry['guid'], options).then((node: NodeEntry) => {
|
||||
this.navigateTo(node.entry);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -911,7 +915,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
canNavigateFolder(node: Node): boolean {
|
||||
let canNavigateFolder: boolean = false;
|
||||
|
||||
if (node && node.isFolder) {
|
||||
if (node?.isFolder) {
|
||||
canNavigateFolder = true;
|
||||
}
|
||||
|
||||
@@ -960,8 +964,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
if (JSON.parse(err.message).error.statusCode === 403) {
|
||||
this.noPermission = true;
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
this.setLoadingState(false);
|
||||
this.error.emit(err);
|
||||
@@ -976,7 +979,11 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
getSelectionBasedOnSelectionMode(): DataRow[] {
|
||||
return this.hasPreselectedRows() ? (this.isSingleSelectionMode() ? [this.preselectedRows[0]] : this.data.getSelectedRows()) : this.data.getSelectedRows();
|
||||
return this.hasPreselectedRows()
|
||||
? this.isSingleSelectionMode()
|
||||
? [this.preselectedRows[0]]
|
||||
: this.data.getSelectedRows()
|
||||
: this.data.getSelectedRows();
|
||||
}
|
||||
|
||||
onPreselectNodes() {
|
||||
|
@@ -63,7 +63,7 @@ export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['currentFolderId'] && changes['currentFolderId'].currentValue) {
|
||||
if (changes['currentFolderId']?.currentValue) {
|
||||
this.resetFilterHeader();
|
||||
this.configureSearchParent(changes['currentFolderId'].currentValue);
|
||||
}
|
||||
|
@@ -15,15 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
ViewEncapsulation,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, ViewEncapsulation, OnInit, Input, ElementRef, OnDestroy } from '@angular/core';
|
||||
import { NodeEntry, Site } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
@@ -36,13 +28,17 @@ import { takeUntil } from 'rxjs/operators';
|
||||
template: `
|
||||
<span
|
||||
role="link"
|
||||
[attr.aria-label]="'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL' | translate:{
|
||||
name: displayText$ | async
|
||||
}"
|
||||
[attr.aria-label]="
|
||||
'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL'
|
||||
| translate
|
||||
: {
|
||||
name: displayText$ | async
|
||||
}
|
||||
"
|
||||
class="adf-datatable-cell-value"
|
||||
title="{{ displayTooltip$ | async }}"
|
||||
(click)="onClick()">
|
||||
|
||||
(click)="onClick()"
|
||||
>
|
||||
{{ displayText$ | async }}
|
||||
</span>
|
||||
`,
|
||||
@@ -62,36 +58,29 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private nodesApiService: NodesApiService
|
||||
) {}
|
||||
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
|
||||
this.nodesApiService.nodeUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(node => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this.node = this.context.row.node;
|
||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||
if (this.node && this.node.entry) {
|
||||
this.displayText$.next(
|
||||
this.makeLibraryTitle(this.node.entry as any, rows)
|
||||
);
|
||||
if (this.node?.entry) {
|
||||
this.displayText$.next(this.makeLibraryTitle(this.node.entry as any, rows));
|
||||
this.displayTooltip$.next(this.makeLibraryTooltip(this.node.entry));
|
||||
}
|
||||
}
|
||||
|
@@ -15,14 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ChangeDetectionStrategy,
|
||||
ViewEncapsulation,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { Component, OnInit, Input, ChangeDetectionStrategy, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { SiteEntry, Site } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
@@ -32,8 +25,8 @@ import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
@Component({
|
||||
selector: 'adf-library-role-column',
|
||||
template: `
|
||||
<span class="adf-datatable-cell-value" title="{{ (displayText$ | async) | translate }}">
|
||||
{{ (displayText$ | async) | translate }}
|
||||
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
||||
{{ displayText$ | async | translate }}
|
||||
</span>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -53,24 +46,22 @@ export class LibraryRoleColumnComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
|
||||
this.nodesApiService.nodeUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(node => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
const node: SiteEntry = this.context.row.node;
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
const role: string = node.entry.role;
|
||||
switch (role) {
|
||||
case Site.RoleEnum.SiteManager:
|
||||
|
@@ -25,8 +25,8 @@ import { takeUntil } from 'rxjs/operators';
|
||||
@Component({
|
||||
selector: 'adf-library-status-column',
|
||||
template: `
|
||||
<span class="adf-datatable-cell-value" title="{{ (displayText$ | async) | translate }}">
|
||||
{{ (displayText$ | async) | translate }}
|
||||
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
||||
{{ displayText$ | async | translate }}
|
||||
</span>
|
||||
`,
|
||||
host: { class: 'adf-library-status-column adf-datatable-content-cell' }
|
||||
@@ -44,24 +44,22 @@ export class LibraryStatusColumnComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
|
||||
this.nodesApiService.nodeUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(node => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
const node: SiteEntry = this.context.row.node;
|
||||
if (node && node.entry) {
|
||||
if (node?.entry) {
|
||||
const visibility: string = node.entry.visibility;
|
||||
|
||||
switch (visibility) {
|
||||
|
@@ -15,15 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ViewEncapsulation,
|
||||
ElementRef,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { Component, Input, OnInit, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, OnDestroy } from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
@@ -35,13 +27,17 @@ import { takeUntil } from 'rxjs/operators';
|
||||
template: `
|
||||
<span
|
||||
role="link"
|
||||
[attr.aria-label]="'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL' | translate:{
|
||||
name: displayText$ | async
|
||||
}"
|
||||
[attr.aria-label]="
|
||||
'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL'
|
||||
| translate
|
||||
: {
|
||||
name: displayText$ | async
|
||||
}
|
||||
"
|
||||
class="adf-datatable-cell-value"
|
||||
title="{{ node | adfNodeNameTooltip }}"
|
||||
(click)="onClick()">
|
||||
|
||||
(click)="onClick()"
|
||||
>
|
||||
{{ displayText$ | async }}
|
||||
</span>
|
||||
`,
|
||||
@@ -66,25 +62,23 @@ export class NameColumnComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
|
||||
this.nodesApiService.nodeUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(node => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||
const row: ShareDataRow = this.context.row;
|
||||
if (row) {
|
||||
const { entry } = row.node;
|
||||
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
if (entry === node) {
|
||||
row.node = { entry };
|
||||
this.updateValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
this.node = this.context.row.node;
|
||||
|
||||
if (this.node && this.node.entry) {
|
||||
if (this.node?.entry) {
|
||||
const displayText = this.context.row.getValue(this.key);
|
||||
this.displayText$.next(displayText || this.node.entry.id);
|
||||
}
|
||||
|
@@ -15,71 +15,62 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
ViewEncapsulation,
|
||||
OnInit,
|
||||
Input
|
||||
} from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, ViewEncapsulation, OnInit, Input } from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-trashcan-name-column',
|
||||
template: `
|
||||
<ng-container *ngIf="!isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ node | adfNodeNameTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ displayTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-datatable-content-cell adf-trashcan-name-column' }
|
||||
selector: 'adf-trashcan-name-column',
|
||||
template: `
|
||||
<ng-container *ngIf="!isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ node | adfNodeNameTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ displayTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-datatable-content-cell adf-trashcan-name-column' }
|
||||
})
|
||||
export class TrashcanNameColumnComponent implements OnInit {
|
||||
@Input()
|
||||
context: any;
|
||||
@Input()
|
||||
context: any;
|
||||
|
||||
isLibrary = false;
|
||||
displayText: string;
|
||||
displayTooltip: string;
|
||||
node: NodeEntry;
|
||||
isLibrary = false;
|
||||
displayText: string;
|
||||
displayTooltip: string;
|
||||
node: NodeEntry;
|
||||
|
||||
ngOnInit() {
|
||||
this.node = this.context.row.node;
|
||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||
ngOnInit() {
|
||||
this.node = this.context.row.node;
|
||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||
|
||||
if (this.node && this.node.entry) {
|
||||
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
||||
if (this.node?.entry) {
|
||||
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
||||
|
||||
if (this.isLibrary) {
|
||||
const { properties } = this.node.entry;
|
||||
if (this.isLibrary) {
|
||||
const { properties } = this.node.entry;
|
||||
|
||||
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
||||
this.displayTooltip =
|
||||
properties['cm:description'] || properties['cm:title'];
|
||||
} else {
|
||||
this.displayText = this.node.entry.name || this.node.entry.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeLibraryTitle(library: any, rows: Array<ShareDataRow>): string {
|
||||
const entries = rows.map((r: ShareDataRow) => r.node.entry);
|
||||
const { id } = library;
|
||||
const title = library.properties['cm:title'];
|
||||
|
||||
let isDuplicate = false;
|
||||
|
||||
if (entries) {
|
||||
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.properties['cm:title'] === title);
|
||||
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
||||
this.displayTooltip = properties['cm:description'] || properties['cm:title'];
|
||||
} else {
|
||||
this.displayText = this.node.entry.name || this.node.entry.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isDuplicate
|
||||
? `${library.properties['cm:title']} (${library.name})`
|
||||
: `${library.properties['cm:title']}`;
|
||||
}
|
||||
makeLibraryTitle(library: any, rows: Array<ShareDataRow>): string {
|
||||
const entries = rows.map((r: ShareDataRow) => r.node.entry);
|
||||
const { id } = library;
|
||||
const title = library.properties['cm:title'];
|
||||
|
||||
let isDuplicate = false;
|
||||
|
||||
if (entries) {
|
||||
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.properties['cm:title'] === title);
|
||||
}
|
||||
|
||||
return isDuplicate ? `${library.properties['cm:title']} (${library.name})` : `${library.properties['cm:title']}`;
|
||||
}
|
||||
}
|
||||
|
@@ -95,11 +95,11 @@ export class ShareDataRow implements DataRow {
|
||||
}
|
||||
|
||||
isFile(nodeEntry: NodeEntry): boolean {
|
||||
return nodeEntry.entry && nodeEntry.entry.isFile;
|
||||
return nodeEntry.entry?.isFile;
|
||||
}
|
||||
|
||||
isFolder(nodeEntry: NodeEntry): boolean {
|
||||
return nodeEntry.entry && nodeEntry.entry.isFolder;
|
||||
return nodeEntry.entry?.isFolder;
|
||||
}
|
||||
|
||||
cacheValue(key: string, value: any): any {
|
||||
|
@@ -87,7 +87,7 @@ export class DocumentListService implements DocumentListLoader {
|
||||
*/
|
||||
getFolder(folder: string, opts?: any, includeFields: string[] = []): Observable<NodePaging> {
|
||||
let rootNodeId = ROOT_ID;
|
||||
if (opts && opts.rootFolderId) {
|
||||
if (opts?.rootFolderId) {
|
||||
rootNodeId = opts.rootFolderId;
|
||||
}
|
||||
|
||||
|
@@ -51,7 +51,7 @@ export class SearchPermissionConfigurationService implements SearchConfiguration
|
||||
|
||||
private getQuery(searchTerm: string) {
|
||||
let query: string;
|
||||
if (this.queryProvider && this.queryProvider.query) {
|
||||
if (this.queryProvider?.query) {
|
||||
query = this.queryProvider.query.replace(new RegExp(/\${([^}]+)}/g), searchTerm);
|
||||
} else {
|
||||
query = `(email:*${searchTerm}* OR firstName:*${searchTerm}* OR lastName:*${searchTerm}* OR displayName:*${searchTerm}* OR authorityName:*${searchTerm}* OR authorityDisplayName:*${searchTerm}*) AND ANAME:(\"0/APP.DEFAULT\")`;
|
||||
|
@@ -22,7 +22,6 @@ import { NodeEntry } from '@alfresco/js-api';
|
||||
name: 'adfNodeNameTooltip'
|
||||
})
|
||||
export class NodeNameTooltipPipe implements PipeTransform {
|
||||
|
||||
transform(node: NodeEntry): string {
|
||||
if (node) {
|
||||
return this.getNodeTooltip(node);
|
||||
@@ -46,18 +45,17 @@ export class NodeNameTooltipPipe implements PipeTransform {
|
||||
}
|
||||
|
||||
private getNodeTooltip(node: NodeEntry): string {
|
||||
if (!node || !node.entry) {
|
||||
if (!node?.entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { entry: { properties, name } } = node;
|
||||
const lines = [ name ];
|
||||
const {
|
||||
entry: { properties, name }
|
||||
} = node;
|
||||
const lines = [name];
|
||||
|
||||
if (properties) {
|
||||
const {
|
||||
'cm:title': title,
|
||||
'cm:description': description
|
||||
} = properties;
|
||||
const { 'cm:title': title, 'cm:description': description } = properties;
|
||||
|
||||
if (title && description) {
|
||||
lines[0] = title;
|
||||
|
@@ -16,8 +16,19 @@
|
||||
*/
|
||||
|
||||
import { AuthenticationService, ThumbnailService, SearchTextInputComponent } from '@alfresco/adf-core';
|
||||
import { Component, EventEmitter, Input, OnDestroy, Output,
|
||||
QueryList, ViewEncapsulation, ViewChild, ViewChildren, TemplateRef, ContentChild } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
QueryList,
|
||||
ViewEncapsulation,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
TemplateRef,
|
||||
ContentChild
|
||||
} from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { Subject } from 'rxjs';
|
||||
import { SearchComponent } from './search.component';
|
||||
@@ -32,7 +43,6 @@ import { EmptySearchResultComponent } from './empty-search-result.component';
|
||||
host: { class: 'adf-search-control' }
|
||||
})
|
||||
export class SearchControlComponent implements OnDestroy {
|
||||
|
||||
/** Toggles highlighting of the search term in the results. */
|
||||
@Input()
|
||||
highlight: boolean = false;
|
||||
@@ -90,15 +100,12 @@ export class SearchControlComponent implements OnDestroy {
|
||||
emptySearchTemplate: EmptySearchResultComponent;
|
||||
|
||||
focusSubject = new Subject<FocusEvent>();
|
||||
noSearchResultTemplate: TemplateRef <any> = null;
|
||||
noSearchResultTemplate: TemplateRef<any> = null;
|
||||
searchTerm: string = '';
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
public authService: AuthenticationService,
|
||||
private thumbnailService: ThumbnailService
|
||||
) {}
|
||||
constructor(public authService: AuthenticationService, private thumbnailService: ThumbnailService) {}
|
||||
|
||||
isNoSearchTemplatePresent(): boolean {
|
||||
return !!this.emptySearchTemplate;
|
||||
@@ -126,7 +133,7 @@ export class SearchControlComponent implements OnDestroy {
|
||||
getMimeType(node: NodeEntry): string {
|
||||
let mimeType: string;
|
||||
|
||||
if (node.entry.content && node.entry.content.mimeType) {
|
||||
if (node.entry.content?.mimeType) {
|
||||
mimeType = node.entry.content.mimeType;
|
||||
}
|
||||
if (node.entry.isFolder) {
|
||||
@@ -154,7 +161,7 @@ export class SearchControlComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
onSelectFirstResult() {
|
||||
if ( this.listResultElement && this.listResultElement.length > 0) {
|
||||
if (this.listResultElement && this.listResultElement.length > 0) {
|
||||
const firstElement = this.listResultElement.first as MatListItem;
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
firstElement._getHostElement().focus();
|
||||
@@ -184,7 +191,7 @@ export class SearchControlComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
private isListElement(event: any): boolean {
|
||||
return event.relatedTarget && event.relatedTarget.children[0] && event.relatedTarget.children[0].className === 'mat-list-item-content';
|
||||
return event.relatedTarget?.children[0] && event.relatedTarget.children[0].className === 'mat-list-item-content';
|
||||
}
|
||||
|
||||
private getNextElementSibling(node: Element): Element {
|
||||
|
@@ -18,12 +18,7 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
||||
import {
|
||||
MOMENT_DATE_FORMATS,
|
||||
MomentDateAdapter,
|
||||
UserPreferencesService,
|
||||
UserPreferenceValues
|
||||
} from '@alfresco/adf-core';
|
||||
import { MOMENT_DATE_FORMATS, MomentDateAdapter, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
||||
|
||||
import { SearchWidget } from '../../models/search-widget.interface';
|
||||
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
|
||||
@@ -54,7 +49,6 @@ const DEFAULT_FORMAT_DATE: string = 'DD/MM/YYYY';
|
||||
host: { class: 'adf-search-date-range' }
|
||||
})
|
||||
export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
||||
|
||||
from: UntypedFormControl;
|
||||
to: UntypedFormControl;
|
||||
|
||||
@@ -74,23 +68,28 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private dateAdapter: DateAdapter<Moment>,
|
||||
private userPreferencesService: UserPreferencesService) {
|
||||
}
|
||||
constructor(private dateAdapter: DateAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
|
||||
|
||||
getFromValidationMessage(): string {
|
||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATE' :
|
||||
this.from.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' :
|
||||
this.from.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
||||
'';
|
||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from)
|
||||
? 'SEARCH.FILTER.VALIDATION.INVALID-DATE'
|
||||
: this.from.hasError('matDatepickerMax')
|
||||
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE'
|
||||
: this.from.hasError('required')
|
||||
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||
: '';
|
||||
}
|
||||
|
||||
getToValidationMessage(): string {
|
||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATE' :
|
||||
this.to.hasError('matDatepickerMin') ? 'SEARCH.FILTER.VALIDATION.NO-DAYS' :
|
||||
this.to.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' :
|
||||
this.to.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
||||
'';
|
||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to)
|
||||
? 'SEARCH.FILTER.VALIDATION.INVALID-DATE'
|
||||
: this.to.hasError('matDatepickerMin')
|
||||
? 'SEARCH.FILTER.VALIDATION.NO-DAYS'
|
||||
: this.to.hasError('matDatepickerMax')
|
||||
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE'
|
||||
: this.to.hasError('required')
|
||||
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||
: '';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -102,13 +101,11 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
||||
this.userPreferencesService
|
||||
.select(UserPreferenceValues.Locale)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(locale => this.setLocale(locale));
|
||||
.subscribe((locale) => this.setLocale(locale));
|
||||
|
||||
const validators = Validators.compose([
|
||||
Validators.required
|
||||
]);
|
||||
const validators = Validators.compose([Validators.required]);
|
||||
|
||||
if (this.settings && this.settings.maxDate) {
|
||||
if (this.settings?.maxDate) {
|
||||
if (this.settings.maxDate === 'today') {
|
||||
this.maxDate = this.dateAdapter.today().endOf('day');
|
||||
} else {
|
||||
@@ -174,7 +171,12 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
||||
if (this.form.invalid || this.form.pristine) {
|
||||
this.displayValue$.next('');
|
||||
} else {
|
||||
this.displayValue$.next(`${this.dateAdapter.format(this.form.value.from, this.datePickerFormat)} - ${this.dateAdapter.format(this.form.value.to, this.datePickerFormat)}`);
|
||||
this.displayValue$.next(
|
||||
`${this.dateAdapter.format(this.form.value.from, this.datePickerFormat)} - ${this.dateAdapter.format(
|
||||
this.form.value.to,
|
||||
this.datePickerFormat
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,10 +221,9 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
||||
}
|
||||
|
||||
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
||||
|
||||
const inputValue = event.value;
|
||||
const formatDate = this.dateAdapter.parse(inputValue, this.datePickerFormat);
|
||||
if (formatDate && formatDate.isValid()) {
|
||||
if (formatDate?.isValid()) {
|
||||
formControl.setValue(formatDate);
|
||||
} else if (formatDate) {
|
||||
formControl.setErrors({
|
||||
@@ -247,6 +248,6 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
||||
}
|
||||
|
||||
setFromMaxDate() {
|
||||
this.fromMaxDate = (!this.to.value || this.maxDate && (moment(this.maxDate).isBefore(this.to.value))) ? this.maxDate : moment(this.to.value);
|
||||
this.fromMaxDate = !this.to.value || (this.maxDate && moment(this.maxDate).isBefore(this.to.value)) ? this.maxDate : moment(this.to.value);
|
||||
}
|
||||
}
|
||||
|
@@ -42,14 +42,11 @@ const DEFAULT_DATETIME_FORMAT: string = 'DD/MM/YYYY HH:mm';
|
||||
selector: 'adf-search-datetime-range',
|
||||
templateUrl: './search-datetime-range.component.html',
|
||||
styleUrls: ['./search-datetime-range.component.scss'],
|
||||
providers: [
|
||||
{ provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS }
|
||||
],
|
||||
providers: [{ provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS }],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-search-date-range' }
|
||||
})
|
||||
export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
||||
|
||||
from: UntypedFormControl;
|
||||
to: UntypedFormControl;
|
||||
|
||||
@@ -69,23 +66,28 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private dateAdapter: DatetimeAdapter<Moment>,
|
||||
private userPreferencesService: UserPreferencesService) {
|
||||
}
|
||||
constructor(private dateAdapter: DatetimeAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
|
||||
|
||||
getFromValidationMessage(): string {
|
||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME' :
|
||||
this.from.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME' :
|
||||
this.from.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
||||
'';
|
||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from)
|
||||
? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME'
|
||||
: this.from.hasError('matDatepickerMax')
|
||||
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME'
|
||||
: this.from.hasError('required')
|
||||
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||
: '';
|
||||
}
|
||||
|
||||
getToValidationMessage(): string {
|
||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME' :
|
||||
this.to.hasError('matDatepickerMin') ? 'SEARCH.FILTER.VALIDATION.NO-DAYS' :
|
||||
this.to.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME' :
|
||||
this.to.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
||||
'';
|
||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to)
|
||||
? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME'
|
||||
: this.to.hasError('matDatepickerMin')
|
||||
? 'SEARCH.FILTER.VALIDATION.NO-DAYS'
|
||||
: this.to.hasError('matDatepickerMax')
|
||||
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME'
|
||||
: this.to.hasError('required')
|
||||
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||
: '';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -94,13 +96,11 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
||||
this.userPreferencesService
|
||||
.select(UserPreferenceValues.Locale)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(locale => this.setLocale(locale));
|
||||
.subscribe((locale) => this.setLocale(locale));
|
||||
|
||||
const validators = Validators.compose([
|
||||
Validators.required
|
||||
]);
|
||||
const validators = Validators.compose([Validators.required]);
|
||||
|
||||
if (this.settings && this.settings.maxDatetime) {
|
||||
if (this.settings?.maxDatetime) {
|
||||
this.maxDatetime = moment(this.settings.maxDatetime);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,12 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
||||
if (this.form.invalid || this.form.pristine) {
|
||||
this.displayValue$.next('');
|
||||
} else {
|
||||
this.displayValue$.next(`${this.dateAdapter.format(this.form.value.from, this.datetimePickerFormat)} - ${this.dateAdapter.format(this.form.value.to, this.datetimePickerFormat)}`);
|
||||
this.displayValue$.next(
|
||||
`${this.dateAdapter.format(this.form.value.from, this.datetimePickerFormat)} - ${this.dateAdapter.format(
|
||||
this.form.value.to,
|
||||
this.datetimePickerFormat
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +212,9 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
||||
}
|
||||
|
||||
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
||||
|
||||
const inputValue = event.value;
|
||||
const formatDate = this.dateAdapter.parse(inputValue, this.datetimePickerFormat);
|
||||
if (formatDate && formatDate.isValid()) {
|
||||
if (formatDate?.isValid()) {
|
||||
formControl.setValue(formatDate);
|
||||
} else if (formatDate) {
|
||||
formControl.setErrors({
|
||||
@@ -235,6 +239,7 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
||||
}
|
||||
|
||||
setFromMaxDatetime() {
|
||||
this.fromMaxDatetime = (!this.to.value || this.maxDatetime && (moment(this.maxDatetime).isBefore(this.to.value))) ? this.maxDatetime : moment(this.to.value);
|
||||
this.fromMaxDatetime =
|
||||
!this.to.value || (this.maxDatetime && moment(this.maxDatetime).isBefore(this.to.value)) ? this.maxDatetime : moment(this.to.value);
|
||||
}
|
||||
}
|
||||
|
@@ -33,19 +33,19 @@ import { Subject } from 'rxjs';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchFacetFieldComponent implements FacetWidget {
|
||||
|
||||
@Input()
|
||||
field!: FacetField;
|
||||
|
||||
displayValue$: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
private searchFacetFiltersService: SearchFacetFiltersService,
|
||||
private translationService: TranslationService) {
|
||||
}
|
||||
constructor(
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
private searchFacetFiltersService: SearchFacetFiltersService,
|
||||
private translationService: TranslationService
|
||||
) {}
|
||||
|
||||
get canUpdateOnChange() {
|
||||
return this.field.settings?.allowUpdateOnChange ?? true;
|
||||
return this.field.settings?.allowUpdateOnChange ?? true;
|
||||
}
|
||||
|
||||
onToggleBucket(event: MatCheckboxChange, field: FacetField, bucket: FacetFieldBucket) {
|
||||
@@ -83,14 +83,14 @@ export class SearchFacetFieldComponent implements FacetWidget {
|
||||
}
|
||||
|
||||
canResetSelectedBuckets(field: FacetField): boolean {
|
||||
if (field && field.buckets) {
|
||||
if (field?.buckets) {
|
||||
return field.buckets.items.some((bucket) => bucket.checked);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resetSelectedBuckets(field: FacetField) {
|
||||
if (field && field.buckets) {
|
||||
if (field?.buckets) {
|
||||
for (const bucket of field.buckets.items) {
|
||||
bucket.checked = false;
|
||||
this.queryBuilder.removeUserFacetBucket(field.field, bucket);
|
||||
@@ -110,7 +110,8 @@ export class SearchFacetFieldComponent implements FacetWidget {
|
||||
if (!this.field.buckets?.items) {
|
||||
this.displayValue$.next('');
|
||||
} else {
|
||||
const displayValue = this.field.buckets?.items?.filter((item) => item.checked)
|
||||
const displayValue = this.field.buckets?.items
|
||||
?.filter((item) => item.checked)
|
||||
.map((item) => this.translationService.instant(item.display || item.label))
|
||||
.join(', ');
|
||||
this.displayValue$.next(displayValue);
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Inject, Input, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, Inject, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { SearchFacetFiltersService } from '../../services/search-facet-filters.service';
|
||||
import { SEARCH_QUERY_SERVICE_TOKEN } from '../../search-query-service.token';
|
||||
import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
|
||||
@@ -28,7 +28,7 @@ import { takeUntil } from 'rxjs/operators';
|
||||
styleUrls: ['./search-filter-chips.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchFilterChipsComponent {
|
||||
export class SearchFilterChipsComponent implements OnInit, OnDestroy {
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
/** Toggles whether to show or not the context facet filters. */
|
||||
@@ -40,12 +40,14 @@ export class SearchFilterChipsComponent {
|
||||
constructor(
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN)
|
||||
public queryBuilder: SearchQueryBuilderService,
|
||||
public facetFiltersService: SearchFacetFiltersService) {}
|
||||
public facetFiltersService: SearchFacetFiltersService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.queryBuilder.executed.asObservable()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => this.facetChipTabbedId = 'search-fact-chip-tabbed-' + this.facetFiltersService.tabbedFacet?.fields.join('-'));
|
||||
this.queryBuilder.executed
|
||||
.asObservable()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => (this.facetChipTabbedId = 'search-fact-chip-tabbed-' + this.facetFiltersService.tabbedFacet?.fields.join('-')));
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@@ -15,18 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
Output,
|
||||
OnInit,
|
||||
EventEmitter,
|
||||
ViewEncapsulation,
|
||||
ViewChild,
|
||||
Inject,
|
||||
OnDestroy,
|
||||
ElementRef
|
||||
} from '@angular/core';
|
||||
import { Component, Input, Output, OnInit, EventEmitter, ViewEncapsulation, ViewChild, Inject, OnDestroy, ElementRef } from '@angular/core';
|
||||
import { ConfigurableFocusTrapFactory, ConfigurableFocusTrap } from '@angular/cdk/a11y';
|
||||
import { DataColumn, TranslationService } from '@alfresco/adf-core';
|
||||
import { SearchWidgetContainerComponent } from '../search-widget-container/search-widget-container.component';
|
||||
@@ -44,7 +33,6 @@ import { FilterSearch } from '../../models/filter-search.interface';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchFilterContainerComponent implements OnInit, OnDestroy {
|
||||
|
||||
/** The column the filter will be applied on. */
|
||||
@Input()
|
||||
col: DataColumn;
|
||||
@@ -69,14 +57,15 @@ export class SearchFilterContainerComponent implements OnInit, OnDestroy {
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService,
|
||||
private translationService: TranslationService,
|
||||
private focusTrapFactory: ConfigurableFocusTrapFactory) {
|
||||
}
|
||||
constructor(
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService,
|
||||
private translationService: TranslationService,
|
||||
private focusTrapFactory: ConfigurableFocusTrapFactory
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.category = this.searchFilterQueryBuilder.getCategoryForColumn(this.col.key);
|
||||
this.initialValue = this.value && this.value[this.col.key] ? this.value[this.col.key] : undefined;
|
||||
this.initialValue = this.value?.[this.col.key] ? this.value[this.col.key] : undefined;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@@ -30,7 +30,6 @@ import { SearchFacetFiltersService } from '../../services/search-facet-filters.s
|
||||
host: { class: 'adf-search-filter' }
|
||||
})
|
||||
export class SearchFilterComponent {
|
||||
|
||||
/** Toggles whether to show or not the context facet filters. */
|
||||
@Input()
|
||||
showContextFacets: boolean = true;
|
||||
@@ -41,16 +40,18 @@ export class SearchFilterComponent {
|
||||
};
|
||||
displayResetButton: boolean;
|
||||
|
||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
public facetFiltersService: SearchFacetFiltersService) {
|
||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
||||
constructor(
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
public facetFiltersService: SearchFacetFiltersService
|
||||
) {
|
||||
if (queryBuilder.config?.facetQueries) {
|
||||
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
||||
this.facetExpanded['query'] = queryBuilder.config.facetQueries.expanded;
|
||||
}
|
||||
if (queryBuilder.config && queryBuilder.config.facetFields) {
|
||||
if (queryBuilder.config?.facetFields) {
|
||||
this.facetExpanded['field'] = queryBuilder.config.facetFields.expanded;
|
||||
}
|
||||
if (queryBuilder.config && queryBuilder.config.facetIntervals) {
|
||||
if (queryBuilder.config?.facetIntervals) {
|
||||
this.facetExpanded['interval'] = queryBuilder.config.facetIntervals.expanded;
|
||||
}
|
||||
this.displayResetButton = this.queryBuilder.config && !!this.queryBuilder.config.resetButton;
|
||||
|
@@ -38,7 +38,6 @@ import { Observable } from 'rxjs';
|
||||
template: '<div #content></div>'
|
||||
})
|
||||
export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
@ViewChild('content', { read: ViewContainerRef, static: true })
|
||||
content: ViewContainerRef;
|
||||
|
||||
@@ -62,8 +61,8 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
||||
constructor(
|
||||
private searchFilterService: SearchFilterService,
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private queryBuilder: BaseQueryBuilderService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver) {
|
||||
}
|
||||
private componentFactoryResolver: ComponentFactoryResolver
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
const componentType = this.searchFilterService.widgets[this.selector];
|
||||
@@ -85,9 +84,9 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
||||
}
|
||||
|
||||
private setupWidget(ref: ComponentRef<any>) {
|
||||
if (ref && ref.instance) {
|
||||
if (ref?.instance) {
|
||||
ref.instance.id = this.id;
|
||||
ref.instance.settings = {...this.settings};
|
||||
ref.instance.settings = { ...this.settings };
|
||||
ref.instance.context = this.queryBuilder;
|
||||
if (this.value) {
|
||||
ref.instance.isActive = true;
|
||||
@@ -128,7 +127,7 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
||||
}
|
||||
|
||||
resetInnerWidget() {
|
||||
if (this.componentRef && this.componentRef.instance) {
|
||||
if (this.componentRef?.instance) {
|
||||
this.componentRef.instance.reset();
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,8 @@ import {
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
OnDestroy
|
||||
OnDestroy,
|
||||
SimpleChanges
|
||||
} from '@angular/core';
|
||||
import { NodePaging, ResultSetPaging } from '@alfresco/js-api';
|
||||
import { Subject } from 'rxjs';
|
||||
@@ -45,7 +46,6 @@ import { SearchComponentInterface } from '@alfresco/adf-core';
|
||||
host: { class: 'adf-search' }
|
||||
})
|
||||
export class SearchComponent implements SearchComponentInterface, AfterContentInit, OnChanges, OnDestroy {
|
||||
|
||||
@ViewChild('panel', { static: true })
|
||||
panel: ElementRef;
|
||||
|
||||
@@ -74,8 +74,8 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||
@Input('class')
|
||||
set classList(classList: string) {
|
||||
if (classList && classList.length) {
|
||||
classList.split(' ').forEach((className) => this._classList[className.trim()] = true);
|
||||
if (classList?.length) {
|
||||
classList.split(' ').forEach((className) => (this._classList[className.trim()] = true));
|
||||
this._elementRef.nativeElement.className = '';
|
||||
}
|
||||
}
|
||||
@@ -104,31 +104,23 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
||||
_classList: { [key: string]: boolean } = {};
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private searchService: SearchService,
|
||||
private _elementRef: ElementRef) {
|
||||
this.keyPressedStream
|
||||
.pipe(
|
||||
debounceTime(200),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe(searchedWord => {
|
||||
this.loadSearchResults(searchedWord);
|
||||
});
|
||||
constructor(private searchService: SearchService, private _elementRef: ElementRef) {
|
||||
this.keyPressedStream.pipe(debounceTime(200), takeUntil(this.onDestroy$)).subscribe((searchedWord) => {
|
||||
this.loadSearchResults(searchedWord);
|
||||
});
|
||||
|
||||
searchService.dataLoaded
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(
|
||||
nodePaging => this.onSearchDataLoaded(nodePaging),
|
||||
error => this.onSearchDataError(error)
|
||||
);
|
||||
searchService.dataLoaded.pipe(takeUntil(this.onDestroy$)).subscribe(
|
||||
(nodePaging) => this.onSearchDataLoaded(nodePaging),
|
||||
(error) => this.onSearchDataError(error)
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.setVisibility();
|
||||
}
|
||||
|
||||
ngOnChanges(changes) {
|
||||
if (changes.searchTerm && changes.searchTerm.currentValue) {
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.searchTerm?.currentValue) {
|
||||
this.loadSearchResults(changes.searchTerm.currentValue);
|
||||
}
|
||||
}
|
||||
@@ -174,8 +166,8 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
||||
}
|
||||
}
|
||||
|
||||
onSearchDataError(error) {
|
||||
if (error && error.status !== 400) {
|
||||
onSearchDataError(error: { status: number }) {
|
||||
if (error?.status !== 400) {
|
||||
this.results = null;
|
||||
this.error.emit(error);
|
||||
}
|
||||
|
@@ -19,10 +19,8 @@ import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||
|
||||
export class LiveErrorStateMatcher implements ErrorStateMatcher {
|
||||
|
||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const isSubmitted = form && form.submitted;
|
||||
return !!(control && control.invalid && (control.dirty || control.touched || (!control.pristine && isSubmitted)));
|
||||
const isSubmitted = form?.submitted;
|
||||
return !!(control?.invalid && (control.dirty || control.touched || (!control.pristine && isSubmitted)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ export abstract class BaseQueryBuilderService {
|
||||
// TODO: to be supported in future iterations
|
||||
ranges: { [id: string]: SearchRange } = {};
|
||||
|
||||
constructor(protected appConfig: AppConfigService, protected alfrescoApiService: AlfrescoApiService) {
|
||||
protected constructor(protected appConfig: AppConfigService, protected alfrescoApiService: AlfrescoApiService) {
|
||||
this.resetToDefaults();
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ export abstract class BaseQueryBuilderService {
|
||||
* @returns The primary sorting definition
|
||||
*/
|
||||
getPrimarySorting(): SearchSortingDefinition {
|
||||
if (this.sorting && this.sorting.length > 0) {
|
||||
if (this.sorting?.length > 0) {
|
||||
return this.sorting[0];
|
||||
}
|
||||
return null;
|
||||
@@ -386,10 +386,7 @@ export abstract class BaseQueryBuilderService {
|
||||
* @returns Pre-configured sorting options
|
||||
*/
|
||||
getSortingOptions(): SearchSortingDefinition[] {
|
||||
if (this.config && this.config.sorting) {
|
||||
return this.config.sorting.options || [];
|
||||
}
|
||||
return [];
|
||||
return this.config?.sorting?.options || [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,7 +395,7 @@ export abstract class BaseQueryBuilderService {
|
||||
* @param query Target query
|
||||
* @returns Query group
|
||||
*/
|
||||
getQueryGroup(query) {
|
||||
getQueryGroup(query: FacetQuery): string {
|
||||
return query.group || this.config.facetQueries.label || 'Facet Queries';
|
||||
}
|
||||
|
||||
@@ -408,10 +405,7 @@ export abstract class BaseQueryBuilderService {
|
||||
* @returns True if defined, false otherwise
|
||||
*/
|
||||
get hasFacetQueries(): boolean {
|
||||
if (this.config && this.config.facetQueries && this.config.facetQueries.queries && this.config.facetQueries.queries.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this.config?.facetQueries?.queries?.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,11 +414,11 @@ export abstract class BaseQueryBuilderService {
|
||||
* @returns True if defined, false otherwise
|
||||
*/
|
||||
get hasFacetIntervals(): boolean {
|
||||
return this.config && this.config.facetIntervals && this.config.facetIntervals.intervals && this.config.facetIntervals.intervals.length > 0;
|
||||
return this.config?.facetIntervals?.intervals?.length > 0;
|
||||
}
|
||||
|
||||
get hasFacetHighlight(): boolean {
|
||||
return !!(this.config && this.config.highlight);
|
||||
return !!this.config?.highlight;
|
||||
}
|
||||
|
||||
protected get sort(): RequestSortDefinitionInner[] {
|
||||
@@ -515,9 +509,9 @@ export abstract class BaseQueryBuilderService {
|
||||
}
|
||||
|
||||
protected get facetFields(): RequestFacetFields {
|
||||
const facetFields = this.config.facetFields && this.config.facetFields.fields;
|
||||
const facetFields = this.config.facetFields?.fields;
|
||||
|
||||
if (facetFields && facetFields.length > 0) {
|
||||
if (facetFields?.length > 0) {
|
||||
return {
|
||||
facets: facetFields.map(
|
||||
(facet) =>
|
||||
|
@@ -40,7 +40,6 @@ const DEFAULT_PAGE_SIZE: number = 5;
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SearchFacetFiltersService implements OnDestroy {
|
||||
|
||||
/** All facet field items to be displayed in the component. These are updated according to the response.
|
||||
* When a new search is performed, the already existing items are updated with the new bucket count values and
|
||||
* the newly received items are added to the responseFacets.
|
||||
@@ -55,32 +54,27 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
private readonly facetQueriesPageSize = DEFAULT_PAGE_SIZE;
|
||||
private readonly onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
private searchService: SearchService,
|
||||
private translationService: TranslationService,
|
||||
private categoryService: CategoryService
|
||||
constructor(
|
||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||
private searchService: SearchService,
|
||||
private translationService: TranslationService,
|
||||
private categoryService: CategoryService
|
||||
) {
|
||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
||||
if (queryBuilder.config?.facetQueries) {
|
||||
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
|
||||
this.queryBuilder.configUpdated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.selectedBuckets = [];
|
||||
this.responseFacets = null;
|
||||
});
|
||||
this.queryBuilder.configUpdated.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||
this.selectedBuckets = [];
|
||||
this.responseFacets = null;
|
||||
});
|
||||
|
||||
this.queryBuilder.updated
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((query) => this.queryBuilder.execute(query));
|
||||
this.queryBuilder.updated.pipe(takeUntil(this.onDestroy$)).subscribe((query) => this.queryBuilder.execute(query));
|
||||
|
||||
this.queryBuilder.executed
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((resultSetPaging: ResultSetPaging) => {
|
||||
this.onDataLoaded(resultSetPaging);
|
||||
this.searchService.dataLoaded.next(resultSetPaging);
|
||||
});
|
||||
this.queryBuilder.executed.pipe(takeUntil(this.onDestroy$)).subscribe((resultSetPaging: ResultSetPaging) => {
|
||||
this.onDataLoaded(resultSetPaging);
|
||||
this.searchService.dataLoaded.next(resultSetPaging);
|
||||
});
|
||||
}
|
||||
|
||||
onDataLoaded(data: any) {
|
||||
@@ -104,17 +98,20 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
private parseFacetItems(context: ResultSetContext, configFacetFields: FacetField[], itemType: string) {
|
||||
configFacetFields.forEach((facetField) => {
|
||||
const responseField = this.findFacet(context, itemType, facetField.label);
|
||||
const responseBuckets = this.getResponseBuckets(responseField, facetField)
|
||||
.filter(this.getFilterByMinCount(facetField.mincount));
|
||||
this.sortFacetBuckets(responseBuckets, facetField.settings?.bucketSortBy, facetField.settings?.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
|
||||
const responseBuckets = this.getResponseBuckets(responseField, facetField).filter(this.getFilterByMinCount(facetField.mincount));
|
||||
this.sortFacetBuckets(
|
||||
responseBuckets,
|
||||
facetField.settings?.bucketSortBy,
|
||||
facetField.settings?.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING
|
||||
);
|
||||
const alreadyExistingField = this.findResponseFacet(itemType, facetField.label);
|
||||
|
||||
if (facetField.field === 'cm:categories'){
|
||||
if (facetField.field === 'cm:categories') {
|
||||
this.loadCategoryNames(responseBuckets);
|
||||
}
|
||||
|
||||
if (alreadyExistingField) {
|
||||
const alreadyExistingBuckets = alreadyExistingField.buckets && alreadyExistingField.buckets.items || [];
|
||||
const alreadyExistingBuckets = alreadyExistingField.buckets?.items || [];
|
||||
|
||||
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
||||
} else if (responseField) {
|
||||
@@ -166,18 +163,18 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
}
|
||||
|
||||
private parseFacetFields(context: ResultSetContext) {
|
||||
const configFacetFields = this.queryBuilder.config.facetFields && this.queryBuilder.config.facetFields.fields || [];
|
||||
const configFacetFields = this.queryBuilder.config.facetFields?.fields || [];
|
||||
this.parseFacetItems(context, configFacetFields, 'field');
|
||||
}
|
||||
|
||||
private parseFacetIntervals(context: ResultSetContext) {
|
||||
const configFacetIntervals = this.queryBuilder.config.facetIntervals && this.queryBuilder.config.facetIntervals.intervals || [];
|
||||
const configFacetIntervals = this.queryBuilder.config.facetIntervals?.intervals || [];
|
||||
this.parseFacetItems(context, configFacetIntervals, 'interval');
|
||||
}
|
||||
|
||||
private parseFacetQueries(context: ResultSetContext) {
|
||||
const facetQuerySetting = this.queryBuilder.config.facetQueries?.settings || {};
|
||||
const configFacetQueries = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.queries || [];
|
||||
const configFacetQueries = this.queryBuilder.config.facetQueries?.queries || [];
|
||||
const configGroups = configFacetQueries.reduce((acc, query) => {
|
||||
const group = this.queryBuilder.getQueryGroup(query);
|
||||
if (acc[group]) {
|
||||
@@ -188,18 +185,21 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const mincount = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.mincount;
|
||||
const mincountFilter = this.getFilterByMinCount(mincount);
|
||||
const minCount = this.queryBuilder.config.facetQueries?.mincount;
|
||||
const minCountFilter = this.getFilterByMinCount(minCount);
|
||||
|
||||
Object.keys(configGroups).forEach((group) => {
|
||||
const responseField = this.findFacet(context, 'query', group);
|
||||
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group])
|
||||
.filter(mincountFilter);
|
||||
this.sortFacetBuckets(responseBuckets, facetQuerySetting?.bucketSortBy, facetQuerySetting.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
|
||||
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group]).filter(minCountFilter);
|
||||
this.sortFacetBuckets(
|
||||
responseBuckets,
|
||||
facetQuerySetting?.bucketSortBy,
|
||||
facetQuerySetting.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING
|
||||
);
|
||||
const alreadyExistingField = this.findResponseFacet('query', group);
|
||||
|
||||
if (alreadyExistingField) {
|
||||
const alreadyExistingBuckets = alreadyExistingField.buckets && alreadyExistingField.buckets.items || [];
|
||||
const alreadyExistingBuckets = alreadyExistingField.buckets?.items || [];
|
||||
|
||||
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
||||
} else if (responseField) {
|
||||
@@ -229,8 +229,7 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
}
|
||||
|
||||
private getResponseBuckets(responseField: GenericFacetResponse, configField: FacetField): FacetFieldBucket[] {
|
||||
return ((responseField && responseField.buckets) || []).map((respBucket) => {
|
||||
|
||||
return (responseField?.buckets || []).map((respBucket) => {
|
||||
respBucket['count'] = this.getCountValue(respBucket);
|
||||
respBucket.filterQuery = respBucket.filterQuery || this.getCorrespondingFilterQuery(configField, respBucket.label);
|
||||
return {
|
||||
@@ -244,8 +243,7 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
|
||||
private getResponseQueryBuckets(responseField: GenericFacetResponse, configGroup: any): FacetFieldBucket[] {
|
||||
return (configGroup || []).map((query) => {
|
||||
const respBucket = ((responseField && responseField.buckets) || [])
|
||||
.find((bucket) => bucket.label === query.label) || {};
|
||||
const respBucket = (responseField?.buckets || []).find((bucket) => bucket.label === query.label) || {};
|
||||
|
||||
respBucket['count'] = this.getCountValue(respBucket);
|
||||
return {
|
||||
@@ -261,7 +259,9 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
switch (sortBy) {
|
||||
case FacetBucketSortBy.LABEL:
|
||||
buckets.sort((bucket1, bucket2) =>
|
||||
sortDirection === FacetBucketSortDirection.ASCENDING ? bucket1.label.localeCompare(bucket2.label) : bucket2.label.localeCompare(bucket1.label)
|
||||
sortDirection === FacetBucketSortDirection.ASCENDING
|
||||
? bucket1.label.localeCompare(bucket2.label)
|
||||
: bucket2.label.localeCompare(bucket1.label)
|
||||
);
|
||||
break;
|
||||
case FacetBucketSortBy.COUNT:
|
||||
@@ -282,28 +282,26 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
return bucket.count === null ? '' : `(${bucket.count})`;
|
||||
}
|
||||
|
||||
private getFilterByMinCount(mincountInput: number) {
|
||||
return (bucket) => {
|
||||
let mincount = mincountInput;
|
||||
if (mincount === undefined) {
|
||||
mincount = 1;
|
||||
private getFilterByMinCount =
|
||||
(minCountInput: number) =>
|
||||
(bucket: FacetFieldBucket): boolean => {
|
||||
let minCount = minCountInput;
|
||||
if (minCount === undefined) {
|
||||
minCount = 1;
|
||||
}
|
||||
return bucket.count >= mincount;
|
||||
return bucket.count >= minCount;
|
||||
};
|
||||
}
|
||||
|
||||
private getCorrespondingFilterQuery(configFacetItem: FacetField, bucketLabel: string): string {
|
||||
let filterQuery = null;
|
||||
|
||||
if (configFacetItem.field && bucketLabel) {
|
||||
|
||||
if (configFacetItem.sets) {
|
||||
const configSet = configFacetItem.sets.find((set) => bucketLabel === set.label);
|
||||
|
||||
if (configSet) {
|
||||
filterQuery = this.buildIntervalQuery(configFacetItem.field, configSet);
|
||||
}
|
||||
|
||||
} else {
|
||||
filterQuery = `${configFacetItem.field}:"${bucketLabel}"`;
|
||||
}
|
||||
@@ -315,8 +313,8 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
private buildIntervalQuery(fieldName: string, interval: any): string {
|
||||
const start = interval.start;
|
||||
const end = interval.end;
|
||||
const startLimit = (interval.startInclusive === undefined || interval.startInclusive === true) ? '[' : '<';
|
||||
const endLimit = (interval.endInclusive === undefined || interval.endInclusive === true) ? ']' : '>';
|
||||
const startLimit = interval.startInclusive === undefined || interval.startInclusive === true ? '[' : '<';
|
||||
const endLimit = interval.endInclusive === undefined || interval.endInclusive === true ? ']' : '>';
|
||||
|
||||
return `${fieldName}:${startLimit}"${start}" TO "${end}"${endLimit}`;
|
||||
}
|
||||
@@ -329,22 +327,27 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
return (this.responseFacets || []).find((response) => response.type === itemType && response.label === fieldLabel);
|
||||
}
|
||||
|
||||
private updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets) {
|
||||
private updateExistingBuckets(
|
||||
responseField: GenericFacetResponse,
|
||||
responseBuckets: FacetFieldBucket[],
|
||||
alreadyExistingField: FacetField,
|
||||
alreadyExistingBuckets: FacetFieldBucket[]
|
||||
) {
|
||||
const bucketsToDelete = [];
|
||||
|
||||
alreadyExistingBuckets
|
||||
.map((bucket) => {
|
||||
const responseBucket = ((responseField && responseField.buckets) || []).find((respBucket) => respBucket.label === bucket.label);
|
||||
alreadyExistingBuckets.forEach((bucket) => {
|
||||
const responseBucket = (responseField?.buckets || []).find((respBucket) => respBucket.label === bucket.label);
|
||||
|
||||
if (!responseBucket) {
|
||||
bucketsToDelete.push(bucket);
|
||||
}
|
||||
bucket.count = this.getCountValue(responseBucket);
|
||||
return bucket;
|
||||
});
|
||||
if (!responseBucket) {
|
||||
bucketsToDelete.push(bucket);
|
||||
}
|
||||
bucket.count = this.getCountValue(responseBucket);
|
||||
return bucket;
|
||||
});
|
||||
|
||||
const hasSelection = this.selectedBuckets
|
||||
.find((selBuckets) => alreadyExistingField.label === selBuckets.field.label && alreadyExistingField.type === selBuckets.field.type);
|
||||
const hasSelection = !!this.selectedBuckets.find(
|
||||
(selBuckets) => alreadyExistingField.label === selBuckets.field.label && alreadyExistingField.type === selBuckets.field.type
|
||||
);
|
||||
|
||||
if (!hasSelection && bucketsToDelete.length) {
|
||||
bucketsToDelete.forEach((bucket) => {
|
||||
@@ -361,8 +364,9 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private getBucketFilterFunction(bucketList) {
|
||||
return (bucket: FacetFieldBucket): boolean => {
|
||||
private getBucketFilterFunction =
|
||||
(bucketList: SearchFilterList<FacetFieldBucket>) =>
|
||||
(bucket: FacetFieldBucket): boolean => {
|
||||
if (bucket && bucketList.filterText) {
|
||||
const pattern = (bucketList.filterText || '').toLowerCase();
|
||||
const label = (this.translationService.instant(bucket.display) || this.translationService.instant(bucket.label)).toLowerCase();
|
||||
@@ -370,21 +374,19 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private loadCategoryNames(bucketList: FacetFieldBucket[]) {
|
||||
bucketList.forEach((item) => {
|
||||
const categoryId = item.label.split('/').pop();
|
||||
this.categoryService.getCategory(categoryId, {include: ['path']})
|
||||
.pipe(catchError(error => throwError(error)))
|
||||
.subscribe(
|
||||
category => {
|
||||
const nextAfterGeneralPathPartIndex = 3;
|
||||
const pathSeparator = '/';
|
||||
const path = category.entry.path.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
||||
item.display = path ? `${path}/${category.entry.name}` : category.entry.name;
|
||||
}
|
||||
);
|
||||
this.categoryService
|
||||
.getCategory(categoryId, { include: ['path'] })
|
||||
.pipe(catchError((error) => throwError(error)))
|
||||
.subscribe((category) => {
|
||||
const nextAfterGeneralPathPartIndex = 3;
|
||||
const pathSeparator = '/';
|
||||
const path = category.entry.path.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
||||
item.display = path ? `${path}/${category.entry.name}` : category.entry.name;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -401,14 +403,15 @@ export class SearchFacetFiltersService implements OnDestroy {
|
||||
updateSelectedBuckets() {
|
||||
if (this.responseFacets) {
|
||||
this.selectedBuckets = [];
|
||||
let facetFields = this.tabbedFacet === null ? [] : Object.keys(this.tabbedFacet?.fields).map(field => this.tabbedFacet.facets[field]);
|
||||
let facetFields = this.tabbedFacet === null ? [] : Object.keys(this.tabbedFacet?.fields).map((field) => this.tabbedFacet.facets[field]);
|
||||
facetFields = [...facetFields, ...this.responseFacets];
|
||||
for (const facetField of facetFields) {
|
||||
if (facetField?.buckets) {
|
||||
this.selectedBuckets.push(
|
||||
...this.queryBuilder.getUserFacetBuckets(facetField.field)
|
||||
...this.queryBuilder
|
||||
.getUserFacetBuckets(facetField.field)
|
||||
.filter((bucket) => bucket.checked)
|
||||
.map((bucket) => ({field: facetField, bucket}))
|
||||
.map((bucket) => ({ field: facetField, bucket }))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -19,8 +19,8 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } fro
|
||||
import { LogService, InfiniteSelectScrollDirective, AuthenticationService } from '@alfresco/adf-core';
|
||||
import { SitePaging, SiteEntry, Site } from '@alfresco/js-api';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import {LiveAnnouncer} from '@angular/cdk/a11y';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import { LiveAnnouncer } from '@angular/cdk/a11y';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SitesService } from '../common/services/sites.service';
|
||||
|
||||
/* eslint-disable no-shadow */
|
||||
@@ -39,7 +39,6 @@ export enum Relations {
|
||||
host: { class: 'adf-sites-dropdown' }
|
||||
})
|
||||
export class DropdownSitesComponent implements OnInit {
|
||||
|
||||
/** Hide the "My Files" option. */
|
||||
@Input()
|
||||
hideMyFiles: boolean = false;
|
||||
@@ -81,12 +80,13 @@ export class DropdownSitesComponent implements OnInit {
|
||||
selected: SiteEntry = null;
|
||||
MY_FILES_VALUE = '-my-';
|
||||
|
||||
constructor(private authService: AuthenticationService,
|
||||
private sitesService: SitesService,
|
||||
private logService: LogService,
|
||||
private liveAnnouncer: LiveAnnouncer,
|
||||
private translateService: TranslateService) {
|
||||
}
|
||||
constructor(
|
||||
private authService: AuthenticationService,
|
||||
private sitesService: SitesService,
|
||||
private logService: LogService,
|
||||
private liveAnnouncer: LiveAnnouncer,
|
||||
private translateService: TranslateService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.siteList) {
|
||||
@@ -102,10 +102,12 @@ export class DropdownSitesComponent implements OnInit {
|
||||
}
|
||||
|
||||
selectedSite(event: MatSelectChange) {
|
||||
this.liveAnnouncer.announce(this.translateService.instant('ADF_DROPDOWN.SELECTION_ARIA_LABEL', {
|
||||
placeholder: this.translateService.instant(this.placeholder),
|
||||
selectedOption: this.translateService.instant(event.value.entry.title)
|
||||
}));
|
||||
this.liveAnnouncer.announce(
|
||||
this.translateService.instant('ADF_DROPDOWN.SELECTION_ARIA_LABEL', {
|
||||
placeholder: this.translateService.instant(this.placeholder),
|
||||
selectedOption: this.translateService.instant(event.value.entry.title)
|
||||
})
|
||||
);
|
||||
this.change.emit(event.value);
|
||||
}
|
||||
|
||||
@@ -121,8 +123,8 @@ export class DropdownSitesComponent implements OnInit {
|
||||
extendedOptions.relations = [this.relations];
|
||||
}
|
||||
|
||||
this.sitesService.getSites(extendedOptions).subscribe((sitePaging: SitePaging) => {
|
||||
|
||||
this.sitesService.getSites(extendedOptions).subscribe(
|
||||
(sitePaging: SitePaging) => {
|
||||
if (!this.siteList) {
|
||||
this.siteList = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
||||
|
||||
@@ -137,7 +139,6 @@ export class DropdownSitesComponent implements OnInit {
|
||||
this.value = this.MY_FILES_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const siteList: SitePaging = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
||||
|
||||
@@ -155,7 +156,8 @@ export class DropdownSitesComponent implements OnInit {
|
||||
},
|
||||
(error) => {
|
||||
this.logService.error(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
showLoading(): boolean {
|
||||
@@ -167,7 +169,7 @@ export class DropdownSitesComponent implements OnInit {
|
||||
}
|
||||
|
||||
private siteListHasMoreItems(): boolean {
|
||||
return this.siteList && this.siteList.list.pagination && this.siteList.list.pagination.hasMoreItems;
|
||||
return this.siteList?.list.pagination?.hasMoreItems;
|
||||
}
|
||||
|
||||
private filteredResultsByMember(sites: SitePaging): SitePaging {
|
||||
@@ -177,7 +179,9 @@ export class DropdownSitesComponent implements OnInit {
|
||||
}
|
||||
|
||||
private isCurrentUserMember(site: SiteEntry, loggedUserName: string): boolean {
|
||||
return site.entry.visibility === 'PUBLIC' ||
|
||||
!!site.relations.members.list.entries.find((member) => member.entry.id.toLowerCase() === loggedUserName.toLowerCase());
|
||||
return (
|
||||
site.entry.visibility === 'PUBLIC' ||
|
||||
!!site.relations.members.list.entries.find((member) => member.entry.id.toLowerCase() === loggedUserName.toLowerCase())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -27,9 +27,7 @@ import { NodeEntry } from '@alfresco/js-api';
|
||||
templateUrl: './tree-view.component.html',
|
||||
styleUrls: ['./tree-view.component.scss']
|
||||
})
|
||||
|
||||
export class TreeViewComponent implements OnChanges {
|
||||
|
||||
/** Identifier of the node to display. */
|
||||
@Input()
|
||||
nodeId: string;
|
||||
@@ -51,8 +49,7 @@ export class TreeViewComponent implements OnChanges {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['nodeId'] && changes['nodeId'].currentValue &&
|
||||
changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
||||
if (changes['nodeId']?.currentValue && changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
||||
this.loadTreeNode();
|
||||
} else {
|
||||
this.dataSource.data = [];
|
||||
@@ -70,12 +67,11 @@ export class TreeViewComponent implements OnChanges {
|
||||
hasChild = (_: number, nodeData: TreeBaseNode) => nodeData.expandable;
|
||||
|
||||
private loadTreeNode() {
|
||||
this.treeViewService.getTreeNodes(this.nodeId)
|
||||
.subscribe(
|
||||
(treeNode: TreeBaseNode[]) => {
|
||||
this.dataSource.data = treeNode;
|
||||
},
|
||||
(error) => this.error.emit(error)
|
||||
);
|
||||
this.treeViewService.getTreeNodes(this.nodeId).subscribe(
|
||||
(treeNode: TreeBaseNode[]) => {
|
||||
this.dataSource.data = treeNode;
|
||||
},
|
||||
(error) => this.error.emit(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import { TreeNode } from '../models/tree-node.interface';
|
||||
import { TreeResponse } from '../models/tree-response.interface';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
||||
export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
||||
public readonly treeControl: FlatTreeControl<T>;
|
||||
public treeNodesSource = new BehaviorSubject<T[]>([]);
|
||||
|
||||
@@ -38,7 +38,10 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.treeControl = new FlatTreeControl<T>(node => node.level, node => node.hasChildren);
|
||||
this.treeControl = new FlatTreeControl<T>(
|
||||
(node) => node.level,
|
||||
(node) => node.hasChildren
|
||||
);
|
||||
this.treeNodes = [];
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
||||
* @param nodeToCollapse Node to be collapsed
|
||||
*/
|
||||
public collapseNode(nodeToCollapse: T): void {
|
||||
if (nodeToCollapse != null && nodeToCollapse.hasChildren) {
|
||||
if (nodeToCollapse?.hasChildren) {
|
||||
this.treeControl.collapse(nodeToCollapse);
|
||||
const children: T[] = this.treeNodes.filter((node: T) => nodeToCollapse.id === node.parentId);
|
||||
children.forEach((child: T) => {
|
||||
@@ -142,9 +145,7 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
||||
const index: number = this.treeNodes.indexOf(nodeToCollapse);
|
||||
this.treeNodes.splice(index, 1);
|
||||
if (nodeToCollapse.hasChildren) {
|
||||
this.treeNodes
|
||||
.filter((node: T) => nodeToCollapse.id === node.parentId)
|
||||
.forEach((child: T) => this.collapseInnerNode(child));
|
||||
this.treeNodes.filter((node: T) => nodeToCollapse.id === node.parentId).forEach((child: T) => this.collapseInnerNode(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -36,9 +36,11 @@ export class FileUploadingListRowComponent {
|
||||
}
|
||||
|
||||
showCancelledStatus(): boolean {
|
||||
return this.file.status === FileUploadStatus.Cancelled ||
|
||||
return (
|
||||
this.file.status === FileUploadStatus.Cancelled ||
|
||||
this.file.status === FileUploadStatus.Aborted ||
|
||||
this.file.status === FileUploadStatus.Deleted;
|
||||
this.file.status === FileUploadStatus.Deleted
|
||||
);
|
||||
}
|
||||
|
||||
get versionNumber(): string {
|
||||
@@ -46,29 +48,19 @@ export class FileUploadingListRowComponent {
|
||||
}
|
||||
|
||||
get mimeType(): string {
|
||||
if (this.file && this.file.file && this.file.file.type) {
|
||||
return this.file.file.type;
|
||||
}
|
||||
|
||||
return 'default';
|
||||
return this.file?.file?.type || 'default';
|
||||
}
|
||||
|
||||
isUploadVersion(): boolean {
|
||||
return (
|
||||
!!this.file.data &&
|
||||
this.file.options &&
|
||||
this.file.options.newVersion &&
|
||||
this.file.data.entry.properties &&
|
||||
this.file.data.entry.properties['cm:versionLabel']
|
||||
);
|
||||
return !!this.file.data && this.file.options?.newVersion && this.file.data.entry.properties?.['cm:versionLabel'];
|
||||
}
|
||||
|
||||
canCancelUpload(): boolean {
|
||||
return this.file && this.file.status === FileUploadStatus.Pending;
|
||||
return this.file?.status === FileUploadStatus.Pending;
|
||||
}
|
||||
|
||||
isUploadError(): boolean {
|
||||
return this.file && this.file.status === FileUploadStatus.Error;
|
||||
return this.file?.status === FileUploadStatus.Error;
|
||||
}
|
||||
|
||||
isUploading(): boolean {
|
||||
@@ -76,10 +68,10 @@ export class FileUploadingListRowComponent {
|
||||
}
|
||||
|
||||
isUploadComplete(): boolean {
|
||||
return this.file.status === FileUploadStatus.Complete && !this.isUploadVersion();
|
||||
return this.file?.status === FileUploadStatus.Complete && !this.isUploadVersion();
|
||||
}
|
||||
|
||||
isUploadVersionComplete(): boolean {
|
||||
return this.file && (this.file.status === FileUploadStatus.Complete && this.isUploadVersion());
|
||||
return this.file?.status === FileUploadStatus.Complete && this.isUploadVersion();
|
||||
}
|
||||
}
|
||||
|
@@ -16,10 +16,7 @@
|
||||
*/
|
||||
|
||||
import { EXTENDIBLE_COMPONENT, FileUtils, LogService } from '@alfresco/adf-core';
|
||||
import {
|
||||
Component, EventEmitter, forwardRef, Input,
|
||||
OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation, inject
|
||||
} from '@angular/core';
|
||||
import { Component, EventEmitter, forwardRef, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation, inject } from '@angular/core';
|
||||
import { NodesApiService } from '../../common/services/nodes-api.service';
|
||||
import { ContentService } from '../../common/services/content.service';
|
||||
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
||||
@@ -33,9 +30,7 @@ import { NodeAllowableOperationSubject } from '../../interfaces/node-allowable-o
|
||||
selector: 'adf-upload-button',
|
||||
templateUrl: './upload-button.component.html',
|
||||
styleUrls: ['./upload-button.component.scss'],
|
||||
viewProviders: [
|
||||
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }
|
||||
],
|
||||
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class UploadButtonComponent extends UploadBase implements OnInit, OnChanges, NodeAllowableOperationSubject {
|
||||
@@ -78,7 +73,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
const rootFolderId = changes['rootFolderId'];
|
||||
if (rootFolderId && rootFolderId.currentValue) {
|
||||
if (rootFolderId?.currentValue) {
|
||||
this.checkPermission();
|
||||
}
|
||||
}
|
||||
@@ -88,7 +83,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
||||
}
|
||||
|
||||
onFilesAdded($event: any): void {
|
||||
const files: File[] = FileUtils.toFileArray($event.currentTarget.files);
|
||||
const files = FileUtils.toFileArray($event.currentTarget.files);
|
||||
|
||||
if (this.hasAllowableOperations) {
|
||||
this.uploadFiles(files);
|
||||
@@ -101,7 +96,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
||||
|
||||
onClickUploadButton(): void {
|
||||
if (this.file) {
|
||||
const files: File[] = [this.file];
|
||||
const files = [this.file];
|
||||
|
||||
if (this.hasAllowableOperations) {
|
||||
this.uploadFiles(files);
|
||||
@@ -113,7 +108,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
||||
|
||||
onDirectoryAdded($event: any): void {
|
||||
if (this.hasAllowableOperations) {
|
||||
const files: File[] = FileUtils.toFileArray($event.currentTarget.files);
|
||||
const files = FileUtils.toFileArray($event.currentTarget.files);
|
||||
this.uploadFiles(files);
|
||||
} else {
|
||||
this.permissionEvent.emit(new PermissionModel({ type: 'content', action: 'upload', permission: 'create' }));
|
||||
@@ -132,10 +127,10 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
||||
this.nodesApiService.getNode(this.rootFolderId, opts).subscribe(
|
||||
(res) => this.permissionValue.next(this.nodeHasPermission(res, AllowableOperationsEnum.CREATE)),
|
||||
(error: { error: Error }) => {
|
||||
if (error && error.error) {
|
||||
if (error?.error) {
|
||||
this.error.emit({ error: error.error.message } as any);
|
||||
} else {
|
||||
this.error.emit({ error: 'FILE_UPLOAD.BUTTON.PERMISSION_CHECK_ERROR'} as any);
|
||||
this.error.emit({ error: 'FILE_UPLOAD.BUTTON.PERMISSION_CHECK_ERROR' } as any);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@@ -22,15 +22,14 @@ import { UploadBase } from './base-upload/upload-base';
|
||||
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
||||
import { ContentService } from '../../common/services/content.service';
|
||||
import { FileModel } from '../../common/models/file.model';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-upload-drag-area',
|
||||
templateUrl: './upload-drag-area.component.html',
|
||||
styleUrls: ['./upload-drag-area.component.scss'],
|
||||
host: { class: 'adf-upload-drag-area' },
|
||||
viewProviders: [
|
||||
{provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent)}
|
||||
],
|
||||
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent) }],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class UploadDragAreaComponent extends UploadBase implements NodeAllowableOperationSubject {
|
||||
@@ -70,9 +69,12 @@ export class UploadDragAreaComponent extends UploadBase implements NodeAllowable
|
||||
const messageTranslate = this.translationService.instant('FILE_UPLOAD.MESSAGES.PROGRESS');
|
||||
const actionTranslate = this.translationService.instant('FILE_UPLOAD.ACTION.UNDO');
|
||||
|
||||
this.notificationService.openSnackMessageAction(messageTranslate, actionTranslate).onAction().subscribe(() => {
|
||||
this.uploadService.cancelUpload(...latestFilesAdded);
|
||||
});
|
||||
this.notificationService
|
||||
.openSnackMessageAction(messageTranslate, actionTranslate)
|
||||
.onAction()
|
||||
.subscribe(() => {
|
||||
this.uploadService.cancelUpload(...latestFilesAdded);
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns true or false considering the component options and node permissions */
|
||||
@@ -88,27 +90,29 @@ export class UploadDragAreaComponent extends UploadBase implements NodeAllowable
|
||||
onUploadFiles(event: CustomEvent) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const isAllowed: boolean = this.isTargetNodeFolder(event) ?
|
||||
this.contentService.hasAllowableOperations(event.detail.data.obj.entry, AllowableOperationsEnum.CREATE)
|
||||
: this.contentService.hasAllowableOperations(event.detail.data.obj.entry, AllowableOperationsEnum.UPDATE);
|
||||
|
||||
const node: Node = event.detail.data.obj.entry;
|
||||
const files: FileInfo[] = event.detail?.files || [];
|
||||
|
||||
const isAllowed: boolean = this.isTargetNodeFolder(node)
|
||||
? this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.CREATE)
|
||||
: this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATE);
|
||||
|
||||
if (isAllowed) {
|
||||
if (!this.isTargetNodeFolder(event) && event.detail.files.length === 1) {
|
||||
if (!this.isTargetNodeFolder(node) && files.length === 1) {
|
||||
this.updateFileVersion.emit(event);
|
||||
} else {
|
||||
const fileInfo: FileInfo[] = event.detail.files;
|
||||
if (this.isTargetNodeFolder(event)) {
|
||||
const destinationFolderName = event.detail.data.obj.entry.name;
|
||||
fileInfo.map((file) => file.relativeFolder = destinationFolderName ? destinationFolderName.concat(file.relativeFolder) : file.relativeFolder);
|
||||
if (this.isTargetNodeFolder(node)) {
|
||||
files.forEach((file) => (file.relativeFolder = node.name ? node.name.concat(file.relativeFolder) : file.relativeFolder));
|
||||
}
|
||||
if (fileInfo && fileInfo.length > 0) {
|
||||
this.uploadFilesInfo(fileInfo);
|
||||
if (files?.length > 0) {
|
||||
this.uploadFilesInfo(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isTargetNodeFolder(event: CustomEvent): boolean {
|
||||
return event.detail.data.obj && event.detail.data.obj.entry.isFolder;
|
||||
private isTargetNodeFolder(node: Node): boolean {
|
||||
return !!node?.isFolder;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -42,17 +42,7 @@ import {
|
||||
ViewUtilService
|
||||
} from '@alfresco/adf-core';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
ContentApi,
|
||||
Node,
|
||||
NodeEntry,
|
||||
NodesApi,
|
||||
RenditionEntry,
|
||||
SharedlinksApi,
|
||||
Version,
|
||||
VersionEntry,
|
||||
VersionsApi
|
||||
} from '@alfresco/js-api';
|
||||
import { ContentApi, Node, NodeEntry, NodesApi, RenditionEntry, SharedlinksApi, Version, VersionEntry, VersionsApi } from '@alfresco/js-api';
|
||||
import { RenditionService } from '../../common/services/rendition.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
@@ -66,12 +56,11 @@ import { NodeActionsService } from '../../document-list';
|
||||
selector: 'adf-alfresco-viewer',
|
||||
templateUrl: './alfresco-viewer.component.html',
|
||||
styleUrls: ['./alfresco-viewer.component.scss'],
|
||||
host: {class: 'adf-alfresco-viewer'},
|
||||
host: { class: 'adf-alfresco-viewer' },
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
providers: [ViewUtilService]
|
||||
})
|
||||
export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
|
||||
@ViewChild('adfViewer')
|
||||
adfViewer: ViewerComponent<{ node: Node }>;
|
||||
|
||||
@@ -204,8 +193,8 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
tracks: Track[] = [];
|
||||
readOnly: boolean = true;
|
||||
|
||||
sidebarRightTemplateContext: { node: Node } = {node: null};
|
||||
sidebarLeftTemplateContext: { node: Node } = {node: null};
|
||||
sidebarRightTemplateContext: { node: Node } = { node: null };
|
||||
sidebarLeftTemplateContext: { node: Node } = { node: null };
|
||||
|
||||
_sharedLinksApi: SharedlinksApi;
|
||||
get sharedLinksApi(): SharedlinksApi {
|
||||
@@ -231,27 +220,33 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
return this._contentApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private nodesApiService: NodesApiService,
|
||||
private renditionService: RenditionService,
|
||||
private viewUtilService: ViewUtilService,
|
||||
private logService: LogService,
|
||||
private contentService: ContentService,
|
||||
private uploadService: UploadService,
|
||||
public dialog: MatDialog,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private nodeActionsService: NodeActionsService) {
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private nodesApiService: NodesApiService,
|
||||
private renditionService: RenditionService,
|
||||
private viewUtilService: ViewUtilService,
|
||||
private logService: LogService,
|
||||
private contentService: ContentService,
|
||||
private uploadService: UploadService,
|
||||
public dialog: MatDialog,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private nodeActionsService: NodeActionsService
|
||||
) {
|
||||
renditionService.maxRetries = this.maxRetries;
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.nodesApiService.nodeUpdated.pipe(
|
||||
filter((node) => node && node.id === this.nodeId &&
|
||||
(node.name !== this.fileName ||
|
||||
this.getNodeVersionProperty(this.nodeEntry.entry) !== this.getNodeVersionProperty(node))),
|
||||
takeUntil(this.onDestroy$)
|
||||
).subscribe((node) => this.onNodeUpdated(node));
|
||||
this.nodesApiService.nodeUpdated
|
||||
.pipe(
|
||||
filter(
|
||||
(node) =>
|
||||
node &&
|
||||
node.id === this.nodeId &&
|
||||
(node.name !== this.fileName || this.getNodeVersionProperty(this.nodeEntry.entry) !== this.getNodeVersionProperty(node))
|
||||
),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe((node) => this.onNodeUpdated(node));
|
||||
}
|
||||
|
||||
private async onNodeUpdated(node: Node) {
|
||||
@@ -282,7 +277,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
|
||||
private async setupNode() {
|
||||
try {
|
||||
this.nodeEntry = await this.nodesApi.getNode(this.nodeId, {include: ['allowableOperations']});
|
||||
this.nodeEntry = await this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] });
|
||||
if (this.versionId) {
|
||||
this.versionEntry = await this.versionsApi.getVersion(this.nodeId, this.versionId);
|
||||
await this.setUpNodeFile(this.nodeEntry.entry, this.versionEntry.entry);
|
||||
@@ -297,24 +292,24 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> {
|
||||
|
||||
this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
|
||||
let mimeType;
|
||||
let urlFileContent;
|
||||
let mimeType: string;
|
||||
let urlFileContent: string;
|
||||
|
||||
if (versionData && versionData.content) {
|
||||
if (versionData?.content) {
|
||||
mimeType = versionData.content.mimeType;
|
||||
} else if (nodeData.content) {
|
||||
mimeType = nodeData.content.mimeType;
|
||||
}
|
||||
|
||||
const currentFileVersion = this.nodeEntry?.entry?.properties && this.nodeEntry.entry.properties['cm:versionLabel'] ?
|
||||
encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel']) : encodeURI('1.0');
|
||||
const currentFileVersion = this.nodeEntry?.entry?.properties?.['cm:versionLabel']
|
||||
? encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel'])
|
||||
: encodeURI('1.0');
|
||||
|
||||
urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) :
|
||||
this.contentApi.getContentUrl(this.nodeId);
|
||||
urlFileContent = this.cacheBusterNumber ? urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber :
|
||||
urlFileContent + '&' + currentFileVersion;
|
||||
urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) : this.contentApi.getContentUrl(this.nodeId);
|
||||
urlFileContent = this.cacheBusterNumber
|
||||
? urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber
|
||||
: urlFileContent + '&' + currentFileVersion;
|
||||
|
||||
const fileExtension = this.viewUtilService.getFileExtension(versionData ? versionData.name : nodeData.name);
|
||||
this.fileName = versionData ? versionData.name : nodeData.name;
|
||||
@@ -349,10 +344,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
const viewerType = this.viewUtilService.getViewerType(fileExtension, mimeType);
|
||||
|
||||
if (viewerType === 'unknown') {
|
||||
({
|
||||
url: urlFileContent,
|
||||
mimeType
|
||||
} = await this.getSharedLinkRendition(this.sharedLinkId));
|
||||
({ url: urlFileContent, mimeType } = await this.getSharedLinkRendition(this.sharedLinkId));
|
||||
}
|
||||
this.mimeType = mimeType;
|
||||
this.urlFileContent = urlFileContent;
|
||||
@@ -363,7 +355,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf');
|
||||
if (rendition.entry.status.toString() === 'CREATED') {
|
||||
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
|
||||
return {url: urlFileContent, mimeType: 'application/pdf'};
|
||||
return { url: urlFileContent, mimeType: 'application/pdf' };
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
@@ -371,8 +363,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
|
||||
if (rendition.entry.status.toString() === 'CREATED') {
|
||||
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
|
||||
return {url: urlFileContent, mimeType: 'image/png'};
|
||||
|
||||
return { url: urlFileContent, mimeType: 'image/png' };
|
||||
}
|
||||
} catch (renditionError) {
|
||||
this.logService.error(renditionError);
|
||||
@@ -404,7 +395,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
|
||||
onSubmitFile(newImageBlob: Blob) {
|
||||
if (this?.nodeEntry?.entry?.id && !this.readOnly) {
|
||||
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, {type: this?.nodeEntry?.entry?.content?.mimeType});
|
||||
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, { type: this?.nodeEntry?.entry?.content?.mimeType });
|
||||
const newFile = new FileModel(
|
||||
newImageFile,
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"paths": {
|
||||
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
||||
|
Reference in New Issue
Block a user