mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ADF-5378] Rotate image: auto increment version on submit (#2099)
* add cropperjs dependency * remove unnecesary dependencies * misstype * misstype * update core package & added testing * change with latest typos * update tests & integrate jasmine-marbles
This commit is contained in:
parent
dc63d68810
commit
422f8bc986
@ -94,6 +94,7 @@
|
||||
"styles": [
|
||||
"src/assets/fonts/material-icons/material-icons.css",
|
||||
"src/assets/fonts/muli/muli.css",
|
||||
"node_modules/cropperjs/dist/cropper.min.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": [
|
||||
|
15
package-lock.json
generated
15
package-lock.json
generated
@ -38,9 +38,9 @@
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-core": {
|
||||
"version": "4.4.0-32262",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-4.4.0-32262.tgz",
|
||||
"integrity": "sha512-CXOaGnRbPMliRcTNUeztNc4Bc0zHWdQ2vp1JucplMQY6vaDrmKXBXasFTunA9y3v0WR/YHTqDCP2r+5y5LYZTg==",
|
||||
"version": "4.4.0-32367",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-4.4.0-32367.tgz",
|
||||
"integrity": "sha512-SWyrLWyaoosCyZycSkw6mfysVdAYARGQrHIqcYM1AnfmXyqz/evW9x+88/IG/Pyh/iL/vfgutkUTf3ZTxjsBhA==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
@ -8806,6 +8806,15 @@
|
||||
"integrity": "sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"jasmine-marbles": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/jasmine-marbles/-/jasmine-marbles-0.6.0.tgz",
|
||||
"integrity": "sha512-1uzgjEesEeCb+r+v46qn5x326TiGqk5SUZa+A3O+XnMCjG/pGcUOhL9Xsg5L7gLC6RFHyWGTkB5fei4rcvIOiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.5.0"
|
||||
}
|
||||
},
|
||||
"jasmine-spec-reporter": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-6.0.0.tgz",
|
||||
|
@ -25,7 +25,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@alfresco/adf-content-services": "4.4.0-32262",
|
||||
"@alfresco/adf-core": "4.4.0-32262",
|
||||
"@alfresco/adf-core": "4.4.0-32367",
|
||||
"@alfresco/adf-extensions": "4.4.0-32262",
|
||||
"@alfresco/js-api": "4.4.0-3371",
|
||||
"@angular/animations": "10.0.4",
|
||||
@ -85,6 +85,7 @@
|
||||
"husky": "^5.1.1",
|
||||
"inquirer": "^7.3.3",
|
||||
"jasmine-core": "~3.7.1",
|
||||
"jasmine-marbles": "0.6.0",
|
||||
"jasmine-spec-reporter": "~6.0.0",
|
||||
"karma": "^6.3.1",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
|
@ -28,7 +28,8 @@ import { Action } from '@ngrx/store';
|
||||
export enum UploadActionTypes {
|
||||
UploadFiles = 'UPLOAD_FILES',
|
||||
UploadFolder = 'UPLOAD_FOLDER',
|
||||
UploadFileVersion = 'UPLOAD_FILE_VERSION'
|
||||
UploadFileVersion = 'UPLOAD_FILE_VERSION',
|
||||
UploadImage = 'UPLOAD_IMAGE'
|
||||
}
|
||||
|
||||
export class UploadFilesAction implements Action {
|
||||
@ -43,6 +44,12 @@ export class UploadFolderAction implements Action {
|
||||
constructor(public payload: any) {}
|
||||
}
|
||||
|
||||
export class UploadNewImageAction implements Action {
|
||||
readonly type = UploadActionTypes.UploadImage;
|
||||
|
||||
constructor(public payload: any) {}
|
||||
}
|
||||
|
||||
export class UploadFileVersionAction implements Action {
|
||||
readonly type = UploadActionTypes.UploadFileVersion;
|
||||
|
||||
|
@ -15,6 +15,12 @@
|
||||
right: 0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
adf-file-uploading-dialog {
|
||||
z-index: 1100;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 599px) {
|
||||
|
@ -14,6 +14,8 @@
|
||||
[allowDownload]="false"
|
||||
[allowFullScreen]="false"
|
||||
[overlayMode]="true"
|
||||
[readOnly]="!canUpdateNode"
|
||||
(fileSubmit)="onFileSubmit($event)"
|
||||
(showViewerChange)="onViewerVisibilityChanged()"
|
||||
[canNavigateBefore]="previousNodeId"
|
||||
[canNavigateNext]="nextNodeId"
|
||||
|
@ -33,6 +33,7 @@ import {
|
||||
ReloadDocumentListAction,
|
||||
SetCurrentNodeVersionAction,
|
||||
SetSelectedNodesAction,
|
||||
UploadNewImageAction,
|
||||
ViewerActionTypes,
|
||||
ViewNodeAction
|
||||
} from '@alfresco/aca-shared/store';
|
||||
@ -45,6 +46,7 @@ import { Store } from '@ngrx/store';
|
||||
import { from, Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { Actions, ofType } from '@ngrx/effects';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-viewer',
|
||||
@ -64,6 +66,7 @@ export class AppViewerComponent implements OnInit, OnDestroy {
|
||||
selection: SelectionState;
|
||||
infoDrawerOpened$: Observable<boolean>;
|
||||
|
||||
canUpdateNode = false;
|
||||
showRightSide = false;
|
||||
openWith: ContentActionRef[] = [];
|
||||
toolbarActions: ContentActionRef[] = [];
|
||||
@ -112,7 +115,8 @@ export class AppViewerComponent implements OnInit, OnDestroy {
|
||||
private preferences: UserPreferencesService,
|
||||
private apiService: AlfrescoApiService,
|
||||
private uploadService: UploadService,
|
||||
private appHookService: AppHookService
|
||||
private appHookService: AppHookService,
|
||||
private content: ContentManagementService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@ -208,6 +212,7 @@ export class AppViewerComponent implements OnInit, OnDestroy {
|
||||
if (nodeId) {
|
||||
try {
|
||||
this.node = await this.contentApi.getNodeInfo(nodeId).toPromise();
|
||||
this.canUpdateNode = this.content.canUpdateNode(this.node);
|
||||
this.store.dispatch(new SetSelectedNodesAction([{ entry: this.node }]));
|
||||
|
||||
if (this.node && this.node.isFile) {
|
||||
@ -248,6 +253,11 @@ export class AppViewerComponent implements OnInit, OnDestroy {
|
||||
this.store.dispatch(new ViewNodeAction(this.nextNodeId, { location }));
|
||||
}
|
||||
|
||||
onFileSubmit(newBlob: Blob) {
|
||||
const newImageFile: File = new File([newBlob], this?.node?.name, { type: this?.node?.content?.mimeType });
|
||||
this.store.dispatch(new UploadNewImageAction(newImageFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves nearest node information for the given node and folder.
|
||||
* @param nodeId Unique identifier of the document node
|
||||
|
@ -25,13 +25,23 @@
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { Actions, EffectsModule } from '@ngrx/effects';
|
||||
import { UploadEffects } from './upload.effects';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { NgZone } from '@angular/core';
|
||||
import { UploadService, FileUploadCompleteEvent, FileModel } from '@alfresco/adf-core';
|
||||
import { UnlockWriteAction, UploadFileVersionAction } from '@alfresco/aca-shared/store';
|
||||
import {
|
||||
SnackbarErrorAction,
|
||||
SnackbarInfoAction,
|
||||
UnlockWriteAction,
|
||||
UploadFileVersionAction,
|
||||
UploadNewImageAction
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import { provideMockActions } from '@ngrx/effects/testing';
|
||||
|
||||
describe('UploadEffects', () => {
|
||||
let store: Store<any>;
|
||||
@ -39,10 +49,35 @@ describe('UploadEffects', () => {
|
||||
let effects: UploadEffects;
|
||||
let zone: NgZone;
|
||||
let contentManagementService: ContentManagementService;
|
||||
let actions$: Observable<any> = of();
|
||||
const fakeNode: MinimalNodeEntryEntity = {
|
||||
createdAt: undefined,
|
||||
modifiedAt: undefined,
|
||||
modifiedByUser: undefined,
|
||||
isFile: true,
|
||||
createdByUser: {
|
||||
id: 'admin.adf@alfresco.com',
|
||||
displayName: 'Administrator'
|
||||
},
|
||||
nodeType: 'cm:content',
|
||||
content: {
|
||||
mimeType: 'image/jpeg',
|
||||
mimeTypeName: 'JPEG Image',
|
||||
sizeInBytes: 175540,
|
||||
encoding: 'UTF-8'
|
||||
},
|
||||
parentId: 'dff2bc1e-d092-42ac-82d1-87c82f6e56cb',
|
||||
isFolder: false,
|
||||
name: 'GoqZhm.jpg',
|
||||
id: '1bf8a8f7-18ac-4eef-919d-61d952eaa179',
|
||||
allowableOperations: ['delete', 'update', 'updatePermissions'],
|
||||
isFavorite: false
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule, EffectsModule.forRoot([UploadEffects])]
|
||||
imports: [AppTestingModule, EffectsModule.forRoot([UploadEffects])],
|
||||
providers: [provideMockActions(() => actions$)]
|
||||
});
|
||||
|
||||
zone = TestBed.inject(NgZone);
|
||||
@ -56,11 +91,6 @@ describe('UploadEffects', () => {
|
||||
effects = TestBed.inject(UploadEffects);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(effects['fileVersionInput'], 'click');
|
||||
spyOn(effects, 'uploadVersion').and.callThrough();
|
||||
});
|
||||
|
||||
describe('uploadAndUnlock()', () => {
|
||||
it('should not upload and unlock file if param not provided', () => {
|
||||
effects.uploadAndUnlock(null);
|
||||
@ -151,8 +181,17 @@ describe('UploadEffects', () => {
|
||||
});
|
||||
|
||||
describe('upload file version', () => {
|
||||
beforeEach(() => {
|
||||
actions$ = TestBed.inject(Actions);
|
||||
});
|
||||
|
||||
it('should trigger upload file from context menu', () => {
|
||||
store.dispatch({ type: 'UPLOAD_FILE_VERSION' });
|
||||
spyOn(effects['fileVersionInput'], 'click');
|
||||
actions$ = hot('a', {
|
||||
a: new UploadFileVersionAction(undefined)
|
||||
});
|
||||
const expected = cold('b', {});
|
||||
expect(effects.uploadVersion$).toBeObservable(expected);
|
||||
expect(effects['fileVersionInput'].click).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -206,8 +245,50 @@ describe('UploadEffects', () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
store.dispatch(new UploadFileVersionAction(fakeEvent));
|
||||
actions$ = hot('a', {
|
||||
a: new UploadFileVersionAction(fakeEvent)
|
||||
});
|
||||
|
||||
const expected = cold('b', {});
|
||||
expect(effects.uploadVersion$).toBeObservable(expected);
|
||||
|
||||
expect(contentManagementService.versionUpdateDialog).toHaveBeenCalledWith(fakeEvent.detail.data.node.entry, fakeEvent.detail.files[0].file);
|
||||
});
|
||||
});
|
||||
|
||||
describe('image versioning', () => {
|
||||
beforeEach(() => {
|
||||
actions$ = TestBed.inject(Actions);
|
||||
});
|
||||
|
||||
it('should trigger upload file version from viewer', () => {
|
||||
spyOn(contentManagementService, 'getNodeInfo').and.returnValue(of(fakeNode));
|
||||
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||
const fakeBlob = new Blob([data], { type: 'image/png' });
|
||||
const newImageFile: File = new File([fakeBlob], 'GoqZhm.jpg');
|
||||
actions$ = hot('a', {
|
||||
a: new UploadNewImageAction(newImageFile)
|
||||
});
|
||||
|
||||
const expected = cold('b', {
|
||||
b: new SnackbarInfoAction('APP.MESSAGES.UPLOAD.SUCCESS.MEDIA_MANAGEMENT')
|
||||
});
|
||||
expect(effects.uploadNewImage$).toBeObservable(expected);
|
||||
});
|
||||
|
||||
it('should display snackbar if can`t retrieve node details', () => {
|
||||
spyOn(contentManagementService, 'getNodeInfo').and.returnValue(throwError(fakeNode));
|
||||
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||
const fakeBlob = new Blob([data], { type: 'image/png' });
|
||||
const newImageFile: File = new File([fakeBlob], 'GoqZhm.jpg');
|
||||
actions$ = hot('a', {
|
||||
a: new UploadNewImageAction(newImageFile)
|
||||
});
|
||||
|
||||
const expected = cold('b', {
|
||||
b: new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.GENERIC')
|
||||
});
|
||||
expect(effects.uploadNewImage$).toBeObservable(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -31,14 +31,16 @@ import {
|
||||
UploadFilesAction,
|
||||
UploadFileVersionAction,
|
||||
UploadFolderAction,
|
||||
getCurrentFolder
|
||||
getCurrentFolder,
|
||||
UploadNewImageAction,
|
||||
SnackbarInfoAction
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { FileModel, FileUtils, UploadService } from '@alfresco/adf-core';
|
||||
import { Injectable, NgZone, RendererFactory2 } from '@angular/core';
|
||||
import { Actions, Effect, ofType } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { of } from 'rxjs';
|
||||
import { catchError, map, take } from 'rxjs/operators';
|
||||
import { catchError, map, mergeMap, switchMap, take } from 'rxjs/operators';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
||||
|
||||
@ -101,17 +103,47 @@ export class UploadEffects {
|
||||
})
|
||||
);
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
uploadNewImage$ = this.actions$.pipe(
|
||||
ofType<UploadNewImageAction>(UploadActionTypes.UploadImage),
|
||||
switchMap((action) => {
|
||||
return this.contentService.getNodeInfo().pipe(
|
||||
mergeMap((node) => {
|
||||
if (node?.id) {
|
||||
const newFile = new FileModel(
|
||||
action?.payload,
|
||||
{
|
||||
majorVersion: false,
|
||||
newVersion: true,
|
||||
parentId: node?.parentId,
|
||||
nodeType: node?.content?.mimeType
|
||||
},
|
||||
node?.id
|
||||
);
|
||||
this.uploadQueue([newFile]);
|
||||
return of(new SnackbarInfoAction('APP.MESSAGES.UPLOAD.SUCCESS.MEDIA_MANAGEMENT'));
|
||||
}
|
||||
return of(null);
|
||||
}),
|
||||
catchError(() => {
|
||||
return of(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.GENERIC'));
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
uploadVersion$ = this.actions$.pipe(
|
||||
ofType<UploadFileVersionAction>(UploadActionTypes.UploadFileVersion),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
const node = action.payload.detail.data.node.entry;
|
||||
const file: any = action.payload.detail.files[0].file;
|
||||
this.contentService.versionUpdateDialog(node, file);
|
||||
mergeMap((action) => {
|
||||
if (action?.payload) {
|
||||
const node = action?.payload?.detail?.data?.node?.entry;
|
||||
const file: any = action?.payload?.detail?.files[0]?.file;
|
||||
return of(this.contentService.versionUpdateDialog(node, file));
|
||||
} else if (!action.payload) {
|
||||
this.fileVersionInput.click();
|
||||
return of(this.fileVersionInput.click());
|
||||
}
|
||||
return of(null);
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -301,6 +301,9 @@
|
||||
"504": "The server timed out, try again or contact IT support [504]",
|
||||
"403": "Insufficient permissions to upload in this location [403]",
|
||||
"404": "Upload location no longer exists [404]"
|
||||
},
|
||||
"SUCCESS": {
|
||||
"MEDIA_MANAGEMENT_SUCCESS": "Version updated successfully"
|
||||
}
|
||||
},
|
||||
"INFO": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user