diff --git a/src/app/appmarket/appinstance/appinstance/appinstance.component.html b/src/app/appmarket/appinstance/appinstance/appinstance.component.html index bd80e664df98172ae6bf8299140d951d9ffe6219..4991bc5708e6ebd3f124c9e7ccfbd92b9ff6a952 100644 --- a/src/app/appmarket/appinstance/appinstance/appinstance.component.html +++ b/src/app/appmarket/appinstance/appinstance/appinstance.component.html @@ -49,7 +49,7 @@ </div> </div> <div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 container-bottom-right"> - <h3><i style="color: #337ab7;">{{ translateState(appInstanceStatus?.state) }}</i></h3> + <h3><em style="color: #337ab7;">{{ translateState(appInstanceStatus?.state) }}</em></h3> </div> </div> <hr> diff --git a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.css b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.css index a9cf4751c33cdf26035425f5c002765066c073a6..d40837a09c5ed4989c745bf1de78b6abeb1e9746 100644 --- a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.css +++ b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.css @@ -114,3 +114,7 @@ .no-bullet-list { list-style:none; } + +.formio-editor-read-only-content { + white-space: pre-wrap; +} diff --git a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html index 808fdb621394375db31342aa1129e744320bcf19..b2077c3a127c356594da66d6c42b79bb2eaf48f7 100644 --- a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html +++ b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html @@ -31,7 +31,8 @@ 'has-success': appName.valid && (appName.dirty || appName.touched)}"> <label for="appName" class="control-label">{{'APPS_WIZARD.NAME_LABEL' | translate}} *</label> <br> - <input type="text" id="appName" class="form-control" required [(ngModel)]="applicationDTO.applicationBase.name" + <input type="text" id="appName" class="form-control" required + [(ngModel)]="applicationDTO.applicationBase.name" [maxLength]="30" pattern="^[a-zA-Z0-9- ]+$" name="appName" #appName="ngModel" tooltip="{{'APPS_WIZARD.NAME_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions"> @@ -41,7 +42,8 @@ 'has-success': version.valid && (version.dirty || version.touched)}"> <label for="appVersion" class="control-label">{{'APPS_WIZARD.VERSION_LABEL' | translate}} *</label> <br> - <input type="text" id="appVersion" class="form-control" required [(ngModel)]="applicationDTO.application.version" + <input type="text" id="appVersion" class="form-control" required + [(ngModel)]="applicationDTO.application.version" name="version" #version="ngModel" tooltip="{{'APPS_WIZARD.VERSION_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions"> </div> @@ -50,7 +52,8 @@ 'has-success': license.valid && (license.dirty || license.touched)}"> <label for="appLicense" class="control-label">{{'APPS_WIZARD.LICENSE_LABEL' | translate}}</label> <br> - <input type="text" id="appLicense" class="form-control" [(ngModel)]="applicationDTO.applicationBase.license" name="license" + <input type="text" id="appLicense" class="form-control" + [(ngModel)]="applicationDTO.applicationBase.license" name="license" #license="ngModel" tooltip="{{'APPS_WIZARD.LICENSE_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions"> </div> @@ -61,7 +64,8 @@ class="control-label">{{'APPS_WIZARD.LICENSE_URL_LABEL' | translate}}</label> <br> <input type="url" id="appLicenseUrl" class="form-control" [pattern]="urlPattern" - [(ngModel)]="applicationDTO.applicationBase.licenseUrl" name="licenseUrl" #licenseUrl="ngModel" + [(ngModel)]="applicationDTO.applicationBase.licenseUrl" name="licenseUrl" + #licenseUrl="ngModel" tooltip="{{'APPS_WIZARD.LICENSE_URL_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions" placeholder="e.g. https://opensource.org/licenses/MIT"> </div> @@ -73,7 +77,8 @@ <br> <input type="url" id="wwwUrl" class="form-control" [pattern]="urlPattern" name="wwwUrl" #wwwUrl="ngModel" tooltip="{{'APPS_WIZARD.PROJECT_WEBSITE_TOOLTIP' | translate}}" - [display]="true" [options]="defaultTooltipOptions" [(ngModel)]="applicationDTO.applicationBase.wwwUrl"> + [display]="true" [options]="defaultTooltipOptions" + [(ngModel)]="applicationDTO.applicationBase.wwwUrl"> </div> <div class="form-group form-group-sm" [ngClass]="{'has-error': sourceUrl.invalid && (sourceUrl.dirty || sourceUrl.touched), @@ -82,7 +87,8 @@ <br> <input type="url" id="sourceUrl" class="form-control" [pattern]="urlPattern" name="sourceUrl" #sourceUrl="ngModel" tooltip="{{'APPS_WIZARD.SOURCE_CODE_TOOLTIP' | translate}}" - [display]="true" [options]="defaultTooltipOptions" [(ngModel)]="applicationDTO.applicationBase.sourceUrl"> + [display]="true" [options]="defaultTooltipOptions" + [(ngModel)]="applicationDTO.applicationBase.sourceUrl"> </div> <div class="form-group form-group-sm" [ngClass]="{'has-error': issuesUrl.invalid && (issuesUrl.dirty || issuesUrl.touched), @@ -92,7 +98,8 @@ <br> <input type="url" id="issuesUrl" class="form-control" [pattern]="urlPattern" name="issuesUrl" #issuesUrl="ngModel" tooltip="{{'APPS_WIZARD.PROJECT_ISSUES_TOOLTIP' | translate}}" - [display]="true" [options]="defaultTooltipOptions" [(ngModel)]="applicationDTO.applicationBase.issuesUrl"> + [display]="true" [options]="defaultTooltipOptions" + [(ngModel)]="applicationDTO.applicationBase.issuesUrl"> </div> <div class="form-group form-group-sm" [ngClass]="{'has-error': nmaasDocumentationUrl.invalid && (nmaasDocumentationUrl.dirty || nmaasDocumentationUrl.touched), @@ -103,7 +110,8 @@ <input type="url" id="nmaasDocumentationUrl" class="form-control" [pattern]="urlPattern" name="nmaasDocumentationUrl" #nmaasDocumentationUrl="ngModel" tooltip="{{'APPS_WIZARD.PROJECT_NMAAS_DOCUMENTATION_TOOLTIP' | translate}}" [display]="true" - [options]="defaultTooltipOptions" [(ngModel)]="applicationDTO.applicationBase.nmaasDocumentationUrl"> + [options]="defaultTooltipOptions" + [(ngModel)]="applicationDTO.applicationBase.nmaasDocumentationUrl"> </div> <div class="form-group form-group-sm"> <label for="tags" class="control-label">{{'APPS_WIZARD.TAGS_LABEL' | translate}} * </label> @@ -280,7 +288,8 @@ <br> <input type="text" class="form-control" id="kubernetesTemplateChartName" name="kubernetesTemplateChartName" #kubernetesTemplateChartName="ngModel" - [(ngModel)]="applicationDTO.application.appDeploymentSpec.kubernetesTemplate.chart.name" required + [(ngModel)]="applicationDTO.application.appDeploymentSpec.kubernetesTemplate.chart.name" + required tooltip="{{'APPS_WIZARD.CHART_NAME_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions"> </div> @@ -290,7 +299,8 @@ <br> <input type="text" class="form-control" id="kubernetesTemplateChartVersion" name="kubernetesTemplateChartVersion" - [(ngModel)]="applicationDTO.application.appDeploymentSpec.kubernetesTemplate.chart.version" required + [(ngModel)]="applicationDTO.application.appDeploymentSpec.kubernetesTemplate.chart.version" + required tooltip="{{'APPS_WIZARD.CHART_VERSION_TOOLTIP' | translate}}" [display]="true" [options]="defaultTooltipOptions"> </div> @@ -350,7 +360,8 @@ <div class="form-group form-group-sm"> <h4>{{'APPS_WIZARD.STORAGE_VOLUMES' | translate}}</h4> <ul *ngIf="applicationDTO.application.appDeploymentSpec.storageVolumes"> - <li *ngFor="let s of applicationDTO.application.appDeploymentSpec.storageVolumes; let i=index" class="no-bullet-list"> + <li *ngFor="let s of applicationDTO.application.appDeploymentSpec.storageVolumes; let i=index" + class="no-bullet-list"> <app-storage-volume-edit [storageVolume]="s" [id]="i" [storageVolumeTypes]="storageVolumeTypeOptions()" (output)="removeStorageVolume($event)"></app-storage-volume-edit> @@ -363,7 +374,8 @@ <div class="form-group form-group-sm"> <h4>{{'APPS_WIZARD.ACCESS_METHODS' | translate}}</h4> <ul *ngIf="applicationDTO.application.appDeploymentSpec.accessMethods"> - <li *ngFor="let a of applicationDTO.application.appDeploymentSpec.accessMethods; let i=index" class="no-bullet-list"> + <li *ngFor="let a of applicationDTO.application.appDeploymentSpec.accessMethods; let i=index" + class="no-bullet-list"> <app-access-method-edit [accessMethod]="a" [id]="i" [accessMethodTypes]="accessMethodTypeOptions()" (output)="removeAccessMethod($event)"></app-access-method-edit> @@ -420,6 +432,28 @@ [options]="defaultTooltipOptions"> </div> </div> + <div class="form-group form-group-sm"> + <label for="termsAcceptance" style="text-align: left; padding-left: 0;" + class="col-sm-2 control-label">{{'APPS_WIZARD.TERMS_ACCEPTANCE_LABEL' | translate}}</label> + <div class="col-sm-10"> + <input type="checkbox" id="termsAcceptance" name="termsAcceptance" + (change)="changeTermsAcceptanceInForms()" + [defaultChecked]="hasAlreadyBasicAuth()" [(ngModel)]="termsAcceptance" + tooltip="{{'APPS_WIZARD.TERMS_ACCEPTANCE_TOOLTIP' | translate}}" [display]="true" + [options]="defaultTooltipOptions"> + </div> + </div> + <div class="form-group form-group-sm" *ngIf="termsAcceptance"> + <label for="termsContent" style="text-align: left; padding-left: 0;" + class="col-sm-2 control-label">{{'APPS_WIZARD.TERMS_CONTENT_LABEL' | translate}}</label> + <div class="col-sm-10"> + <textarea id="termsContent" name="termsContent" class="form-control" rows="7" + [(ngModel)]="termsContent" + tooltip="{{'APPS_WIZARD.TERMS_CONTENT_TOOLTIP' | translate}}" [display]="true" + [options]="defaultTooltipOptions"></textarea> + <button role="button" class="btn btn-success" (click)="changeTermsAcceptanceInForms()">{{'APPS_WIZARD.TERMS_CONTENT_BUTTON' | translate}}</button> + </div> + </div> <div *ngIf="applicationDTO.application.appConfigurationSpec.configFileRepositoryRequired"> <div *ngFor="let configTemplate of configFileTemplates; let i=index"> <div class="form-group form-group-sm" [ngClass]="{'has-error': configFileName.invalid && (configFileName.dirty || configFileName.touched), @@ -490,7 +524,8 @@ <div class="panel-heading">{{'APPS_WIZARD.UPDATE_CONFIG_WIZARD_TEMPLATE_LABEL' | translate}}</div> <div class="panel-body"> <div class="form-group form-group-sm" style="padding-bottom: 5vh;"> - <label for="addConfigUpdate" style="text-align: left; padding-left: 0; font-size: 12px" class="col-sm-2 control-label"> + <label for="addConfigUpdate" style="text-align: left; padding-left: 0; font-size: 12px" + class="col-sm-2 control-label"> {{'APPS_WIZARD.ADD_CONFIG_UPDATE_TEMPLATE_LABEL' | translate}} </label> <div class="col-sm-10"> diff --git a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts index 943debfe23d15e884819807efa29cca3290ddbda..aaa81b975e4d84f444964c5d7fe7c4b1181e0543 100644 --- a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts +++ b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts @@ -54,6 +54,8 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit { public configFileTemplates: ConfigFileTemplate[] = []; public addConfigUpdate = false; public basicAuth = false; + public termsAcceptance = false; + public termsContent: string = undefined; public selectedLanguages: string[] = []; public languages: SelectItem[] = []; public formDisplayChange = true; @@ -256,10 +258,10 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit { public uploadLogo(id: number) { if (this.isInMode(ComponentMode.EDIT) && this.logo[0] == null) { - this.appImagesService.deleteLogo(id).subscribe(() => console.debug('Logo deleted')); + this.appImagesService.deleteLogo(id).subscribe(() => console.log('Logo deleted')); } if (this.logo[0] != null) { - this.appsService.uploadAppLogo(id, this.logo[0]).subscribe(() => console.debug('Logo uploaded')); + this.appsService.uploadAppLogo(id, this.logo[0]).subscribe(() => console.log('Logo uploaded')); } } @@ -275,7 +277,7 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit { private uploadScreenshots(id: number) { for (const screenshot of this.screenshots) { - this.appsService.uploadScreenshot(id, screenshot).subscribe(() => console.debug('Screenshot uploaded')); + this.appsService.uploadScreenshot(id, screenshot).subscribe(() => console.log('Screenshot uploaded')); } } @@ -470,6 +472,63 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit { }, 1); } + public changeTermsAcceptanceInForms() { + this.formDisplayChange = false; + this.handleTermsAcceptance(); + setTimeout(() => { + this.formDisplayChange = true + }, 1); + } + + public handleTermsAcceptance(): void { + if (!this.applicationDTO.application.appConfigurationSpec.configFileRepositoryRequired + && this.applicationDTO.application.configWizardTemplate == null) { + this.applicationDTO.application.configWizardTemplate = new ConfigWizardTemplate(); + this.applicationDTO.application.configWizardTemplate.template = this.configTemplateService.getConfigTemplate(); + } + if (this.termsAcceptance) { + if (this.hasAlreadyTermsAcceptance()) { + this.removeTermsAcceptance(); + } + this.addTermsAcceptance(); + } else { + this.removeTermsAcceptance(); + } + } + + public addTermsAcceptance(): void { + const config = this.getNestedObject( + this.applicationDTO.application.configWizardTemplate.template, + ['components', 0, 'components', 0, 'components'] + ); + if (config != null) { + config.unshift(this.configTemplateService.getTermsAcceptance(this.termsContent || 'Terms unavailable')); + } + } + + public removeTermsAcceptance(): void { + const config = this.getNestedObject( + this.applicationDTO.application.configWizardTemplate.template, + ['components', 0, 'components', 0, 'components'] + ); + if (config != null) { + const index = config.findIndex(val => val.key === 'termsAcceptance'); + config.splice(index, 1); + } + // this.applicationDTO.application.configWizardTemplate.template.components = + // this.applicationDTO.application.configWizardTemplate.template.components.filter(val => val.key !== 'termsAcceptance'); + } + + public hasAlreadyTermsAcceptance(): boolean { + if (this.applicationDTO.application.configWizardTemplate == null) { + return false; + } + const config: string = JSON.stringify(this.applicationDTO.application.configWizardTemplate.template); + return config.search(/termsAcceptance/g) !== -1 + && config.search(/termsContent/g) !== -1 + && config.search(/termsAcceptanceStatement/g) !== -1; + } + public changeDefaultElementInForms() { this.formDisplayChange = false; this.handleDefaultElement(); diff --git a/src/app/model/app-configuration-spec.ts b/src/app/model/app-configuration-spec.ts index cfcebd48d363a026ea25cdfbcf9f8c4a4540d1c1..9113137713826df08e88e2be81136fdf9b3462c6 100644 --- a/src/app/model/app-configuration-spec.ts +++ b/src/app/model/app-configuration-spec.ts @@ -5,4 +5,5 @@ export class AppConfigurationSpec { public configFileRepositoryRequired = false; public configUpdateEnabled = false; public templates: ConfigFileTemplate[] = []; + public termsAcceptanceRequired = false; } diff --git a/src/app/model/app-configuration.ts b/src/app/model/app-configuration.ts index 30ef0dedbfe65eb9f18412ea2db75aa9236010fb..2fa89d90157ea903ae973c8b811055be8b28845a 100644 --- a/src/app/model/app-configuration.ts +++ b/src/app/model/app-configuration.ts @@ -1,7 +1,7 @@ -export class AppConfiguration{ - public jsonInput:any; - public additionalParameters:any; - public mandatoryParameters:any; - public accessCredentials:any; - public storageSpace:number; -} \ No newline at end of file +export class AppConfiguration { + public jsonInput: any; + public additionalParameters: any; + public mandatoryParameters: any; + public accessCredentials: any; + public storageSpace: number; +} diff --git a/src/app/service/configtemplate.service.ts b/src/app/service/configtemplate.service.ts index f97ea8ceaa32a0d59cb32ea3c095a2aeb12f08fe..8e2ea4b667cb1dd49ab22c8665f04f38dde6ef9d 100644 --- a/src/app/service/configtemplate.service.ts +++ b/src/app/service/configtemplate.service.ts @@ -14,6 +14,8 @@ export class ConfigTemplateService { public basicAuth: any; + public termsAcceptance: any; + constructor(public http: HttpClient) { } public loadConfigTemplate() { @@ -34,6 +36,9 @@ export class ConfigTemplateService { this.http.get('/assets/formio/basicAuth.json') .subscribe(auth => this.basicAuth = auth); + + this.http.get('/assets/formio/termsAcceptance.json') + .subscribe(data => this.termsAcceptance = data); } public getConfigTemplate(): any { @@ -48,6 +53,13 @@ export class ConfigTemplateService { return this.defaultElement; } + public getTermsAcceptance(termsContent: string): any { + let temp = JSON.stringify(this.termsAcceptance); + temp = temp.replace(/"@TERMS_CONTENT"/g, JSON.stringify(termsContent)) + console.log(JSON.parse(temp)) + return JSON.parse(temp) + } + public getBasicAuth(appName: string): any { let temp = JSON.stringify(this.basicAuth); temp = temp.replace(/@APP_NAME/g, appName); diff --git a/src/assets/formio/termsAcceptance.json b/src/assets/formio/termsAcceptance.json new file mode 100644 index 0000000000000000000000000000000000000000..f8d0c0a11c4632db777805e2079f2238804af88f --- /dev/null +++ b/src/assets/formio/termsAcceptance.json @@ -0,0 +1,43 @@ +{ + "label": "Terms acceptance", + "hideLabel": true, + "tableView": true, + "type": "container", + "input": true, + "tab": 0, + "key": "termsAcceptance", + "display": "form", + "components": [ + { + "label": "Terms", + "autoExpand": false, + "spellcheck": false, + "disabled": true, + "tableView": true, + "persistent": false, + "key": "termsContent", + "attributes": { + "style": "white-space: pre-wrap;" + }, + "type": "textarea", + "inputFormat": "plain", + "rows": 5, + "input": true, + "defaultValue": "@TERMS_CONTENT" + }, + { + "label": "Accept Terms", + "placeholder": "Yes", + "tableView": true, + "persistent": false, + "validate": { + "required": true, + "pattern": "(yes)|(YES)|(Yes)", + "customMessage": "You must accept application terms - enter \"Yes\" to accept." + }, + "key": "termsAcceptanceStatement", + "type": "textfield", + "input": true + } + ] +}