feat: Create a tutorial dialog

This commit is contained in:
Marcel Haag 2023-05-09 10:06:44 +02:00 committed by Cel
parent cf7204fb9d
commit bc8d59f1a9
34 changed files with 402 additions and 79 deletions

View File

@ -29,7 +29,9 @@
],
"styles": [
"src/assets/@theme/styles/styles.scss",
"node_modules/@fortawesome/fontawesome-free/css/all.css"
"node_modules/@fortawesome/fontawesome-free/css/all.css",
"node_modules/@glidejs/glide/src/assets/sass/glide.core.scss",
"node_modules/@glidejs/glide/src/assets/sass/glide.theme.scss"
],
"scripts": [
"node_modules/@fortawesome/fontawesome-free/js/all.js"

View File

@ -472,11 +472,11 @@
}
},
"@angular/animations": {
"version": "12.2.17",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-12.2.17.tgz",
"integrity": "sha512-WVUcvKvr6wr9Nf3I2ksu5bFJ5xHhby4UEBTvOAdLpDqic+dzqtzVwAktDRprBSdxKQk1OlTw6jD4MsVEDKnZTg==",
"version": "11.2.14",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.2.14.tgz",
"integrity": "sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA==",
"requires": {
"tslib": "^2.2.0"
"tslib": "^2.0.0"
}
},
"@angular/cdk": {
@ -2433,6 +2433,11 @@
}
}
},
"@glidejs/glide": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@glidejs/glide/-/glide-3.6.0.tgz",
"integrity": "sha512-47Aa+JmYjY4xTFpTtYCwrqirmI1arnp1UZETwtWpbTPisXUAuxrdJxKJLH8KHFWMsSrLi9+AcfyfzDIuO75rEA=="
},
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -11802,6 +11807,14 @@
"resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-13.5.2.tgz",
"integrity": "sha512-mn9qkef166cKmg5k1/jY4AlXEGEPx/cdWXKDdSrs/Fett+nLEAx70uD1LJrpQ35PY6k0v6AUd4fbZX5OaoFNRg=="
},
"ngx-glide": {
"version": "12.1.1",
"resolved": "https://registry.npmjs.org/ngx-glide/-/ngx-glide-12.1.1.tgz",
"integrity": "sha512-nbc5lRm22WRJ7Kb6bXFJ1E+2S/HIKy157ML6ZXlo2CYwJ1mt+LvvWCGiQP2mQ9CIKufbE4fcZqn1QZWkDxnkGQ==",
"requires": {
"tslib": "^2.1.0"
}
},
"ngx-moment": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ngx-moment/-/ngx-moment-5.0.0.tgz",

View File

@ -11,7 +11,7 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^12.2.16",
"@angular/animations": "^11.2.14",
"@angular/cdk": "^12.2.7",
"@angular/common": "^12.2.16",
"@angular/compiler": "~12.2.16",
@ -27,6 +27,7 @@
"@fortawesome/fontawesome-svg-core": "^6.3.0",
"@fortawesome/free-regular-svg-icons": "^6.3.0",
"@fortawesome/free-solid-svg-icons": "^6.3.0",
"@glidejs/glide": "^3.6.0",
"@nebular/eva-icons": "^8.0.0",
"@nebular/theme": "^8.0.0",
"@ngneat/until-destroy": "~8.0.4",
@ -44,6 +45,7 @@
"moment": "^2.29.1",
"moment-timezone": "latest",
"ng-mocks": "^13.4.2",
"ngx-glide": "^12.0.0",
"ngx-moment": "^5.0.0",
"ngx-take-until-destroy": "^5.4.0",
"ngx-translate-testing": "^5.2.0",

View File

@ -14,7 +14,7 @@
<nb-actions size="medium">
<!--Info Action-->
<nb-action>
<fa-icon title="Info" [icon]="fa.faCircleInfo" (click)="onClickShowInfo()" class="action-element-icon fa-2x">
<fa-icon title="Info" [icon]="fa.faCircleInfo" (click)="onClickShowTutorial()" class="action-element-icon fa-2x">
</fa-icon>
</nb-action>
<!--OWASP Action-->

View File

@ -16,6 +16,7 @@ import {environment} from '../../environments/environment';
import {Router} from '@angular/router';
import {DialogService} from '@shared/services/dialog-service/dialog.service';
import {ProfileSettingsComponent} from '@shared/modules/profile-settings/profile-settings.component';
import {TutorialDialogComponent} from '@shared/modules/tutorial-dialog/tutorial-dialog.component';
@Component({
selector: 'app-header',
@ -128,8 +129,20 @@ export class HeaderComponent implements OnInit {
window.open(url, '_blank');
}
onClickShowInfo(): void {
onClickShowTutorial(): void {
console.info('To be implemented..');
this.dialogService.openCustomDialog(
TutorialDialogComponent,
{}
).onClose.pipe(
filter((confirm) => !!confirm),
untilDestroyed(this)
).subscribe({
next: () => {
console.info('New Settings confirmed');
}
});
}
onClickSwitchTheme(): void {

View File

@ -13,6 +13,7 @@ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {FlexLayoutModule} from '@angular/flex-layout';
import {TranslateModule} from '@ngx-translate/core';
import {ProfileSettingsModule} from '@shared/modules/profile-settings/profile-settings.module';
import {TutorialDialogModule} from '@shared/modules/tutorial-dialog/tutorial-dialog.module';
@NgModule({
declarations: [
@ -33,6 +34,7 @@ import {ProfileSettingsModule} from '@shared/modules/profile-settings/profile-se
NbUserModule,
NbContextMenuModule,
ProfileSettingsModule,
TutorialDialogModule
],
providers: [
]

View File

@ -9,6 +9,10 @@
@import './overrides';
@import './variables';
// loading glide
@import "~@glidejs/glide/src/assets/sass/glide.core";
@import "~@glidejs/glide/src/assets/sass/glide.theme";
* {
font-family: Roboto, "Helvetica Neue", sans-serif;
}

View File

@ -20,6 +20,7 @@
"action.complete": "Fertig",
"action.disable": "Deaktivieren",
"action.enable": "Aktivieren",
"action.close": "Schließen",
"action.yes": "Ja",
"action.no": "Nein",
"username": "Nutzername",
@ -87,6 +88,23 @@
}
}
},
"tutorial": {
"header": "Erste Schritte mit C4PO",
"carousel": {
"project_overview": "Die Projektübersicht gibt Ihnen einen Überblick über alle Ihre aktuellen Projekte.\nHier können Sie neue erstellen, bestehende bearbeiten oder löschen oder nach einem bestimmten Projekt filtern.\nSehen Sie den aktuellen Stand Ihrer Projekte sowie den Fortschritt zusammen mit einigen zusätzlichen Informationen wie Name, Kunde, Tester und wann es erstellt wurde.",
"project_overview_filtered": "Das Filtern in der Projektübersicht kann Ihnen helfen, das/die gesuchte(n) Projekt(e) zu finden.\nGeben Sie bestimmte Schlüsselwörter wie den Titel eines Projekts oder einen speziellen Status wie „Benötigt weitere Informationen“ ein oder suchen Sie nach einem wichtigen Kunden.",
"create_edit_project": "Erstellen Sie ein neues oder ein bestehendes Projekt, geben Sie ihm einen Titel und einen Kundennamen, weisen Sie einen Tester zu und schreiben Sie eine Zusammenfassung für den Pentest (nur im Bearbeitungsmodus verfügbar).\nDarüber hinaus können Sie auch einen bestimmten Status für das Projekt auswählen, um anzuzeigen, ob der Pentest derzeit „in Arbeit“ ist oder darauf wartet, dass der Kunde den Bericht überprüft.",
"userprofile": "Ändern Sie Ihre Einstellungen.\nEgal, ob Sie nur die Sprache der Anwendung auswählen oder Ihr Passwort ändern.",
"category&objective_overview": "Sehen Sie sich hier jedes Ziel jeder Kategorie an.\nDerselbe Inhalt ist auch im OWASP Web Testing Guide enthalten.\nSie können sich einen guten Überblick über alle Ziele verschaffen, die in einer bestimmten Kategorie enthalten sind, sehen, wie viele Ergebnisse und Kommentare hinzugefügt wurden, und sogar bestimmte Ziele deaktivieren, was zur Folge hat, dass sie nicht in den Bericht aufgenommen werden.",
"objective_info": "Lesen Sie die wichtigsten Informationen zum gewählten Ziel.\nZu diesen Informationen gehört, was am Ziel zu tun ist, welche Probleme am häufigsten auftreten und wie Sie sie ausnutzen können.",
"objective_finding_overview": "Sehen Sie sich alle Funde an, die sich auf das ausgewählte Ziel beziehen.\nSie können den Titel, den Schweregrad, einen Teil der Beschreibung und die Auswirkung des Befundes sehen.\nDarüber hinaus können Sie einen bestimmten Befund auch bearbeiten oder sogar löschen.",
"create_edit_finding": "Bearbeiten oder erstellen Sie neue Funde für das Ziel.\nDokumentieren Sie hier den Titel, die Beschreibung, die betroffenen Anwendungsteile, die betroffenen URLs oder APIs und eine Schweregradbewertung zusammen mit Reproduktionsschritten und einem Abhilfevorschlag.\nSie können Befunde erst erstellen, wenn Sie den Timer gestartet haben, damit Ihre Arbeit nachverfolgt wird.",
"objective_comment_overview": "Sehen Sie sich alle Kommentare an, die sich auf das ausgewählte Ziel beziehen.\nSie können den Titel und einen Teil der Beschreibung des Kommentars sehen.\nDarüber hinaus können Sie einen bestimmten Kommentar auch bearbeiten oder sogar löschen.",
"create_edit_comment": "Bearbeiten oder erstellen Sie neue Kommentare für das Ziel.\nDokumentieren Sie hier den Titel und eine Beschreibung.\nSie können Kommentare erst erstellen, wenn Sie den Timer gestartet haben, damit Ihre Arbeit nachverfolgt wird.",
"generate_report": "Generieren und exportieren Sie Ihren Bericht. Sie können den Namen und die Version Ihres Projekts sowie einige Statistiken darüber sehen, wie viele Ihrer Ziele abgeschlossen, in Bearbeitung, pausiert, nicht gestartet oder deaktiviert sind.\nNur Ihre abgeschlossenen Ziele werden in den Abschlussbericht aufgenommen.\nStellen Sie vor dem Exportieren sicher, dass Sie die richtige Sprache für Ihren Bericht auswählen.",
"report": "Laden Sie Ihren generierten Bericht als PDF herunter und senden Sie ihn direkt an den Kunden.\nDer Bericht enthält alle Informationen, die Sie in der C4PO-Anwendung eingegeben haben.\nDer Bericht besteht aus einem Deckblatt, einem Inhaltsverzeichnis, dem Stand der Vertraulichkeit, einer Zusammenfassung, technischen Details zu den Ergebnissen sowie Kommentaren und Anhängen."
}
},
"state": {
"new": "Neu",
"needs_more_info": "Benötigt mehr Informationen",
@ -203,7 +221,7 @@
"title.label": "Fundtitel",
"description.label": "Beschreibung des Funds",
"impact.label": "Auswirkung auf Anwendung",
"affectedUrls.label": "Betroffene URL's",
"affectedUrls.label": "Betroffene URL's / API's",
"reproduction.label": "Reproduktionsschritte",
"mitigation.label": "Minderungsvorschlag",
"no.findings": "Keine Funde verfügbar",

View File

@ -20,6 +20,7 @@
"action.complete": "Complete",
"action.disable": "Deactivate",
"action.enable": "Activate",
"action.close": "Close",
"action.yes": "Yes",
"action.no": "No",
"username": "Username",
@ -87,6 +88,23 @@
}
}
},
"tutorial": {
"header": "Getting started with C4PO",
"carousel": {
"project_overview": "The Project Overview gives you a rundown of all your current projects. \nYou can create new ones, edit or delete existing ones or filter for an specific project here. \nLook up the current state of your projects as well as the progress together with some additional information like name, client, tester and when it was created.",
"project_overview_filtered": "Filtering through the Project Overview can help you to find the project(s) you are looking for. \nEnter specific keywords like the title of a project, a special state like 'Needs More Info or look for an important client.",
"create_edit_project": "Create a new project or an existing one and give it a title, client name, assign a tester and write a summary for the pentest (only available in edit mode). \nIn addition to that you can also select a specific state for the project to show if the pentest is currently 'work in progress' or waits for the customer to review the report.",
"userprofile": "Change your settings. \nWeather it's just selecting the language of the application or changing your password.",
"category&objective_overview": "View every objective of every category here. \nThe same content is also included in the OWASP Web Testing Guide. \nYou can get a good overview of all the objectives that are included in a specific category, see how many findings and comments have been added and even deactivate specific ones that you will result in them not being included in the report.",
"objective_info": "Read the most important information in regards to the selected objective. \nThis information includes what has to be done in the objective and what are the most common issue as well as how you could exploit them.",
"objective_finding_overview": "See all the findings that relate to the selected objective. \nYou can see the title, severity, part of the description and impact of the finding. \nIn addition you can also edit or even delete a specific finding.",
"create_edit_finding": "Edit or create new findings for the objective. \nDocument the title, description, the impacted application parts, affected URL's or API's and a severity rating together with reproduction steps and a mitigation suggestion here. \nYou can only create findings once you have started the timer so that your work will be tracked.",
"objective_comment_overview": "See all the comments that relate to the selected objective. \nYou can see the title and part of the description of the comment. \nIn addition you can also edit or even delete a specific comment.",
"create_edit_comment": "Edit or create new comments for the objective. \nDocument the title and a description here. \nYou can only create comments once you have started the timer so that your work will be tracked.",
"generate_report": "Generate and export your report. You can see your project name and version as well as some statistics about how many of your objectives are completed, in progress, paused, not started or disabled. \nOnly your completed objectives will be included in the final report. \nBefore exporting make sure you select the correct language of you report.",
"report": "Download your generated report as an pdf and send it directly to the customer. \nThe report includes all the information you have entered in the C4PO application. \nThe report consists of a Cover, Table of Contents, State of Confidentiality, Executive Summary, Technical Details for Findings and Comments and Appendencies."
}
},
"state": {
"new": "New",
"needs_more_info": "Needs More Info",
@ -203,7 +221,7 @@
"title.label": "Finding Title",
"description.label": "Description of Finding",
"impact.label": "Impacted Applicationparts",
"affectedUrls.label": "Affected URL's",
"affectedUrls.label": "Affected URL's / API's",
"reproduction.label": "Reproductionsteps",
"mitigation.label": "Suggest Mitigation",
"no.findings": "No findings available",

View File

@ -0,0 +1 @@
<svg enable-background="new 0 0 100 100" height="512" viewBox="0 0 100 100" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m48.3612213 51.6400146c-7.3800049-7.3798828-19.3898926-7.3798828-26.7700195 0l-10.6298828 10.6298829c-7.380127 7.380127-7.380127 19.3901367 0 26.7700195 7.3798828 7.380127 19.3898926 7.380127 26.7698975 0l10.6300049-10.6298828c7.3800048-7.380127 7.3800048-19.3901367-.0000001-26.7700196zm-31.8100586 31.8100586c-4.289917-4.3000488-4.289917-11.2900391 0-15.5900879l10.630127-10.630127c4.2999268-4.2897949 11.2900391-4.2897949 15.5799561 0 4.2999268 4.3000488 4.2999268 11.2900391 0 15.5900879l-10.6199951 10.630127c-4.3000489 4.2900391-11.2900392 4.2900391-15.590088 0z" fill="#3a545f"/><path d="m89.0312653 10.960083c-7.3800049-7.380127-19.3900146-7.380127-26.7700195 0l-10.6199952 10.6298828c-7.3900146 7.380127-7.3900146 19.3898926 0 26.7700195 7.3800049 7.380127 19.3900146 7.380127 26.7700195 0l10.6199951-10.619873c7.3900147-7.3801269 7.3900147-19.3901367.0000001-26.7800293zm-31.8000489 31.8098145c-4.2999268-4.2998047-4.2999268-11.2900391 0-15.5898438l10.6300049-10.6201172c4.2900391-4.2998047 11.2800293-4.2998047 15.5800781 0 4.2999268 4.2900391 4.2999268 11.2900391 0 15.5800781l-10.630127 10.6298828c-4.2899169 4.3000489-11.2799071 4.3000489-15.579956.0000001z" fill="#3a545f"/><path d="m61.9912262 44.710083-17.289917 17.2800293c-1.8500977 1.8498535-4.8400879 1.8498535-6.6900635 0-1.8499756-1.8500977-1.8499756-4.8400879 0-6.6901855l17.2799073-17.289795c1.8500977-1.8400879 4.8500977-1.8400879 6.7000732 0 1.8399658 1.8498536 1.8399658 4.8498536 0 6.6999512z" fill="#ffd25a"/><g fill="#e6e7e8"><path d="m32.9172554 32.9235573c-.4984818.4984818-1.3056526.4980392-1.8036938 0l-6.5115223-6.5115242c-.4980412-.4980412-.4984818-1.305212 0-1.8036919.4984798-.4984818 1.3056507-.4980412 1.8036919 0l6.5115242 6.5115223c.4980392.4980412.4984818 1.305212 0 1.8036938z"/><path d="m40.3612823 29.5078201c-.696064.1116238-1.3497353-.3619156-1.4612617-1.0573654l-1.4581108-9.092514c-.1115265-.6954498.3612976-1.349638 1.0573654-1.4612617.696064-.1116238 1.3497353.3619156 1.4612617 1.0573654l1.4581108 9.092514c.1115266.6954498-.3612975 1.349638-1.0573654 1.4612617z"/><path d="m29.5015182 40.3675842c.1116238-.696064-.3619156-1.3497353-1.0573654-1.4612617l-9.092514-1.4581108c-.6954498-.1115265-1.349638.3612976-1.4612617 1.0573654-.1116238.696064.3619156 1.3497353 1.0573654 1.4612617l9.092514 1.4581108c.6954498.1115265 1.349638-.3612976 1.4612617-1.0573654z"/><path d="m67.077713 67.0840149c.4984818-.4984818 1.3056488-.4980469 1.803688 0l6.511528 6.5115204c.4980392.4980392.4984818 1.3052139 0 1.8036957s-1.3056564.4980392-1.8036957 0l-6.5115204-6.511528c-.4980468-.4980393-.4984816-1.3052064.0000001-1.8036881z"/><path d="m59.6336823 70.4997482c.696064-.1116257 1.3497353.3619156 1.4612617 1.0573654l1.4581108 9.092514c.1115265.6954498-.3612976 1.3496399-1.0573654 1.4612579-.696064.1116257-1.3497353-.361908-1.4612617-1.0573654l-1.4581108-9.0925064c-.1115266-.6954574.3612975-1.3496398 1.0573654-1.4612655z"/><path d="m70.4934464 59.6399841c-.1116257.696064.3619156 1.3497353 1.0573654 1.4612617l9.092514 1.4581108c.6954498.1115265 1.3496399-.3612976 1.4612579-1.0573654.1116257-.696064-.361908-1.3497353-1.0573654-1.4612617l-9.0925064-1.4581108c-.6954574-.1115265-1.3496399.3612976-1.4612655 1.0573654z"/></g></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

View File

@ -135,7 +135,7 @@
<button nbButton size="small"
class="dialog-button"
(click)="onClickCancel()">
{{ 'global.action.exit' | translate }}
{{ 'global.action.close' | translate }}
</button>
</nb-card-footer>
</nb-card>

View File

@ -0,0 +1,55 @@
export class ImageSliderContent {
source: string;
translationText: string;
}
export const CONTENT_IMAGES: ImageSliderContent[] = [
{
source: '../../../assets/images/tutorial/views/1_Project_Overview.png',
translationText: 'tutorial.carousel.project_overview'
},
{
source: '../../../assets/images/tutorial/views/2_Project_Overview_Filter.png',
translationText: 'tutorial.carousel.project_overview_filtered'
},
{
source: '../../../assets/images/tutorial/views/4_Create_Edit_Projectstates.png',
translationText: 'tutorial.carousel.create_edit_project'
},
{
source: '../../../assets/images/tutorial/views/5_Userprofile.png',
translationText: 'tutorial.carousel.userprofile'
},
{
source: '../../../assets/images/tutorial/views/6_Category_&_Objective_Overview.png',
translationText: 'tutorial.carousel.category&objective_overview'
},
{
source: '../../../assets/images/tutorial/views/7_Objective_Info.png',
translationText: 'tutorial.carousel.objective_info'
},
{
source: '../../../assets/images/tutorial/views/8_Objective_Finding_Overview.png',
translationText: 'tutorial.carousel.objective_finding_overview'
},
{
source: '../../../assets/images/tutorial/views/9_Create_Edit_Finding.png',
translationText: 'tutorial.carousel.create_edit_finding'
},
{
source: '../../../assets/images/tutorial/views/10_Objective_Comment_Overview.png',
translationText: 'tutorial.carousel.objective_comment_overview'
},
{
source: '../../../assets/images/tutorial/views/11_Create_Edit_Comment.png',
translationText: 'tutorial.carousel.create_edit_comment'
},
{
source: '../../../assets/images/tutorial/views/12_Generate_Report.png',
translationText: 'tutorial.carousel.generate_report'
},
{
source: '../../../assets/images/tutorial/views/13_Report.png',
translationText: 'tutorial.carousel.report'
},
];

View File

@ -0,0 +1,56 @@
<nb-card accent="control" status="info" class="profile-setting-dialog">
<nb-card-header fxLayoutAlign="start center" class="dialog-header">
<fa-icon [icon]="fa.faJournalWhills"
class="header-icon fa-lg">
</fa-icon>
<span class="header-text"> {{ 'tutorial.header' | translate }} </span>
</nb-card-header>
<nb-card-body class="dialog-body">
<div fxLayout="column" fxLayoutGap="2rem" fxLayoutAlign="center center">
<div class="info-slideshow">
<div *ngIf="images?.length > 0; else defaultImage">
<!--ToDo: Add info slideshow-->
<ngx-glide id="carousel"
type="carousel"
perView="1"
autoplay="4000"
animationDuration="2000"
[arrowLeftTemplate]="arrowLeft"
[arrowRightTemplate]="arrowRight">
<ng-template #arrowLeft>
<div class="left-arrow">
<fa-icon [icon]="fa.faArrowLeft"></fa-icon>
</div>
</ng-template>
<ng-template #arrowRight>
<div class="right-arrow">
<fa-icon [icon]="fa.faArrowRight"></fa-icon>
</div>
</ng-template>
<div *ngFor="let image of images"
fxLayout="column"
fxLayoutAlign="space-evenly center">
<div class="image-text">
{{image.translationText | translate}}
</div>
<div class="image"
fxLayoutAlign="center">
<img [src]="image.source" onerror="this.src=FALLBACK_IMAGE" alt="tutorial-img">
</div>
</div>
</ngx-glide>
</div>
<ng-template #defaultImage>
<div class="default-image"></div>
</ng-template>
</div>
</div>
</nb-card-body>
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
<button nbButton size="small"
class="dialog-button"
(click)="onClickCancel()">
{{ 'global.action.close' | translate }}
</button>
</nb-card-footer>
</nb-card>

View File

@ -0,0 +1,83 @@
@import "../../../assets/@theme/styles/_dialog.scss";
@import '../../../assets/@theme/styles/themes';
$control-button-margin: 1.5rem;
$control-button-size: 3.5rem;
.profile-setting-dialog {
width: 65.25rem !important;
height: 58rem;
.dialog-header {
height: 8vh;
.header-text {
font-size: 1.5rem;
padding-left: 1rem;
}
}
.dialog-body {
//overflow: hidden!important;
.info-slideshow {
max-width: 100%;
max-height: 100%;
.image-text {
font-size: 1.2rem;
padding-top: 1.25rem;
// padding-bottom: 2.25rem;
max-width: 80%;
text-align: center;
// Allows \n in translation file for line breaks
white-space: pre-line;
}
.image {
img {
max-width: 100%;
}
}
.default-image {
background-image: url("../../../assets/images/tutorial/IMAGE_404.png");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
/*min-width: 100%;
min-height: 100vh;*/
position: inherit;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.left-arrow,
.right-arrow {
display: block;
top: calc(55% - (#{$control-button-size} / 2));
position: absolute;
font-size: 2rem;
color: nb-theme(color-basic-transparent-focus);
cursor: pointer;
z-index: 1000;
&:hover {
color: nb-theme(color-info-default);
}
}
.left-arrow {
left: $control-button-margin;
}
.right-arrow {
right: $control-button-margin;
}
}
}
}

View File

@ -0,0 +1,61 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TutorialDialogComponent } from './tutorial-dialog.component';
import {NgxGlideModule} from 'ngx-glide';
import {DialogService} from '@shared/services/dialog-service/dialog.service';
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
import {NbDialogRef, NbFormFieldModule} from '@nebular/theme';
import {createSpyObj} from '@shared/modules/project-dialog/project-dialog.component.spec';
import {ReactiveFormsModule} from '@angular/forms';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {ThemeModule} from '@assets/@theme/theme.module';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from '../../../app/common-app.module';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {HttpClientTestingModule} from '@angular/common/http/testing';
describe('TutorialDialogComponent', () => {
let component: TutorialDialogComponent;
let fixture: ComponentFixture<TutorialDialogComponent>;
beforeEach(async () => {
const dialogSpy = createSpyObj('NbDialogRef', ['close']);
await TestBed.configureTestingModule({
declarations: [
TutorialDialogComponent
],
imports: [
NgxGlideModule,
NbFormFieldModule,
ReactiveFormsModule,
BrowserAnimationsModule,
ThemeModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
HttpClientModule,
HttpClientTestingModule
],
providers: [
{provide: DialogService, useClass: DialogServiceMock},
{provide: NbDialogRef, useValue: dialogSpy}
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TutorialDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,27 @@
import {Component, OnInit} from '@angular/core';
import {NbDialogRef} from '@nebular/theme';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {CONTENT_IMAGES, ImageSliderContent} from '@shared/modules/tutorial-dialog/tutorial-content';
@Component({
selector: 'app-tutorial-dialog',
templateUrl: './tutorial-dialog.component.html',
styleUrls: ['./tutorial-dialog.component.scss']
})
export class TutorialDialogComponent implements OnInit {
// HTML only
readonly fa = FA;
readonly FALLBACK_IMAGE = '../../../assets/images/tutorial/IMAGE_404.png';
images: Array<ImageSliderContent> = CONTENT_IMAGES;
constructor(protected dialogRef: NbDialogRef<any>) { }
ngOnInit(): void {
}
onClickCancel(): void {
this.dialogRef.close();
}
}

View File

@ -0,0 +1,27 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import {TutorialDialogComponent} from '@shared/modules/tutorial-dialog/tutorial-dialog.component';
import {NbButtonModule, NbCardModule} from '@nebular/theme';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {TranslateModule} from '@ngx-translate/core';
import {FlexModule} from '@angular/flex-layout';
import {NgxGlideModule} from 'ngx-glide';
@NgModule({
declarations: [
TutorialDialogComponent
],
imports: [
CommonModule,
NbCardModule,
FontAwesomeModule,
TranslateModule,
NbButtonModule,
FlexModule,
NgxGlideModule
],
exports: [
TutorialDialogComponent
]
})
export class TutorialDialogModule { }

View File

@ -7,7 +7,7 @@ import {UserService} from '@shared/services/user-service/user.service';
import {inject, TestBed} from '@angular/core/testing';
import {HttpClient} from '@angular/common/http';
import {HttpLoaderFactory} from '../../app/common-app.module';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {TranslateLoader, TranslateModule, TranslateService} from '@ngx-translate/core';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {KeycloakService} from 'keycloak-angular';
@ -21,7 +21,6 @@ const DESIRED_STORE_STATE_SESSION: SessionStateModel = {
describe('DateTimeFormatPipe', () => {
let pipe: DateTimeFormatPipe;
let store: Store;
// tslint:disable-next-line:prefer-const
let dateAndNumberFormat: NumberAndDateFormatSystem;
@ -43,18 +42,14 @@ describe('DateTimeFormatPipe', () => {
],
providers: [
{provide: UserService},
{provide: KeycloakService}
{provide: KeycloakService},
{provide: TranslateService}
]
}).compileComponents();
});
beforeEach(inject([Store], (inStore: Store) => {
store = inStore;
store.reset({
...store.snapshot(),
[SESSION_STATE_NAME]: DESIRED_STORE_STATE_SESSION
});
pipe = new DateTimeFormatPipe(inStore);
beforeEach(inject([Store], (translateService: TranslateService) => {
pipe = new DateTimeFormatPipe(translateService);
})
);

View File

@ -1,6 +1,5 @@
import {Pipe, PipeTransform} from '@angular/core';
import {formatDate} from '@angular/common';
import {Store} from '@ngxs/store';
import {CustomPipe} from '@shared/models/custom-pipe.mode';
import {TranslateService} from '@ngx-translate/core';
@ -10,7 +9,7 @@ import {TranslateService} from '@ngx-translate/core';
})
export class DateTimeFormatPipe implements PipeTransform {
constructor(private store: Store, private translateService: TranslateService) {
constructor(private translateService: TranslateService) {
}
/**

View File

@ -124,7 +124,7 @@
}
],
"url": {
"raw": "http://localhost:8444/reports/575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2/pdf",
"raw": "http://localhost:8444/reports/575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2/pdf/en-US",
"protocol": "http",
"host": [
"localhost"
@ -133,61 +133,8 @@
"path": [
"reports",
"575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2",
"pdf"
]
}
},
"response": []
},
{
"name": "getReportCSVforProjectById",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"value": "text/html",
"type": "text"
}
],
"url": {
"raw": "http://localhost:8444/reports/195809ed-9722-4ad5-a84b-0099a9a01652/csv",
"protocol": "http",
"host": [
"localhost"
],
"port": "8444",
"path": [
"reports",
"195809ed-9722-4ad5-a84b-0099a9a01652",
"csv"
]
}
},
"response": []
},
{
"name": "getReportHTMLforProjectById",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"value": "text/csv",
"type": "text"
}
],
"url": {
"raw": "http://localhost:8444/reports/195809ed-9722-4ad5-a84b-0099a9a01652/html",
"protocol": "http",
"host": [
"localhost"
],
"port": "8444",
"path": [
"reports",
"195809ed-9722-4ad5-a84b-0099a9a01652",
"html"
"pdf",
"en-US"
]
}
},