Guided tour added in dataset editor details

This commit is contained in:
gpapavgeri 2020-07-31 17:39:57 +03:00
parent 9ff36a1b12
commit 24855f776b
10 changed files with 167 additions and 83 deletions

View File

@ -8,13 +8,16 @@
</div> --> </div> -->
<div *ngIf="currentTourStep && !isOrbShowing"> <div *ngIf="currentTourStep && !isOrbShowing">
<div class="guided-tour-user-input-mask" (click)="backdropClick($event)"></div> <div class="guided-tour-user-input-mask" (click)="backdropClick($event)"></div>
<div class="guided-tour-spotlight-overlay" [style.top.px]="overlayTop" [style.left.px]="overlayLeft" <div *ngIf="!isStepUnique" class="guided-tour-spotlight-overlay" [style.top.px]="overlayTop" [style.left.px]="overlayLeft"
[style.height.px]="overlayHeight" [style.width.px]="overlayWidth"> [style.height.px]="overlayHeight" [style.width.px]="overlayWidth" >
</div>
<div *ngIf="isStepUnique" class="guided-tour-spotlight-overlay spotlight-overlay-step-unique" [style.top.px]="overlayTop-12" [style.left.px]="overlayLeft-3"
[style.height.px]="overlayHeight" [style.width.px]="overlayWidth" >
</div> </div>
</div> </div>
<div *ngIf="currentTourStep && !isOrbShowing"> <div *ngIf="currentTourStep && !isOrbShowing">
<div #tourStep *ngIf="currentTourStep" class="tour-step tour-{{ currentTourStep.orientation }}" [ngClass]="{ <div #tourStep *ngIf="currentTourStep" class="tour-step tour-{{ currentTourStep.orientation }}" [ngClass]="{
'page-tour-step': !currentTourStep.selector 'page-tour-step': !currentTourStep.selector, 'tour-step-unique' : isStepUnique
}" [style.top.px]="(currentTourStep.selector && selectedElementRect ? topPosition : null)" }" [style.top.px]="(currentTourStep.selector && selectedElementRect ? topPosition : null)"
[style.left.px]="(currentTourStep.selector && selectedElementRect ? leftPosition : null)" [style.left.px]="(currentTourStep.selector && selectedElementRect ? leftPosition : null)"
[style.width.px]="(currentTourStep.selector && selectedElementRect ? calculatedTourStepWidth : null)" [style.width.px]="(currentTourStep.selector && selectedElementRect ? calculatedTourStepWidth : null)"
@ -38,7 +41,7 @@
(click)="guidedTourService.nextStep()"> (click)="guidedTourService.nextStep()">
{{ nextText }} {{ nextText }}
</button> </button>
<button *ngIf="!guidedTourService.onResizeMessage" (click)="guidedTourService.skipTour()" <button *ngIf="!guidedTourService.onResizeMessage && !isStepUnique" (click)="guidedTourService.skipTour()"
class="skip-button link-button"> class="skip-button link-button">
{{ skipText }} {{ skipText }}
</button> </button>

View File

@ -17,6 +17,10 @@ ngx-guided-tour {
border-radius: 44px; border-radius: 44px;
} }
.spotlight-overlay-step-unique {
padding: 20px;
}
.tour-orb { .tour-orb {
position: fixed; position: fixed;
width: 20px; width: 20px;
@ -53,6 +57,10 @@ ngx-guided-tour {
} }
} }
.tour-step-unique {
margin-top: 15px;
}
.tour-step { .tour-step {
position: fixed; position: fixed;
&.page-tour-step { &.page-tour-step {
@ -133,9 +141,9 @@ ngx-guided-tour {
border-radius: 5px; border-radius: 5px;
} }
.tour-progress-indicator { // .tour-progress-indicator {
padding-bottom: 15px; // padding-bottom: 15px;
} // }
.tour-title { .tour-title {
font-weight: lighter !important; font-weight: lighter !important;
@ -149,6 +157,7 @@ ngx-guided-tour {
line-height: 26px; line-height: 26px;
white-space:pre-line; white-space:pre-line;
height: 182px; height: 182px;
width: 983px;
} }
h3.tour-title { h3.tour-title {
@ -158,11 +167,11 @@ ngx-guided-tour {
font-size: 30px; font-size: 30px;
} }
.tour-content { // .tour-content {
min-height: 80px; // min-height: 80px;
padding-bottom: 30px; // padding-bottom: 30px;
font-size: 15px; // font-size: 15px;
} // }
.tour-buttons { .tour-buttons {
overflow: hidden; // clearfix overflow: hidden; // clearfix

View File

@ -1,7 +1,7 @@
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild, ViewEncapsulation, TemplateRef, Inject } from '@angular/core'; import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild, ViewEncapsulation, TemplateRef, Inject } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs'; import { fromEvent, Subscription } from 'rxjs';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { Orientation, TourStep, ProgressIndicatorLocation } from './guided-tour.constants'; import { Orientation, TourStep } from './guided-tour.constants';
import { GuidedTourService } from './guided-tour.service'; import { GuidedTourService } from './guided-tour.service';
import { WindowRefService } from "./windowref.service"; import { WindowRefService } from "./windowref.service";
@ -12,22 +12,23 @@ import { WindowRefService } from "./windowref.service";
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class GuidedTourComponent implements AfterViewInit, OnDestroy { export class GuidedTourComponent implements AfterViewInit, OnDestroy {
@Input() public topOfPageAdjustment ?= 0; @Input() public topOfPageAdjustment?= 0;
@Input() public tourStepWidth ?= 1043; @Input() public tourStepWidth?= 1043;
@Input() public minimalTourStepWidth ?= 900; @Input() public minimalTourStepWidth?= 900;
@Input() public skipText ?= 'Leave Tour'; @Input() public skipText?= 'Leave Tour';
@Input() public nextText ?= 'Got it!'; @Input() public nextText?= 'Got it!';
@Input() public doneText ?= 'Done'; // @Input() public doneText?= 'Done';
@Input() public closeText ?= 'Close'; // @Input() public closeText?= 'Close';
@Input() public backText ?= 'Back'; // @Input() public backText?= 'Back';
@Input() public progressIndicatorLocation?: ProgressIndicatorLocation = ProgressIndicatorLocation.InsideNextButton; // @Input() public progressIndicatorLocation?: ProgressIndicatorLocation = ProgressIndicatorLocation.InsideNextButton;
@Input() public progressIndicator?: TemplateRef<any> = undefined; @Input() public progressIndicator?: TemplateRef<any> = undefined;
@ViewChild('tourStep', { static: false }) public tourStep: ElementRef; @ViewChild('tourStep', { static: false }) public tourStep: ElementRef;
public highlightPadding = 4; public highlightPadding = 4;
public currentTourStep: TourStep = null; public currentTourStep: TourStep = null;
public selectedElementRect: DOMRect = null; public selectedElementRect: DOMRect = null;
public isOrbShowing = false; public isOrbShowing = false;
public progressIndicatorLocations = ProgressIndicatorLocation; // public progressIndicatorLocations = ProgressIndicatorLocation;
public isStepUnique = false;
private resizeSubscription: Subscription; private resizeSubscription: Subscription;
private scrollSubscription: Subscription; private scrollSubscription: Subscription;
@ -58,11 +59,13 @@ export class GuidedTourComponent implements AfterViewInit, OnDestroy {
} }
public get calculatedTourStepWidth() { public get calculatedTourStepWidth() {
return this.tourStepWidth - this.widthAdjustmentForScreenBound; return this.tourStepWidth;
// return this.tourStepWidth - this.widthAdjustmentForScreenBound;
} }
public ngAfterViewInit(): void { public ngAfterViewInit(): void {
this.guidedTourService.guidedTourCurrentStepStream.subscribe((step: TourStep) => { this.guidedTourService.guidedTourCurrentStepStream.subscribe((step: TourStep) => {
this.isStepUnique = this.guidedTourService.isStepUnique;
this.currentTourStep = step; this.currentTourStep = step;
if (step && step.selector) { if (step && step.selector) {
const selectedElement = this.dom.querySelector(step.selector); const selectedElement = this.dom.querySelector(step.selector);

View File

@ -68,8 +68,8 @@ export class Orientation {
public static readonly TopRight = 'top-right'; public static readonly TopRight = 'top-right';
} }
export enum ProgressIndicatorLocation { // export enum ProgressIndicatorLocation {
InsideNextButton = 'inside-next-button', // InsideNextButton = 'inside-next-button',
TopOfTourBlock = 'top-of-tour-block', // TopOfTourBlock = 'top-of-tour-block',
None = 'none', // None = 'none',
} // }

View File

@ -18,6 +18,7 @@ export class GuidedTourService {
private _onFirstStep = true; private _onFirstStep = true;
private _onLastStep = true; private _onLastStep = true;
private _onResizeMessage = false; private _onResizeMessage = false;
public isStepUnique = false;
constructor( constructor(
public errorHandler: ErrorHandler, public errorHandler: ErrorHandler,
@ -77,33 +78,33 @@ export class GuidedTourService {
} }
} }
public backStep(): void { // public backStep(): void {
if (this._currentTour.steps[this._currentTourStepIndex].closeAction) { // if (this._currentTour.steps[this._currentTourStepIndex].closeAction) {
this._currentTour.steps[this._currentTourStepIndex].closeAction(); // this._currentTour.steps[this._currentTourStepIndex].closeAction();
} // }
if (this._currentTour.steps[this._currentTourStepIndex - 1]) { // if (this._currentTour.steps[this._currentTourStepIndex - 1]) {
this._currentTourStepIndex--; // this._currentTourStepIndex--;
this._setFirstAndLast(); // this._setFirstAndLast();
if (this._currentTour.steps[this._currentTourStepIndex].action) { // if (this._currentTour.steps[this._currentTourStepIndex].action) {
this._currentTour.steps[this._currentTourStepIndex].action(); // this._currentTour.steps[this._currentTourStepIndex].action();
setTimeout(() => { // setTimeout(() => {
if (this._checkSelectorValidity()) { // if (this._checkSelectorValidity()) {
this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex)); // this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
} else { // } else {
this.backStep(); // this.backStep();
} // }
}); // });
} else { // } else {
if (this._checkSelectorValidity()) { // if (this._checkSelectorValidity()) {
this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex)); // this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
} else { // } else {
this.backStep(); // this.backStep();
} // }
} // }
} else { // } else {
this.resetTour(); // this.resetTour();
} // }
} // }
public skipTour(): void { public skipTour(): void {
if (this._currentTour.skipCallback) { if (this._currentTour.skipCallback) {
@ -144,6 +145,13 @@ export class GuidedTourService {
} }
} }
public checkIfStepIsUnique(tour: GuidedTour): boolean {
if(tour.steps.length === 1) {
this.isStepUnique = true;
}
return this.isStepUnique;
}
public activateOrb(): void { public activateOrb(): void {
this._guidedTourOrbShowingSubject.next(false); this._guidedTourOrbShowingSubject.next(false);
this.dom.body.classList.add('tour-open'); this.dom.body.classList.add('tour-open');

View File

@ -34,6 +34,7 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<!-- End of Sort by --> <!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour --> <!-- Guided Tour -->
<div class="center-content" [style.display]=" (!isVisible && isAuthenticated()) ? 'block' : 'none'" (click)="restartTour()"> <div class="center-content" [style.display]=" (!isVisible && isAuthenticated()) ? 'block' : 'none'" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }} {{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
@ -48,6 +49,7 @@
<!-- End of Search Filter --> <!-- End of Search Filter -->
</div> </div>
</div> </div>
</div>
<div class="col-md-12 col-sm-12 col-md-9"> <div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dataset-listing-item-component [isPublic]="isPublic" [dataset]="item" [showDivider]="i != (listingItems.length - 1)"></app-dataset-listing-item-component> <app-dataset-listing-item-component [isPublic]="isPublic" [dataset]="item" [showDivider]="i != (listingItems.length - 1)"></app-dataset-listing-item-component>

View File

@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div> <div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link dmp-only-tour-title" target="_blank" (click)="restartTourFromTitle()">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="title-form"> <div class="title-form">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required> <input matInput placeholder="{{'DATASET-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
@ -23,7 +23,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div> <div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link dmp-only-tour-desc" target="_blank" (click)="restartTourFromDesc()">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="description-form"> <div class="description-form">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<textarea rows="3" matInput class="description-area" placeholder="{{'DMP-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" formControlName="description"></textarea> <textarea rows="3" matInput class="description-area" placeholder="{{'DMP-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" formControlName="description"></textarea>

View File

@ -27,6 +27,8 @@ import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DatasetWizardEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { DatasetWizardEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { ENTER, COMMA } from '@angular/cdk/keycodes'; import { ENTER, COMMA } from '@angular/cdk/keycodes';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
@Component({ @Component({
@ -57,6 +59,7 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
// isLinear = false; // isLinear = false;
lock: LockModel; lock: LockModel;
lockStatus: Boolean; lockStatus: Boolean;
dmpText: string;
@Input() formGroup: FormGroup; @Input() formGroup: FormGroup;
@Input() dmpId: string; @Input() dmpId: string;
@ -79,7 +82,8 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
private formService: FormService, private formService: FormService,
private lockService: LockService, private lockService: LockService,
private location: Location, private location: Location,
private authService: AuthService private authService: AuthService,
private guidedTourService: GuidedTourService
) { ) {
super(); super();
} }
@ -133,6 +137,53 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
} }
} }
public dashboardTourDmpTitle: GuidedTour = {
tourId: 'only-dmp-tour',
useOrb: true,
steps: [
{
title: this.dmpText,
selector: '.dmp-only-tour-title',
content: 'Step 1',
orientation: Orientation.Bottom
}
]
};
public dashboardTourDmpDescription: GuidedTour = {
tourId: 'only-dmp-tour',
useOrb: true,
steps: [
{
title: this.dmpText,
selector: '.dmp-only-tour-desc',
content: 'Step 1',
orientation: Orientation.Bottom
}
]
};
setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
this.dashboardTourDmpTitle.steps[0].title = this.dmpText;
this.dashboardTourDmpDescription.steps[0].title = this.dmpText;
}
public restartTourFromTitle(): void {
this.setDashboardTourDmpText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTourDmpTitle);
this.guidedTourService.startTour(this.dashboardTourDmpTitle);
}
public restartTourFromDesc(): void {
this.setDashboardTourDmpText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTourDmpDescription);
this.guidedTourService.startTour(this.dashboardTourDmpDescription);
}
registerFormListeners() { registerFormListeners() {
this.formGroup.get('dmp').valueChanges this.formGroup.get('dmp').valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))

View File

@ -29,20 +29,26 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<!-- End of Sort by --> <!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour --> <!-- Guided Tour -->
<div class="center-content" [style.display]="!isVisible && isAuthenticated()? 'block' : 'none'" (click)="restartTour()"> <div class="center-content"
[style.display]="!isVisible && isAuthenticated()? 'block' : 'none'" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }} {{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
</div> </div>
<!-- End of Guided Tour --> <!-- End of Guided Tour -->
<!-- Search Filter--> <!-- Search Filter-->
<mat-form-field appearance="outline" class="search-form ml-auto col-auto pr-0" floatLabel="never"> <mat-form-field appearance="outline" class="search-form ml-auto col-auto pr-0"
floatLabel="never">
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria" [formControl]="formGroup.get('like')"> <input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria"
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">{{formGroup.get('like').getError('backendError').message}}</mat-error> [formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
<!-- End of Search Filter --> <!-- End of Search Filter -->
</div> </div>
</div> </div>
</div>
<div class="col-md-12 col-sm-12 col-md-9"> <div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component> <app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component>

View File

@ -197,6 +197,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread
public isAuthenticated(): boolean { public isAuthenticated(): boolean {
return !(!this.authService.current()); return !(!this.authService.current());
} }
ngAfterContentChecked(): void { ngAfterContentChecked(): void {
this.scrollbar = this.hasScrollbar(); this.scrollbar = this.hasScrollbar();
} }
@ -470,6 +471,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread
public restartTour(): void { public restartTour(): void {
this.setDashboardTourDmpText(); this.setDashboardTourDmpText();
this.setDashboardTourDatasetText(); this.setDashboardTourDatasetText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTour);
this.guidedTourService.startTour(this.dashboardTour); this.guidedTourService.startTour(this.dashboardTour);
} }
} }