Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): add feature to import pipeline with yaml from UI #2463

Merged
merged 3 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 11 additions & 2 deletions ui/src/app/service/logout.interceptor.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Injectable} from '@angular/core';
import {TranslateService} from '@ngx-translate/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {ToastService} from '../shared/toast/ToastService';
Expand All @@ -9,7 +10,11 @@ import 'rxjs/add/observable/throw';
@Injectable()
export class LogoutInterceptor implements HttpInterceptor {

constructor(private _toast: ToastService, private _authStore: AuthentificationStore, private _router: Router) {
constructor(
private _toast: ToastService,
private _authStore: AuthentificationStore,
private _router: Router,
private _translate: TranslateService) {
}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
Expand All @@ -25,7 +30,11 @@ export class LogoutInterceptor implements HttpInterceptor {
if (e.error && e.error.message) {
this._toast.error(e.statusText, e.error.message);
} else {
this._toast.error(e.statusText, JSON.parse(e.message));
try {
this._toast.error(e.statusText, JSON.parse(e.message));
} catch (e) {
this._toast.error(e.statusText, this._translate.instant('common_error'));
}
}
}
return Observable.throw(e);
Expand Down
16 changes: 15 additions & 1 deletion ui/src/app/service/pipeline/pipeline.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {GroupPermission} from '../../model/group.model';
import {Stage} from '../../model/stage.model';
import {Job} from '../../model/job.model';
import {Parameter} from '../../model/parameter.model';
import {HttpClient, HttpParams} from '@angular/common/http';
import {HttpClient, HttpParams, HttpHeaders} from '@angular/common/http';

/**
* Service to access Pipeline from API.
Expand Down Expand Up @@ -49,6 +49,20 @@ export class PipelineService {
return this._http.put<Pipeline>('/project/' + key + '/pipeline/' + oldName, pipeline);
}

/**
* Import a pipeline
* @param key Project unique key
* @param workflow pipelineCode to import
*/
importPipeline(key: string, pipelineCode: string): Observable<Array<string>> {
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'application/x-yaml');
let params = new HttpParams();
params = params.append('format', 'yaml');

return this._http.post<Array<string>>(`/project/${key}/import/pipeline`, pipelineCode, {headers, params});
}

/**
* Delete a pipeline
* @param key Project unique key
Expand Down
9 changes: 9 additions & 0 deletions ui/src/app/service/pipeline/pipeline.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ export class PipelineStore {
this._pipeline.next(cache.delete(pipKey));
}

/**
* Import a pipeline
* @param key Project unique key
* @param workflow pipelineCode to import
*/
importPipeline(key: string, pipelineCode: string): Observable<Array<string>> {
return this._pipelineService.importPipeline(key, pipelineCode);
}

/**
* Create a new pipeline and put it in the store
* @param key Project unique key
Expand Down
33 changes: 33 additions & 0 deletions ui/src/app/shared/button/upload/upload.button.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {EventEmitter, Output, Input, Component} from '@angular/core';

@Component({
selector: 'app-upload-button',
templateUrl: './upload.button.html',
styleUrls: ['./upload.button.scss']
})
export class UploadButtonComponent {

@Input() accept: string;

@Input() size: string;
@Output() event = new EventEmitter<string>();

showConfirmation = false;

constructor() {}

fileEvent(event) {
if (!event || !event.target || !event.target.files || !event.target.files[0]) {
return;
}
let file = event.target.files[0];
let reader = new FileReader();
let that = this;

reader.onloadend = function(e: any) {
that.event.emit(e.target.result);
};

reader.readAsText(file);
}
}
5 changes: 5 additions & 0 deletions ui/src/app/shared/button/upload/upload.button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<input type="file" (change)="fileEvent($event)" class="inputfile" id="embedpollfileinput" [accept]="accept"/>
<label for="embedpollfileinput" class="ui {{size}} button">
<i class="ui upload icon"></i>
Upload
</label>
8 changes: 8 additions & 0 deletions ui/src/app/shared/button/upload/upload.button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.inputfile {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
3 changes: 3 additions & 0 deletions ui/src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {PermissionService} from './permission/permission.service';
import {PermissionListComponent} from './permission/list/permission.list.component';
import {PermissionFormComponent} from './permission/form/permission.form.component';
import {DeleteButtonComponent} from './button/delete/delete.button';
import {UploadButtonComponent} from './button/upload/upload.button.component';
import {ToastService} from './toast/ToastService';
import {BreadcrumbComponent} from './breadcrumb/breadcrumb.component';
import {ActionComponent} from './action/action.component';
Expand Down Expand Up @@ -90,6 +91,7 @@ import {VCSStrategyComponent} from './vcs/vcs.strategy.component';
CommitListComponent,
CutPipe,
DeleteButtonComponent,
UploadButtonComponent,
ForMapPipe,
GroupFormComponent,
HistoryComponent,
Expand Down Expand Up @@ -166,6 +168,7 @@ import {VCSStrategyComponent} from './vcs/vcs.strategy.component';
CommonModule,
CutPipe,
DeleteButtonComponent,
UploadButtonComponent,
DragulaModule,
ForMapPipe,
FormsModule,
Expand Down
38 changes: 38 additions & 0 deletions ui/src/app/views/pipeline/add/pipeline.add.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {TranslateService} from '@ngx-translate/core';
import {ToastService} from '../../../shared/toast/ToastService';
import {ActivatedRoute, Router} from '@angular/router';
import {Project} from '../../../model/project.model';
import {finalize} from 'rxjs/operators';

@Component({
selector: 'app-pipeline-add',
Expand All @@ -18,6 +19,18 @@ export class PipelineAddComponent {
pipelineType: Array<string>;
newPipeline = new Pipeline();

codeMirrorConfig: any;
pipToImport = `# Pipeline example
version: v1.0
name: root
jobs:
- job: run
stage: Stage 1
steps:
- script:
- echo "I'm the first step"
`;

pipelineNamePattern: RegExp = new RegExp('^[a-zA-Z0-9._-]{1,}$');
pipPatternError = false;

Expand All @@ -31,6 +44,13 @@ export class PipelineAddComponent {
this.pipelineType = list.toArray();
this.newPipeline.type = this.pipelineType[0];
});

this.codeMirrorConfig = {
mode: 'text/x-yaml',
lineWrapping: true,
lineNumbers: true,
autoRefresh: true,
};
}

createPipeline(): void {
Expand All @@ -53,4 +73,22 @@ export class PipelineAddComponent {
});

}

goToProject(): void {
this._router.navigate(['/project', this.project.key], {queryParams: {tab: 'pipelines'}});
}

importPipeline() {
this.loadingCreate = true;
this._pipStore.importPipeline(this.project.key, this.pipToImport)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible to add a popup warning when a pipeline with the same name exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forceUpdate deleted

.pipe(finalize(() => this.loadingCreate = false))
.subscribe(() => {
this._toast.success('', this._translate.instant('pipeline_added'));
this.goToProject();
});
}

fileEvent(event) {
this.pipToImport = event;
}
}
54 changes: 53 additions & 1 deletion ui/src/app/views/pipeline/add/pipeline.add.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,45 @@
<div id="AddPipeline">
<div class="ui form">
<h2>{{ 'pipeline_create' | translate }}</h2>

<div class="ui grid">
<div class="ui row">
<div class="one wide column"></div>
<div class="fourteen wide column">
<div class="two ui buttons">
<button class="ui button"
type="button"
[class.active]="!asCode" [class.blue]="!asCode"
(click)="asCode = false">
{{'common_create' | translate}}
</button>
<button class="ui button" type="button" [class.blue]="asCode" [class.active]="asCode" (click)="asCode = true">
{{'common_import' | translate}}
</button>
</div>
</div>
</div>
<ng-container *ngIf="asCode">
<div class="ui row">
<div class="sixteen wide column centered">
<app-upload-button accept=".yml,.yaml" size="large" (event)="fileEvent($event)">
</app-upload-button>
</div>
</div>
<div class="ui row">
<div class="one wide column"></div>
<div class="fourteen wide column">
<div class="ui horizontal divider">
{{'common_or' | translate}}
</div>
</div>
</div>
</ng-container>

<div class="ui row">
<div class="one wide column">
</div>
<div class="fourteen wide column">
<div class="fourteen wide column" *ngIf="!asCode">
<div class="field">
<label>{{'pipeline_name' | translate}}</label>
<input type="text" name="pipname" [(ngModel)]="newPipeline.name">
Expand All @@ -26,6 +61,23 @@ <h2>{{ 'pipeline_create' | translate }}</h2>
</button>
</div>
</div>
<div class="fourteen wide column" *ngIf="asCode">
<div class="field">
<codemirror
name="pipToImport"
[(ngModel)]="pipToImport"
(keydown)="updated = true"
[config]="codeMirrorConfig" #codeMirror>
</codemirror>
</div>
<div class="field">
<button class="ui button" type="button" (click)="goToProject()">{{ 'btn_cancel' | translate }}</button>
<button class="ui right floated green button" type="button" (click)="importPipeline()" *ngIf="asCode"
[disabled]="!pipToImport" [class.loading]="loadingCreate">{{ 'btn_create' | translate }}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions ui/src/app/views/pipeline/add/pipeline.add.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@

h2 {
text-align: center;
} border-color: #202f3c;
}
}
border-color: #202f3c;
}
17 changes: 16 additions & 1 deletion ui/src/app/views/workflow/add/workflow.add.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,18 @@ export class WorkflowAddComponent {
codemirror: CodemirrorComponent;

codeMirrorConfig: any;
wfToImport: string;
wfToImport = `# Example of workflow
name: myWorkflow
version: v1.0
workflow:
myBuild:
pipeline: build
myTest:
depends_on:
- myBuild
when:
- success
pipeline: test`;

updated = false;
loading = false;
Expand Down Expand Up @@ -87,4 +98,8 @@ export class WorkflowAddComponent {
this.goToProject();
});
}

fileEvent(event) {
this.wfToImport = event;
}
}
17 changes: 16 additions & 1 deletion ui/src/app/views/workflow/add/workflow.add.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ <h2>{{ 'workflow_create' | translate }}</h2>
<button class="ui button"
type="button"
[class.active]="!asCode" [class.blue]="!asCode"
[class.disabled]="!project.application_names || !project.application_names.length"
(click)="asCode = false">
{{'common_create' | translate}}
</button>
Expand All @@ -44,6 +43,22 @@ <h2>{{ 'workflow_create' | translate }}</h2>
</div>
</div>
</div>
<ng-container *ngIf="asCode">
<div class="ui row">
<div class="sixteen wide column centered">
<app-upload-button accept=".yml,.yaml" size="large" (event)="fileEvent($event)">
</app-upload-button>
</div>
</div>
<div class="ui row">
<div class="one wide column"></div>
<div class="fourteen wide column">
<div class="ui horizontal divider">
{{'common_or' | translate}}
</div>
</div>
</div>
</ng-container>
<div class="ui row">
<div class="one wide column">

Expand Down
1 change: 1 addition & 0 deletions ui/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
"common_no_environment": "There is no environment linked",
"common_usage": "Usage",
"common_orientation": "Orientation",
"common_or": "OR",
"common_copy_clipboard": "Copy to clipboad",
"common_select": "Select",
"common_create": "Create",
Expand Down
1 change: 1 addition & 0 deletions ui/src/assets/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
"common_no_environment": "Il n'y a aucun environnement lié",
"common_usage": "Usage",
"common_orientation": "Orientation",
"common_or": "OU",
"common_copy_clipboard": "Copier dans le presse papier",
"common_select": "Sélectionner",
"common_create": "Créer",
Expand Down