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

[UI] Allow single item deletion from multi-value fields #7084

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/apiserver-impl/ui/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/apiserver-impl/ui/main.d1fdc7897d7897d7.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion pkg/apiserver-impl/ui/main.d468134bf8c5f727.js

This file was deleted.

3 changes: 2 additions & 1 deletion ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ testem.log
Thumbs.db

/cypress/videos
/cypress/screenshots

.odo
.odo
282 changes: 270 additions & 12 deletions ui/cypress/e2e/spec.cy.ts

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions ui/cypress/fixtures/input/with-exec-command.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ commands:
hotReloadCapable: false
workingDir: /projects
id: command1
- exec:
commandLine: echo command2
component: container1
hotReloadCapable: true
workingDir: /projects
id: command2
- exec:
commandLine: echo command3
component: container1
hotReloadCapable: true
workingDir: /projects
id: command3
components:
- container:
args:
Expand Down
12 changes: 12 additions & 0 deletions ui/cypress/fixtures/input/with-volume.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
schemaVersion: 2.2.0
metadata: {}
components:
- name: volume1
volume: {}
- name: volume2
volume:
size: 2Gi
- name: volume3
volume:
ephemeral: true
size: 3G
11 changes: 11 additions & 0 deletions ui/src/app/controls/endpoints/endpoints.component.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
.mid-width { width: 50%; }
.quart-width { width: 25%; }

mat-card{
display:flex;
flex-direction: row;
margin-bottom: 16px;
}

mat-card-content{
flex-grow: 1;
overflow: auto;
}
88 changes: 47 additions & 41 deletions ui/src/app/controls/endpoints/endpoints.component.html
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
<div *ngFor="let control of form.controls; index as i">
<ng-container [formGroup]="control">
<mat-form-field class="mid-width" appearance="outline">
<mat-label><span>Name</span></mat-label>
<input [attr.data-cy]="'endpoint-name-'+i" matInput formControlName="name">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label><span>Target Port</span></mat-label>
<input [attr.data-cy]="'endpoint-targetPort-'+i" type="number" matInput formControlName="targetPort">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label>Exposure</mat-label>
<mat-select [attr.data-cy]="'endpoint-exposure-'+i" formControlName="exposure">
<mat-option value="">(default, public)</mat-option>
<mat-option value="public">public</mat-option>
<mat-option value="internal">internal</mat-option>
<mat-option value="none">none</mat-option>
</mat-select>
</mat-form-field>
<div class="group">
<mat-card *ngFor="let control of form.controls; index as i">
<mat-card-content [formGroup]="control">
<mat-form-field class="mid-width" appearance="outline">
<mat-label><span>Name</span></mat-label>
<input [attr.data-cy]="'endpoint-name-'+i" matInput formControlName="name">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label><span>Target Port</span></mat-label>
<input [attr.data-cy]="'endpoint-targetPort-'+i" type="number" matInput formControlName="targetPort">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label>Exposure</mat-label>
<mat-select [attr.data-cy]="'endpoint-exposure-'+i" formControlName="exposure">
<mat-option value="">(default, public)</mat-option>
<mat-option value="public">public</mat-option>
<mat-option value="internal">internal</mat-option>
<mat-option value="none">none</mat-option>
</mat-select>
</mat-form-field>

<mat-form-field class="mid-width" appearance="outline">
<mat-label><span>Path</span></mat-label>
<input [attr.data-cy]="'endpoint-path-'+i" matInput formControlName="path">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label>Protocol</mat-label>
<mat-select [attr.data-cy]="'endpoint-protocol-'+i" formControlName="protocol">
<mat-option value="">(default, http)</mat-option>
<mat-option value="http">http</mat-option>
<mat-option value="https">https</mat-option>
<mat-option value="ws">ws</mat-option>
<mat-option value="wss">wss</mat-option>
<mat-option value="tcp">tcp</mat-option>
<mat-option value="udp">udp</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox [attr.data-cy]="'endpoint-secure-'+i" formControlName="secure">Protocol Is Secure</mat-checkbox>
</ng-container>
<mat-form-field class="mid-width" appearance="outline">
<mat-label><span>Path</span></mat-label>
<input [attr.data-cy]="'endpoint-path-'+i" matInput formControlName="path">
</mat-form-field>
<mat-form-field class="quart-width" appearance="outline">
<mat-label>Protocol</mat-label>
<mat-select [attr.data-cy]="'endpoint-protocol-'+i" formControlName="protocol">
<mat-option value="">(default, http)</mat-option>
<mat-option value="http">http</mat-option>
<mat-option value="https">https</mat-option>
<mat-option value="ws">ws</mat-option>
<mat-option value="wss">wss</mat-option>
<mat-option value="tcp">tcp</mat-option>
<mat-option value="udp">udp</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox [attr.data-cy]="'endpoint-secure-'+i" formControlName="secure">Protocol Is Secure</mat-checkbox>
</mat-card-content>
<mat-card-actions>
<button [attr.data-cy]="'endpoint-minus-'+i" mat-icon-button (click)="removeEndpoint(i)">
<mat-icon class="tab-icon material-icons-outlined">remove</mat-icon>
</button>
</mat-card-actions>
</mat-card>
<div>
<button data-cy="endpoints-add" mat-flat-button (click)="addEndpoint()">Add an Endpoint</button>
</div>
</div>
<button data-cy="endpoints-plus" *ngIf="form.value.length > 0" mat-icon-button (click)="addEndpoint()">
<mat-icon class="tab-icon material-icons-outlined">add</mat-icon>
</button>
<button data-cy="endpoints-add" *ngIf="form.value.length == 0" mat-flat-button (click)="addEndpoint()">Add an Endpoint</button>
4 changes: 4 additions & 0 deletions ui/src/app/controls/endpoints/endpoints.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export class EndpointsComponent implements ControlValueAccessor, Validator {
}));
}

removeEndpoint(index: number) {
this.form.removeAt(index);
}

/* ControlValueAccessor implementation */
writeValue(value: Endpoint[]) {
value.forEach(ep => {
Expand Down
12 changes: 7 additions & 5 deletions ui/src/app/controls/multi-command/multi-command.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ <h3>{{title}}</h3>
<span *ngFor="let control of form.controls; index as i">
<mat-form-field appearance="fill">
<mat-label><span>Command</span></mat-label>
<mat-select [formControl]="control">
<mat-select [attr.data-cy]="'command-selector-'+i" [formControl]="control">
<mat-option *ngFor="let commandElement of commandList" [value]="commandElement">{{commandElement}}</mat-option>
</mat-select>
</mat-form-field>
<button [attr.data-cy]="'command-minus-'+i" mat-icon-button (click)="removeCommand(i)">
<mat-icon class="tab-icon material-icons-outlined">remove</mat-icon>
</button>
</span>
<button *ngIf="form.controls.length > 0" mat-icon-button (click)="addCommand('')">
<mat-icon class="tab-icon material-icons-outlined">add</mat-icon>
</button>
<button *ngIf="form.controls.length == 0" mat-flat-button (click)="addCommand('')">{{addLabel}}</button>
<div>
<button [attr.data-cy]="'add-command'" mat-flat-button (click)="addCommand('')">{{addLabel}}</button>
</div>
</div>
4 changes: 4 additions & 0 deletions ui/src/app/controls/multi-command/multi-command.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export class MultiCommandComponent implements ControlValueAccessor, Validator {
this.form.push(this.newCommand(cmdName));
}

removeCommand(index: number) {
this.form.removeAt(index);
}

/* Validator implementation */
validate(control: AbstractControl): ValidationErrors | null {
if (!this.form.valid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
div.group { margin-bottom: 16px; }
.mid-width { width: 50%; }
.kv-width { width: 45%; }
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<div class="group">
<div *ngFor="let control of form.controls; index as i">
<ng-container [formGroup]="control">
<mat-form-field class="mid-width" appearance="outline">
<mat-form-field class="kv-width" appearance="outline">
<mat-label><span>Name</span></mat-label>
<input [attr.data-cy]="dataCyPrefix+'-name-'+i" matInput formControlName="name">
</mat-form-field>
<mat-form-field class="mid-width" appearance="outline">
<mat-form-field class="kv-width" appearance="outline">
<mat-label><span>Value</span></mat-label>
<input [attr.data-cy]="dataCyPrefix+'-value-'+i" matInput formControlName="value">
</mat-form-field>
<button [attr.data-cy]="dataCyPrefix+'-minus-'+i" mat-icon-button (click)="removeEntry(i)">
<mat-icon class="tab-icon material-icons-outlined">remove</mat-icon>
</button>
</ng-container>
</div>
<button [attr.data-cy]="dataCyPrefix+'-plus'" *ngIf="form.controls.length > 0" mat-icon-button (click)="addEntry('', '')">
<mat-icon class="tab-icon material-icons-outlined">add</mat-icon>
</button>
<button [attr.data-cy]="dataCyPrefix+'-add'" *ngIf="form.controls.length == 0" mat-flat-button (click)="addEntry('', '')">{{addLabel}}</button>
<button [attr.data-cy]="dataCyPrefix+'-add'" mat-flat-button (click)="addEntry('', '')">{{addLabel}}</button>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export class MultiKeyValueComponent implements ControlValueAccessor, Validator {
this.form.push(this.newKeyValueForm({name, value}));
}

removeEntry(index: number) {
this.form.removeAt(index);
}

/* Validator implementation */
validate(control: AbstractControl): ValidationErrors | null {
if (!this.form.valid) {
Expand Down
12 changes: 7 additions & 5 deletions ui/src/app/controls/multi-text/multi-text.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ <h3 *ngIf="title">{{title}}</h3>
<span *ngFor="let control of form.controls; index as i">
<mat-form-field class="inline" appearance="outline">
<mat-label><span>{{label}}</span></mat-label>
<input matInput [formControl]="control">
<input [attr.data-cy]="dataCyPrefix+'-text-'+i" matInput [formControl]="control">
</mat-form-field>
<button [attr.data-cy]="dataCyPrefix+'-minus-'+i" mat-icon-button (click)="removeText(i)">
<mat-icon class="tab-icon material-icons-outlined">remove</mat-icon>
</button>
</span>
<button *ngIf="form.controls.length > 0" mat-icon-button (click)="addText('')">
<mat-icon class="tab-icon material-icons-outlined">add</mat-icon>
</button>
<button *ngIf="form.controls.length == 0" mat-flat-button (click)="addText('')">{{addLabel}}</button>
<div>
<button [attr.data-cy]="'add-text'" mat-flat-button (click)="addText('')">{{addLabel}}</button>
</div>
</div>
5 changes: 5 additions & 0 deletions ui/src/app/controls/multi-text/multi-text.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
})
export class MultiTextComponent implements ControlValueAccessor, Validator {

@Input() dataCyPrefix: string = "";
@Input() label: string = "";
@Input() addLabel: string = "";
@Input() title: string = "";
Expand Down Expand Up @@ -62,6 +63,10 @@ export class MultiTextComponent implements ControlValueAccessor, Validator {
this.form.push(this.newText(text));
}

removeText(index: number) {
this.form.removeAt(index);
}

/* Validator implementation */
validate(control: AbstractControl): ValidationErrors | null {
if (!this.form.valid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
<input formControlName="path" [attr.data-cy]="'volume-mount-path-'+i" matInput>
</mat-form-field>

<button [attr.data-cy]="'volume-mount-minus-'+i" mat-icon-button (click)="remove(i)">
<mat-icon class="tab-icon material-icons-outlined">remove</mat-icon>
</button>

<app-volume
*ngIf="showNewVolume[i]"
(created)="onNewVolumeCreated(i, $event)"
></app-volume>
</ng-container>
</div>
<button data-cy="volume-mount-add" *ngIf="form.controls.length > 0" mat-icon-button (click)="add('', '')">
<mat-icon class="tab-icon material-icons-outlined">add</mat-icon>
</button>
<button data-cy="volume-mount-add" *ngIf="form.controls.length == 0" mat-flat-button (click)="add('', '')">Add Volume Mount</button>
<button data-cy="volume-mount-add" mat-flat-button (click)="add('', '')">Add Volume Mount</button>
</div>

4 changes: 4 additions & 0 deletions ui/src/app/controls/volume-mounts/volume-mounts.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export class VolumeMountsComponent implements ControlValueAccessor, Validator {
this.form.push(this.newVolumeMount({name, path}));
}

remove(i: number) {
this.form.removeAt(i);
}

onNameChange(i: number, name: string) {
this.showNewVolume[i] = name == "!";
}
Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/forms/container/container.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ <h2 *ngIf="container">Edit container <i>{{container.name}}</i></h2>
</mat-form-field>
<h3>Command and Arguments</h3>
<div class="description">Command and Arguments can be used to override the entrypoint of the image</div>
<app-multi-text formControlName="command" label="Command" addLabel="Add command"></app-multi-text>
<app-multi-text formControlName="args" label="Arg" addLabel="Add arg"></app-multi-text>
<app-multi-text dataCyPrefix="container-command" formControlName="command" label="Command" addLabel="Add command"></app-multi-text>
<app-multi-text dataCyPrefix="container-arg" formControlName="args" label="Arg" addLabel="Add arg"></app-multi-text>

<h3>Environment Variables</h3>
<div class="description">Environment Variables to define in the running container</div>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/forms/image/image.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h2 *ngIf="image">Edit image <i>{{image.name}}</i></h2>
<mat-label><span>Image Name</span></mat-label>
<input placeholder="Reference to a container image" data-cy="image-image-name" matInput formControlName="imageName">
</mat-form-field>
<app-multi-text formControlName="args" title="Build Args" label="Arg" addLabel="Add Build Arg"></app-multi-text>
<app-multi-text dataCyPrefix="image-arg" formControlName="args" title="Build Args" label="Arg" addLabel="Add Build Arg"></app-multi-text>
<mat-form-field appearance="outline" class="mid-width">
<mat-label><span>Build Context</span></mat-label>
<input placeholder="Directory from which the build will be executed" data-cy="image-build-context" matInput formControlName="buildContext">
Expand Down