mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACA-1115] Quick Share (#492)
* share file * fix * fix test dependency * experimental guard
This commit is contained in:
committed by
Denys Vuika
parent
e5bc3bb755
commit
3e123bee62
@@ -11,7 +11,8 @@
|
||||
"experimental": {
|
||||
"libraries": false,
|
||||
"comments": false,
|
||||
"cardview": false
|
||||
"cardview": false,
|
||||
"share": false
|
||||
},
|
||||
"headerColor": "#2196F3",
|
||||
"languagePicker": false,
|
||||
|
@@ -30,7 +30,13 @@ import {
|
||||
AuthenticationService, AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from './store/states/app.state';
|
||||
import { SetHeaderColorAction, SetAppNameAction, SetLogoPathAction, SetLanguagePickerAction } from './store/actions';
|
||||
import {
|
||||
SetHeaderColorAction,
|
||||
SetAppNameAction,
|
||||
SetLogoPathAction,
|
||||
SetLanguagePickerAction,
|
||||
SetSharedUrlAction
|
||||
} from './store/actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -94,5 +100,8 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
const languagePicker = this.config.get<boolean>('languagePicker');
|
||||
this.store.dispatch(new SetLanguagePickerAction(languagePicker));
|
||||
|
||||
const sharedPreviewUrl = this.config.get<string>('ecmHost') + '/#/preview/s/';
|
||||
this.store.dispatch(new SetSharedUrlAction(sharedPreviewUrl));
|
||||
}
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ import { SidenavComponent } from './components/sidenav/sidenav.component';
|
||||
import { AboutComponent } from './components/about/about.component';
|
||||
import { LocationLinkComponent } from './components/location-link/location-link.component';
|
||||
import { CustomDlRowComponent } from './components/custom-dl-row/custom-dl-row.component';
|
||||
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
||||
import { NodeCopyDirective } from './common/directives/node-copy.directive';
|
||||
import { NodeDeleteDirective } from './common/directives/node-delete.directive';
|
||||
import { NodeMoveDirective } from './common/directives/node-move.directive';
|
||||
@@ -69,6 +70,7 @@ import { SearchComponent } from './components/search/search.component';
|
||||
import { SettingsComponent } from './components/settings/settings.component';
|
||||
import { PageTitleService as AcaPageTitleService } from './common/services/page-title.service';
|
||||
import { ProfileResolver } from './common/services/profile.resolver';
|
||||
import { ExperimentalGuard } from './common/services/experimental-guard.service';
|
||||
|
||||
import { InfoDrawerComponent } from './components/info-drawer/info-drawer.component';
|
||||
import { EditFolderDirective } from './directives/edit-folder.directive';
|
||||
@@ -128,6 +130,7 @@ import { ContentApiService } from './services/content-api.service';
|
||||
SearchComponent,
|
||||
SettingsComponent,
|
||||
InfoDrawerComponent,
|
||||
SharedLinkViewComponent,
|
||||
EditFolderDirective,
|
||||
CreateFolderDirective,
|
||||
DownloadNodesDirective,
|
||||
@@ -151,6 +154,7 @@ import { ContentApiService } from './services/content-api.service';
|
||||
NodeActionsService,
|
||||
NodePermissionService,
|
||||
ProfileResolver,
|
||||
ExperimentalGuard,
|
||||
ContentApiService
|
||||
],
|
||||
entryComponents: [
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
import { Routes } from '@angular/router';
|
||||
import { AuthGuardEcm } from '@alfresco/adf-core';
|
||||
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
||||
|
||||
import { LayoutComponent } from './components/layout/layout.component';
|
||||
|
||||
@@ -43,6 +44,7 @@ import { SearchComponent } from './components/search/search.component';
|
||||
import { SettingsComponent } from './components/settings/settings.component';
|
||||
|
||||
import { ProfileResolver } from './common/services/profile.resolver';
|
||||
import { ExperimentalGuard } from './common/services/experimental-guard.service';
|
||||
|
||||
export const APP_ROUTES: Routes = [
|
||||
{
|
||||
@@ -59,6 +61,15 @@ export const APP_ROUTES: Routes = [
|
||||
title: 'Settings'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'preview/s/:id',
|
||||
component: SharedLinkViewComponent,
|
||||
canActivate: [ ExperimentalGuard ],
|
||||
data: {
|
||||
ifExperimentalKey: 'share',
|
||||
title: 'APP.PREVIEW.TITLE',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: LayoutComponent,
|
||||
|
20
src/app/common/services/experimental-guard.service.ts
Normal file
20
src/app/common/services/experimental-guard.service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { CanActivate, ActivatedRouteSnapshot } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class ExperimentalGuard implements CanActivate {
|
||||
constructor(private config: AppConfigService) {}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot) {
|
||||
const key = `experimental.${route.data.ifExperimentalKey}`;
|
||||
const value = this.config.get(key);
|
||||
|
||||
if (!environment.production) {
|
||||
return value === true || value === 'true';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -44,6 +44,17 @@
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'share'">
|
||||
<button mat-icon-button
|
||||
color="primary"
|
||||
title="{{ 'APP.ACTIONS.SHARE' | translate }}"
|
||||
*ngIf="selection.file"
|
||||
[baseShareUrl]="sharedPreviewUrl$ | async"
|
||||
[adf-share]="selection.file">
|
||||
<mat-icon>share</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
|
@@ -46,6 +46,17 @@
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'share'">
|
||||
<button mat-icon-button
|
||||
color="primary"
|
||||
title="{{ 'APP.ACTIONS.SHARE' | translate }}"
|
||||
*ngIf="selection.file"
|
||||
[baseShareUrl]="sharedPreviewUrl$ | async"
|
||||
[adf-share]="selection.file">
|
||||
<mat-icon>share</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
|
@@ -31,9 +31,10 @@ import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Subject, Subscription } from 'rxjs/Rx';
|
||||
import { SnackbarErrorAction, ViewNodeAction, SetSelectedNodesAction } from '../store/actions';
|
||||
import { appSelection } from '../store/selectors/app.selectors';
|
||||
import { appSelection, sharedUrl } from '../store/selectors/app.selectors';
|
||||
import { AppStore } from '../store/states/app.state';
|
||||
import { SelectionState } from '../store/states/selection.state';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
export abstract class PageComponent implements OnInit, OnDestroy {
|
||||
|
||||
@@ -47,6 +48,7 @@ export abstract class PageComponent implements OnInit, OnDestroy {
|
||||
node: MinimalNodeEntryEntity;
|
||||
selection: SelectionState;
|
||||
displayMode = DisplayMode.List;
|
||||
sharedPreviewUrl$: Observable<string>;
|
||||
|
||||
protected subscriptions: Subscription[] = [];
|
||||
|
||||
@@ -57,6 +59,8 @@ export abstract class PageComponent implements OnInit, OnDestroy {
|
||||
constructor(protected store: Store<AppStore>) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.sharedPreviewUrl$ = this.store.select(sharedUrl);
|
||||
|
||||
this.store
|
||||
.select(appSelection)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
|
@@ -46,6 +46,16 @@
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'share'">
|
||||
<button mat-menu-item
|
||||
color="primary"
|
||||
[baseShareUrl]="sharedPreviewUrl$ | async"
|
||||
[adf-share]="selectedEntities[0]">
|
||||
<mat-icon>share</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.SHARE' | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaCopyNode]="selectedEntities">
|
||||
|
@@ -30,6 +30,7 @@ import { UserPreferencesService, AppConfigPipe, NodeFavoriteDirective } from '@a
|
||||
import { PreviewComponent } from './preview.component';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { ExperimentalDirective } from '../../directives/experimental.directive';
|
||||
import { NodeEffects } from '../../store/effects/node.effects';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { ContentApiService } from '../../services/content-api.service';
|
||||
@@ -52,7 +53,8 @@ describe('PreviewComponent', () => {
|
||||
declarations: [
|
||||
AppConfigPipe,
|
||||
PreviewComponent,
|
||||
NodeFavoriteDirective
|
||||
NodeFavoriteDirective,
|
||||
ExperimentalDirective
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
});
|
||||
|
@@ -35,6 +35,16 @@
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'share'">
|
||||
<button mat-icon-button
|
||||
title="{{ 'APP.ACTIONS.SHARE' | translate }}"
|
||||
*ngIf="selection.file"
|
||||
[baseShareUrl]="sharedPreviewUrl$ | async"
|
||||
[adf-share]="selection.file">
|
||||
<mat-icon>share</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
|
@@ -80,5 +80,13 @@
|
||||
Cardview
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="share"
|
||||
(change)="onChangeShareFeature($event)">
|
||||
Share
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
@@ -51,6 +51,7 @@ export class SettingsComponent implements OnInit {
|
||||
libraries: boolean;
|
||||
comments: boolean;
|
||||
cardview: boolean;
|
||||
share: boolean;
|
||||
|
||||
constructor(
|
||||
private store: Store<AppStore>,
|
||||
@@ -82,6 +83,9 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
const cardview = this.appConfig.get('experimental.cardview');
|
||||
this.cardview = (cardview === true || cardview === 'true');
|
||||
|
||||
const share = this.appConfig.get('experimental.share');
|
||||
this.share = (share === true || share === 'true');
|
||||
}
|
||||
|
||||
apply(model: any, isValid: boolean) {
|
||||
@@ -113,4 +117,8 @@ export class SettingsComponent implements OnInit {
|
||||
onChangeCardviewFeature(event: MatCheckboxChange) {
|
||||
this.storage.setItem('experimental.cardview', event.checked.toString());
|
||||
}
|
||||
|
||||
onChangeShareFeature(event: MatCheckboxChange) {
|
||||
this.storage.setItem('experimental.share', event.checked.toString());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<ng-container *ngIf="sharedLinkId">
|
||||
<adf-viewer
|
||||
[sharedLinkId]="sharedLinkId"
|
||||
[allowGoBack]="false">
|
||||
</adf-viewer>
|
||||
</ng-container>
|
@@ -0,0 +1,4 @@
|
||||
.app-shared-link-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shared-link-view',
|
||||
templateUrl: 'shared-link-view.component.html',
|
||||
styleUrls: [ 'shared-link-view.component.scss' ],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
// tslint:disable-next-line:use-host-property-decorator
|
||||
host: { 'class': 'app-shared-link-view' }
|
||||
})
|
||||
export class SharedLinkViewComponent implements OnInit {
|
||||
|
||||
sharedLinkId: string = null;
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(params => {
|
||||
this.sharedLinkId = params.id;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -29,6 +29,7 @@ export const SET_APP_NAME = 'SET_APP_NAME';
|
||||
export const SET_HEADER_COLOR = 'SET_HEADER_COLOR';
|
||||
export const SET_LOGO_PATH = 'SET_LOGO_PATH';
|
||||
export const SET_LANGUAGE_PICKER = 'SET_LANGUAGE_PICKER';
|
||||
export const SET_SHARED_URL = 'SET_SHARED_URL';
|
||||
|
||||
export class SetAppNameAction implements Action {
|
||||
readonly type = SET_APP_NAME;
|
||||
@@ -49,3 +50,8 @@ export class SetLanguagePickerAction implements Action {
|
||||
readonly type = SET_LANGUAGE_PICKER;
|
||||
constructor(public payload: boolean) {}
|
||||
}
|
||||
|
||||
export class SetSharedUrlAction implements Action {
|
||||
readonly type = SET_SHARED_URL;
|
||||
constructor(public payload: string) {}
|
||||
}
|
||||
|
@@ -39,7 +39,9 @@ import {
|
||||
} from '../actions';
|
||||
import {
|
||||
SET_LANGUAGE_PICKER,
|
||||
SetLanguagePickerAction
|
||||
SetLanguagePickerAction,
|
||||
SET_SHARED_URL,
|
||||
SetSharedUrlAction
|
||||
} from '../actions/app.actions';
|
||||
|
||||
export function appReducer(
|
||||
@@ -71,6 +73,11 @@ export function appReducer(
|
||||
action
|
||||
));
|
||||
break;
|
||||
case SET_SHARED_URL:
|
||||
newState = updateSharedUrl(state, <SetSharedUrlAction>(
|
||||
action
|
||||
));
|
||||
break;
|
||||
default:
|
||||
newState = Object.assign({}, state);
|
||||
}
|
||||
@@ -108,6 +115,15 @@ function updateLogoPath(state: AppState, action: SetLogoPathAction): AppState {
|
||||
return newState;
|
||||
}
|
||||
|
||||
function updateSharedUrl(
|
||||
state: AppState,
|
||||
action: SetSharedUrlAction
|
||||
): AppState {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.sharedUrl = action.payload;
|
||||
return newState;
|
||||
}
|
||||
|
||||
function updateUser(state: AppState, action: SetUserAction): AppState {
|
||||
const newState = Object.assign({}, state);
|
||||
const user = action.payload;
|
||||
|
@@ -33,3 +33,4 @@ export const selectLogoPath = createSelector(selectApp, state => state.logoPath)
|
||||
export const appSelection = createSelector(selectApp, state => state.selection);
|
||||
export const appLanguagePicker = createSelector(selectApp, state => state.languagePicker);
|
||||
export const selectUser = createSelector(selectApp, state => state.user);
|
||||
export const sharedUrl = createSelector(selectApp, state => state.sharedUrl);
|
||||
|
@@ -31,6 +31,7 @@ export interface AppState {
|
||||
headerColor: string;
|
||||
logoPath: string;
|
||||
languagePicker: boolean;
|
||||
sharedUrl: string;
|
||||
selection: SelectionState;
|
||||
user: ProfileState;
|
||||
}
|
||||
@@ -40,6 +41,7 @@ export const INITIAL_APP_STATE: AppState = {
|
||||
headerColor: '#2196F3',
|
||||
logoPath: 'assets/images/alfresco-logo-white.svg',
|
||||
languagePicker: false,
|
||||
sharedUrl: '',
|
||||
user: {
|
||||
isAdmin: true, // 5.2.x
|
||||
id: null,
|
||||
|
@@ -124,7 +124,8 @@
|
||||
"UNSHARE": "Unshare",
|
||||
"DETAILS": "View details",
|
||||
"VERSIONS": "Manage Versions",
|
||||
"TOGGLE-SIDENAV": "Toggle side navigation bar"
|
||||
"TOGGLE-SIDENAV": "Toggle side navigation bar",
|
||||
"SHARE": "Share"
|
||||
},
|
||||
"DIALOGS": {
|
||||
"CONFIRM_PURGE": {
|
||||
|
Reference in New Issue
Block a user