From 97256841bdb0a93d35b2b913c85f725c0f2cf29a Mon Sep 17 00:00:00 2001 From: Alec Merdler Date: Mon, 22 May 2017 13:59:12 -0700 Subject: [PATCH] Refactor Manage Trigger to Single Workflow (#2577) * Refactor Manage Trigger to Single Workflow --- endpoints/api/robot.py | 2 +- static/css/core-ui.css | 1 + .../context-path-select.component.spec.ts | 32 +- .../context-path-select.component.ts | 25 +- .../ui/cor-table/cor-table-col.component.ts | 10 +- .../ui/cor-table/cor-table.component.html | 28 +- .../ui/cor-table/cor-table.component.ts | 20 +- .../dockerfile-path-select.component.spec.ts | 24 +- .../dockerfile-path-select.component.ts | 25 +- .../linear-workflow-section.component.spec.ts | 14 + .../linear-workflow-section.component.ts | 25 +- .../linear-workflow.component.html | 14 +- .../linear-workflow.component.spec.ts | 33 +- .../linear-workflow.component.ts | 22 +- .../manage-trigger-custom-git.component.html | 64 --- ...anage-trigger-custom-git.component.spec.ts | 14 - .../manage-trigger-custom-git.component.ts | 35 -- .../manage-trigger-githost.component.html | 413 ----------------- .../manage-trigger-githost.component.spec.ts | 113 ----- .../manage-trigger-githost.component.ts | 327 ------------- .../manage-trigger.component.html | 432 ++++++++++++++++++ .../manage-trigger.component.spec.ts | 266 +++++++++++ .../manage-trigger.component.ts | 331 ++++++++++++++ static/js/quay.module.ts | 6 +- static/js/types/common.types.ts | 41 +- static/partials/trigger-setup.html | 22 +- 26 files changed, 1262 insertions(+), 1077 deletions(-) delete mode 100644 static/js/directives/ui/manage-trigger-custom-git/manage-trigger-custom-git.component.html delete mode 100644 static/js/directives/ui/manage-trigger-custom-git/manage-trigger-custom-git.component.spec.ts delete mode 100644 static/js/directives/ui/manage-trigger-custom-git/manage-trigger-custom-git.component.ts delete mode 100644 static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html delete mode 100644 static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.spec.ts delete mode 100644 static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts create mode 100644 static/js/directives/ui/manage-trigger/manage-trigger.component.html create mode 100644 static/js/directives/ui/manage-trigger/manage-trigger.component.spec.ts create mode 100644 static/js/directives/ui/manage-trigger/manage-trigger.component.ts diff --git a/endpoints/api/robot.py b/endpoints/api/robot.py index 8f1cbde73..b2bf36563 100644 --- a/endpoints/api/robot.py +++ b/endpoints/api/robot.py @@ -78,7 +78,7 @@ class UserRobotList(ApiResource): @nickname('getUserRobots') @parse_args() @query_param('permissions', - 'Whether to include repostories and teams in which the robots have permission.', + 'Whether to include repositories and teams in which the robots have permission.', type=truthy_bool, default=False) def get(self, parsed_args): """ List the available robots for the user. """ diff --git a/static/css/core-ui.css b/static/css/core-ui.css index ef80ab7d7..d894b95b4 100644 --- a/static/css/core-ui.css +++ b/static/css/core-ui.css @@ -1239,6 +1239,7 @@ a:focus { .co-top-bar { height: 50px; + padding-bottom: 40px; } .co-check-bar .co-checked-actions .btn { diff --git a/static/js/directives/ui/context-path-select/context-path-select.component.spec.ts b/static/js/directives/ui/context-path-select/context-path-select.component.spec.ts index ebd2a71f6..18a5c0dda 100644 --- a/static/js/directives/ui/context-path-select/context-path-select.component.spec.ts +++ b/static/js/directives/ui/context-path-select/context-path-select.component.spec.ts @@ -1,4 +1,4 @@ -import { ContextPathSelectComponent } from './context-path-select.component'; +import { ContextPathSelectComponent, ContextChangeEvent } from './context-path-select.component'; describe("ContextPathSelectComponent", () => { @@ -57,23 +57,33 @@ describe("ContextPathSelectComponent", () => { expect(component.isValidContext).toBe(false); }); + + it("emits output event indicating build context changed", (done) => { + component.contextChanged.subscribe((event: ContextChangeEvent) => { + expect(event.contextDir).toEqual(newContext); + expect(event.isValid).toEqual(component.isValidContext); + done(); + }); + + component.setContext(newContext); + }); }); describe("setSelectedContext", () => { - var context: string; + var newContext: string; beforeEach(() => { - context = '/conf'; + newContext = '/conf'; }); it("sets current context to given context", () => { - component.setSelectedContext(context); + component.setSelectedContext(newContext); - expect(component.currentContext).toEqual(context); + expect(component.currentContext).toEqual(newContext); }); it("sets valid context flag to true if given context is valid", () => { - component.setSelectedContext(context); + component.setSelectedContext(newContext); expect(component.isValidContext).toBe(true); }); @@ -83,5 +93,15 @@ describe("ContextPathSelectComponent", () => { expect(component.isValidContext).toBe(false); }); + + it("emits output event indicating build context changed", (done) => { + component.contextChanged.subscribe((event: ContextChangeEvent) => { + expect(event.contextDir).toEqual(newContext); + expect(event.isValid).toEqual(component.isValidContext); + done(); + }); + + component.setSelectedContext(newContext); + }); }); }); \ No newline at end of file diff --git a/static/js/directives/ui/context-path-select/context-path-select.component.ts b/static/js/directives/ui/context-path-select/context-path-select.component.ts index bfd635c71..3fd9f33d4 100644 --- a/static/js/directives/ui/context-path-select/context-path-select.component.ts +++ b/static/js/directives/ui/context-path-select/context-path-select.component.ts @@ -1,4 +1,4 @@ -import { Input, Component, OnChanges, SimpleChanges } from 'ng-metadata/core'; +import { Input, Component, OnChanges, SimpleChanges, Output, EventEmitter } from 'ng-metadata/core'; /** @@ -10,10 +10,10 @@ import { Input, Component, OnChanges, SimpleChanges } from 'ng-metadata/core'; }) export class ContextPathSelectComponent implements OnChanges { - // FIXME: Use one-way data binding - @Input('=') public currentContext: string = ''; - @Input('=') public isValidContext: boolean; - @Input('=') public contexts: string[]; + @Input('<') public currentContext: string = ''; + @Input('<') public contexts: string[]; + @Output() public contextChanged: EventEmitter = new EventEmitter(); + public isValidContext: boolean; private isUnknownContext: boolean = true; private selectedContext: string | null = null; @@ -25,12 +25,16 @@ export class ContextPathSelectComponent implements OnChanges { this.currentContext = context; this.selectedContext = null; this.isValidContext = this.checkContext(context, this.contexts); + + this.contextChanged.emit({contextDir: context, isValid: this.isValidContext}); } public setSelectedContext(context: string): void { this.currentContext = context; this.selectedContext = context; this.isValidContext = this.checkContext(context, this.contexts); + + this.contextChanged.emit({contextDir: context, isValid: this.isValidContext}); } private checkContext(context: string = '', contexts: string[] = []): boolean { @@ -39,8 +43,17 @@ export class ContextPathSelectComponent implements OnChanges { if (context.length > 0 && context[0] === '/') { isValidContext = true; - this.isUnknownContext = true; + this.isUnknownContext = contexts.indexOf(context) != -1; } return isValidContext; } } + + +/** + * Build context changed event. + */ +export type ContextChangeEvent = { + contextDir: string; + isValid: boolean; +}; diff --git a/static/js/directives/ui/cor-table/cor-table-col.component.ts b/static/js/directives/ui/cor-table/cor-table-col.component.ts index fcda31d89..9a53141bd 100644 --- a/static/js/directives/ui/cor-table/cor-table-col.component.ts +++ b/static/js/directives/ui/cor-table/cor-table-col.component.ts @@ -15,9 +15,13 @@ export class CorTableColumn implements OnInit { @Input('@') public datafield: string; @Input('@') public sortfield: string; @Input('@') public selected: string; + @Input('=') public bindModel: any; + @Input('@') public style: string; + @Input('@') public class: string; @Input('@') public kindof: string; - constructor(@Host() @Inject(CorTableComponent) private parent: CorTableComponent) { + constructor(@Host() @Inject(CorTableComponent) private parent: CorTableComponent, + @Inject('TableService') private tableService: any) { } @@ -29,9 +33,9 @@ export class CorTableColumn implements OnInit { return this.kindof == 'datetime'; } - public processColumnForOrdered(tableService: any, value: any): any { + public processColumnForOrdered(value: any): any { if (this.kindof == 'datetime') { - return tableService.getReversedTimestamp(value); + return this.tableService.getReversedTimestamp(value); } return value; diff --git a/static/js/directives/ui/cor-table/cor-table.component.html b/static/js/directives/ui/cor-table/cor-table.component.html index 1ed8fb961..f6d18048c 100644 --- a/static/js/directives/ui/cor-table/cor-table.component.html +++ b/static/js/directives/ui/cor-table/cor-table.component.html @@ -4,29 +4,39 @@
+ - Showing {{ $ctrl.orderedData.entries.length }} of {{ $ctrl.tableData.length }} {{ $ctrl.tableItemTitle }} + Showing {{ $ctrl.orderedData.entries.length }} of {{ $ctrl.tableData.length }} {{ ::$ctrl.tableItemTitle }} - +
-
No {{ $ctrl.tableItemTitle }} found.
+
No {{ ::$ctrl.tableItemTitle }} found.
- - + - @@ -36,7 +46,7 @@
-
No matching {{ $ctrl.tableItemTitle }} found.
+
No matching {{ ::$ctrl.tableItemTitle }} found.
Try adjusting your filter above.
\ No newline at end of file diff --git a/static/js/directives/ui/cor-table/cor-table.component.ts b/static/js/directives/ui/cor-table/cor-table.component.ts index 6d7839ae6..2c899c0ee 100644 --- a/static/js/directives/ui/cor-table/cor-table.component.ts +++ b/static/js/directives/ui/cor-table/cor-table.component.ts @@ -13,7 +13,7 @@ import { CorTableColumn } from './cor-table-col.component'; } }) export class CorTableComponent implements OnChanges { - @Input('<') public tableData: any[]; + @Input('<') public tableData: any[] = []; @Input('@') public tableItemTitle: string; @Input('<') public filterFields: string[]; @Input('@') public compact: string; @@ -22,7 +22,7 @@ export class CorTableComponent implements OnChanges { private orderedData: any; private options: any; - constructor(@Inject('TableService') private TableService: any) { + constructor(@Inject('TableService') private tableService: any) { this.columns = []; this.options = { 'filter': '', @@ -49,15 +49,17 @@ export class CorTableComponent implements OnChanges { } private setOrder(col: CorTableColumn): void { - this.TableService.orderBy(col.datafield, this.options); + this.tableService.orderBy(col.datafield, this.options); this.refreshOrder(); } private tablePredicateClass(col: CorTableColumn, options: any) { - return this.TableService.tablePredicateClass(col.datafield, this.options.predicate, this.options.reverse); + return this.tableService.tablePredicateClass(col.datafield, this.options.predicate, this.options.reverse); } private refreshOrder(): void { + this.options.page = 0; + var columnMap = {}; this.columns.forEach(function(col) { columnMap[col.datafield] = col; @@ -69,18 +71,16 @@ export class CorTableComponent implements OnChanges { const numericCols = this.columns.filter(col => col.isNumeric()) .map(col => col.datafield); - const tableData = this.tableData || []; - const processed = tableData.map((item) => { - var newObj = Object.assign({}, item); + const processed = this.tableData.map((item) => { Object.keys(item).forEach((key) => { if (columnMap[key]) { - newObj[key] = columnMap[key].processColumnForOrdered(this.TableService, item[key]); + item[key] = columnMap[key].processColumnForOrdered(item[key]); } }); - return newObj; + return item; }); - this.orderedData = this.TableService.buildOrderedItems(processed, this.options, filterCols, numericCols); + this.orderedData = this.tableService.buildOrderedItems(processed, this.options, filterCols, numericCols); } } diff --git a/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.spec.ts b/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.spec.ts index f1210037d..b96307406 100644 --- a/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.spec.ts +++ b/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.spec.ts @@ -1,4 +1,4 @@ -import { DockerfilePathSelectComponent } from './dockerfile-path-select.component'; +import { DockerfilePathSelectComponent, PathChangeEvent } from './dockerfile-path-select.component'; describe("DockerfilePathSelectComponent", () => { @@ -60,6 +60,16 @@ describe("DockerfilePathSelectComponent", () => { expect(component.isValidPath).toBe(false); }); + + it("emits output event indicating Dockerfile path has changed", (done) => { + component.pathChanged.subscribe((event: PathChangeEvent) => { + expect(event.path).toEqual(newPath); + expect(event.isValid).toBe(component.isValidPath); + done(); + }); + + component.setPath(newPath); + }); }); describe("setCurrentPath", () => { @@ -86,5 +96,15 @@ describe("DockerfilePathSelectComponent", () => { expect(component.isValidPath).toBe(false); }); + + it("emits output event indicating Dockerfile path has changed", (done) => { + component.pathChanged.subscribe((event: PathChangeEvent) => { + expect(event.path).toEqual(newPath); + expect(event.isValid).toBe(component.isValidPath); + done(); + }); + + component.setSelectedPath(newPath); + }); }); -}); \ No newline at end of file +}); diff --git a/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.ts b/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.ts index bebb563f9..fe63e66b3 100644 --- a/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.ts +++ b/static/js/directives/ui/dockerfile-path-select/dockerfile-path-select.component.ts @@ -1,4 +1,4 @@ -import { Input, Component, OnChanges, SimpleChanges } from 'ng-metadata/core'; +import { Input, Output, EventEmitter, Component, OnChanges, SimpleChanges } from 'ng-metadata/core'; /** @@ -10,11 +10,11 @@ import { Input, Component, OnChanges, SimpleChanges } from 'ng-metadata/core'; }) export class DockerfilePathSelectComponent implements OnChanges { - // FIXME: Use one-way data binding - @Input('=') public currentPath: string = ''; - @Input('=') public isValidPath: boolean; - @Input('=') public paths: string[]; - @Input('=') public supportsFullListing: boolean; + @Input('<') public currentPath: string = ''; + @Input('<') public paths: string[]; + @Input('<') public supportsFullListing: boolean; + @Output() public pathChanged: EventEmitter = new EventEmitter(); + public isValidPath: boolean; private isUnknownPath: boolean = true; private selectedPath: string | null = null; @@ -26,12 +26,16 @@ export class DockerfilePathSelectComponent implements OnChanges { this.currentPath = path; this.selectedPath = null; this.isValidPath = this.checkPath(path, this.paths, this.supportsFullListing); + + this.pathChanged.emit({path: this.currentPath, isValid: this.isValidPath}); } public setSelectedPath(path: string): void { this.currentPath = path; this.selectedPath = path; this.isValidPath = this.checkPath(path, this.paths, this.supportsFullListing); + + this.pathChanged.emit({path: this.currentPath, isValid: this.isValidPath}); } private checkPath(path: string = '', paths: string[] = [], supportsFullListing: boolean): boolean { @@ -45,3 +49,12 @@ export class DockerfilePathSelectComponent implements OnChanges { return isValidPath; } } + + +/** + * Dockerfile path changed event. + */ +export type PathChangeEvent = { + path: string; + isValid: boolean; +}; diff --git a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts index f2a65b337..71ad913d8 100644 --- a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts +++ b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.spec.ts @@ -35,6 +35,11 @@ describe("LinearWorkflowSectionComponent", () => { previousValue: false, isFirstChange: () => false, }, + skipSection: { + currentValue: true, + previousValue: false, + isFirstChange: () => false, + }, }; }); @@ -56,6 +61,15 @@ describe("LinearWorkflowSectionComponent", () => { expect(onSectionInvalidSpy.calls.argsFor(0)[0]).toEqual(component.sectionId); }); + + it("calls parent method to go to next section if 'skipSection' input is true and is current section", () => { + delete changesObj['sectionValid']; + const onNextSectionSpy: Spy = spyOn(parentMock, 'onNextSection').and.returnValue(null); + component.isCurrentSection = true; + component.ngOnChanges(changesObj); + + expect(onNextSectionSpy).toHaveBeenCalled(); + }); }); describe("onSubmitSection", () => { diff --git a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts index 8896f640c..f3c3529d7 100644 --- a/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts +++ b/static/js/directives/ui/linear-workflow/linear-workflow-section.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, Inject, Host, OnChanges, OnInit, SimpleChanges } from 'ng-metadata/core'; +import { Component, Input, Inject, Host, OnChanges, OnInit, SimpleChanges, HostListener } from 'ng-metadata/core'; import { LinearWorkflowComponent } from './linear-workflow.component'; @@ -16,21 +16,34 @@ export class LinearWorkflowSectionComponent implements OnChanges, OnInit { @Input('@') public sectionId: string; @Input('@') public sectionTitle: string; - @Input() public sectionValid: boolean = false; + @Input('<') public sectionValid: boolean = false; + @Input('<') public skipSection: boolean = false; public sectionVisible: boolean = false; public isCurrentSection: boolean = false; constructor(@Host() @Inject(LinearWorkflowComponent) private parent: LinearWorkflowComponent) { } - + public ngOnInit(): void { - this.parent.addSection(this); + if (!this.skipSection) { + this.parent.addSection(this); + } } public ngOnChanges(changes: SimpleChanges): void { - if (changes['sectionValid'] !== undefined && !changes['sectionValid'].currentValue) { - this.parent.onSectionInvalid(this.sectionId); + switch (Object.keys(changes)[0]) { + case 'sectionValid': + if (!changes['sectionValid'].currentValue && this.parent) { + this.parent.onSectionInvalid(this.sectionId); + } + break; + + case 'skipSection': + if (changes['skipSection'].currentValue && this.isCurrentSection && this.parent) { + this.parent.onNextSection(); + } + break; } } diff --git a/static/js/directives/ui/linear-workflow/linear-workflow.component.html b/static/js/directives/ui/linear-workflow/linear-workflow.component.html index 899dc4c2d..559d1d405 100644 --- a/static/js/directives/ui/linear-workflow/linear-workflow.component.html +++ b/static/js/directives/ui/linear-workflow/linear-workflow.component.html @@ -8,12 +8,12 @@
- {{ col.title }} + + {{ ::col.title }}
+
{{ item[col.datafield] }}