mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
[UI] Allow single item deletion from multi-value fields (#7084)
* Support single endpoint deletion from multi-endpoints component
* Support single command deletion from multi-commands component
* Support single key-value item deletion from multi-key-value component
* Support single text item deletion from multi-text component
* Support single volume mount item deletion from multi-volume-mounts component
* Add Cypress test cases
* Git-ignore Cypress screenshots folder
* Generate static UI
* Update Delete icon and add tooltip to it
Co-authored-by: Philippe Martin <phmartin@redhat.com>
* Move the "delete endpoint" button closer to the element it is attached to
Co-authored-by: Philippe Martin <phmartin@redhat.com>
* Generate static UI
* Revert "Move the "delete endpoint" button closer to the element it is attached to"
This reverts commit 4bf895f272.
* Move the "delete endpoint" buttons closer to the elements they are attached to
Co-authored-by: Philippe Martin <phmartin@redhat.com>
* Generate static UI
---------
Co-authored-by: Philippe Martin <phmartin@redhat.com>
This commit is contained in:
3
ui/.gitignore
vendored
3
ui/.gitignore
vendored
@@ -42,5 +42,6 @@ testem.log
|
||||
Thumbs.db
|
||||
|
||||
/cypress/videos
|
||||
/cypress/screenshots
|
||||
|
||||
.odo
|
||||
.odo
|
||||
|
||||
@@ -54,10 +54,10 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-0').type("VAR1");
|
||||
cy.getByDataCy('container-env-value-0').type("val1");
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-1').type("VAR2");
|
||||
cy.getByDataCy('container-env-value-1').type("val2");
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-2').type("VAR3");
|
||||
cy.getByDataCy('container-env-value-2').type("val3");
|
||||
|
||||
@@ -79,13 +79,13 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-deploy-anno-add').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-0').type("DEPANNO1");
|
||||
cy.getByDataCy('container-deploy-anno-value-0').type("depval1");
|
||||
cy.getByDataCy('container-deploy-anno-plus').click();
|
||||
cy.getByDataCy('container-deploy-anno-add').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-1').type("DEPANNO2");
|
||||
cy.getByDataCy('container-deploy-anno-value-1').type("depval2");
|
||||
cy.getByDataCy('container-svc-anno-add').click();
|
||||
cy.getByDataCy('container-svc-anno-name-0').type("SVCANNO1");
|
||||
cy.getByDataCy('container-svc-anno-value-0').type("svcval1");
|
||||
cy.getByDataCy('container-svc-anno-plus').click();
|
||||
cy.getByDataCy('container-svc-anno-add').click();
|
||||
cy.getByDataCy('container-svc-anno-name-1').type("SVCANNO2");
|
||||
cy.getByDataCy('container-svc-anno-value-1').type("svcval2");
|
||||
|
||||
@@ -117,7 +117,7 @@ describe('devfile editor spec', () => {
|
||||
});
|
||||
|
||||
|
||||
it.only('displays a modified container', () => {
|
||||
it('displays a modified container', () => {
|
||||
cy.init();
|
||||
|
||||
cy.selectTab(TAB_VOLUMES);
|
||||
@@ -132,10 +132,10 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-0').type("VAR1");
|
||||
cy.getByDataCy('container-env-value-0').type("val1");
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-1').type("VAR2");
|
||||
cy.getByDataCy('container-env-value-1').type("val2");
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-2').type("VAR3");
|
||||
cy.getByDataCy('container-env-value-2').type("val3");
|
||||
|
||||
@@ -157,13 +157,13 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-deploy-anno-add').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-0').type("DEPANNO1");
|
||||
cy.getByDataCy('container-deploy-anno-value-0').type("depval1");
|
||||
cy.getByDataCy('container-deploy-anno-plus').click();
|
||||
cy.getByDataCy('container-deploy-anno-add').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-1').type("DEPANNO2");
|
||||
cy.getByDataCy('container-deploy-anno-value-1').type("depval2");
|
||||
cy.getByDataCy('container-svc-anno-add').click();
|
||||
cy.getByDataCy('container-svc-anno-name-0').type("SVCANNO1");
|
||||
cy.getByDataCy('container-svc-anno-value-0').type("svcval1");
|
||||
cy.getByDataCy('container-svc-anno-plus').click();
|
||||
cy.getByDataCy('container-svc-anno-add').click();
|
||||
cy.getByDataCy('container-svc-anno-name-1').type("SVCANNO2");
|
||||
cy.getByDataCy('container-svc-anno-value-1').type("svcval2");
|
||||
|
||||
@@ -172,7 +172,7 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-edit').click();
|
||||
|
||||
cy.getByDataCy('container-image').type('{selectAll}{del}another-image');
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-3').type("VAR4");
|
||||
cy.getByDataCy('container-env-value-3').type("val4");
|
||||
|
||||
@@ -190,12 +190,12 @@ describe('devfile editor spec', () => {
|
||||
cy.getByDataCy('container-more-params').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-0').type("{selectAll}{del}DEPANNO1b");
|
||||
cy.getByDataCy('container-deploy-anno-value-0').type("{selectAll}{del}depval1b");
|
||||
cy.getByDataCy('container-deploy-anno-plus').click();
|
||||
cy.getByDataCy('container-deploy-anno-add').click();
|
||||
cy.getByDataCy('container-deploy-anno-name-2').type("DEPANNO3");
|
||||
cy.getByDataCy('container-deploy-anno-value-2').type("depval3");
|
||||
cy.getByDataCy('container-svc-anno-name-0').type("{selectAll}{del}SVCANNO1b");
|
||||
cy.getByDataCy('container-svc-anno-value-0').type("{selectAll}{del}svcval1b");
|
||||
cy.getByDataCy('container-svc-anno-plus').click();
|
||||
cy.getByDataCy('container-svc-anno-add').click();
|
||||
cy.getByDataCy('container-svc-anno-name-2').type("SVCANNO3");
|
||||
cy.getByDataCy('container-svc-anno-value-2').type("svcval3");
|
||||
|
||||
@@ -767,4 +767,262 @@ describe('devfile editor spec', () => {
|
||||
cy.selectTab(TAB_YAML);
|
||||
cy.get('[data-cy="yaml-input"]').should("contain.value", "events: {}");
|
||||
});
|
||||
|
||||
it('should update list of commands from multi-value field when adding and editing a composite command', () => {
|
||||
cy.init();
|
||||
cy.fixture('input/with-exec-command.yaml').then(yaml => {
|
||||
cy.setDevfile(yaml);
|
||||
});
|
||||
|
||||
cy.selectTab(TAB_COMMANDS);
|
||||
cy.getByDataCy('add').click();
|
||||
cy.getByDataCy('new-command-composite').click();
|
||||
cy.getByDataCy('command-composite-name').type('my-new-composite-command');
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('command-selector-0').click().get('mat-option').contains('command2').click();
|
||||
cy.getByDataCy('command-selector-1').click().get('mat-option').contains('command3').click();
|
||||
cy.getByDataCy('command-selector-2').click().get('mat-option').contains('command1').click();
|
||||
cy.getByDataCy('command-minus-1').click();
|
||||
cy.getByDataCy('command-composite-create').click();
|
||||
|
||||
cy.getByDataCy('command-info').last()
|
||||
.should('contain.text', 'command2')
|
||||
.should('contain.text', 'command1')
|
||||
.should('not.contain.text', 'command3');
|
||||
|
||||
//Edit
|
||||
cy.getByDataCy('command-edit').last().click();
|
||||
cy.getByDataCy('command-selector-0').should('have.text', 'command2');
|
||||
cy.getByDataCy('command-selector-1').should('have.text', 'command1');
|
||||
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('add-command').click();
|
||||
cy.getByDataCy('command-selector-2').click().get('mat-option').contains('command2').click();
|
||||
cy.getByDataCy('command-minus-4').click();
|
||||
cy.getByDataCy('command-minus-0').click();
|
||||
cy.getByDataCy('command-selector-2').click().get('mat-option').contains('command3').click();
|
||||
cy.getByDataCy('command-composite-save').click();
|
||||
|
||||
cy.getByDataCy('command-info').last()
|
||||
.should('contain.text', 'command1')
|
||||
.should('contain.text', 'command2')
|
||||
.should('contain.text', 'command3');
|
||||
});
|
||||
|
||||
it('should update list of build args from multi-value field when adding and editing an image component', () => {
|
||||
cy.init();
|
||||
cy.selectTab(TAB_IMAGES);
|
||||
|
||||
cy.getByDataCy('image-name').type('my-new-image');
|
||||
cy.getByDataCy('image-image-name').type('an-image-name');
|
||||
cy.getByDataCy('image-dockerfile-uri').type('/path/to/dockerfile');
|
||||
|
||||
cy.getByDataCy('add-text').click();
|
||||
cy.getByDataCy('add-text').click();
|
||||
cy.getByDataCy('add-text').click();
|
||||
|
||||
cy.getByDataCy('image-arg-text-0').type('arg2');
|
||||
cy.getByDataCy('image-arg-text-1').type('arg3');
|
||||
cy.getByDataCy('image-arg-text-2').type('arg1');
|
||||
cy.getByDataCy('image-arg-minus-1').click();
|
||||
|
||||
cy.getByDataCy('image-create').click();
|
||||
|
||||
cy.getByDataCy('image-info').last()
|
||||
.should('contain.text', 'arg2')
|
||||
.should('contain.text', 'arg1')
|
||||
.should('not.contain.text', 'arg3');
|
||||
|
||||
//Edit
|
||||
cy.getByDataCy('image-edit').last().click();
|
||||
cy.getByDataCy('image-arg-text-0').should('have.value', 'arg2');
|
||||
cy.getByDataCy('image-arg-text-1').should('have.value', 'arg1');
|
||||
|
||||
cy.getByDataCy('add-text').click();
|
||||
cy.getByDataCy('add-text').click();
|
||||
cy.getByDataCy('add-text').click();
|
||||
cy.getByDataCy('image-arg-text-2').type('arg2');
|
||||
cy.getByDataCy('image-arg-minus-4').click();
|
||||
cy.getByDataCy('image-arg-minus-0').click();
|
||||
cy.getByDataCy('image-arg-text-2').type('arg3');
|
||||
cy.getByDataCy('image-save').click();
|
||||
|
||||
cy.getByDataCy('image-info').last()
|
||||
.should('contain.text', 'arg1')
|
||||
.should('contain.text', 'arg2')
|
||||
.should('contain.text', 'arg3');
|
||||
});
|
||||
|
||||
it('should update list of env vars from multi-value field when adding and editing a container', () => {
|
||||
cy.init();
|
||||
cy.selectTab(TAB_CONTAINERS);
|
||||
|
||||
cy.getByDataCy('container-name').type('my-new-container');
|
||||
cy.getByDataCy('container-image').type('an-image');
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
|
||||
cy.getByDataCy('container-env-name-0').type("VAR2");
|
||||
cy.getByDataCy('container-env-value-0').type("val2");
|
||||
cy.getByDataCy('container-env-name-1').type("VAR3");
|
||||
cy.getByDataCy('container-env-value-1').type("val3");
|
||||
cy.getByDataCy('container-env-name-2').type("VAR1");
|
||||
cy.getByDataCy('container-env-value-2').type("val1");
|
||||
cy.getByDataCy('container-env-minus-1').click();
|
||||
|
||||
cy.getByDataCy('container-create').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'an-image')
|
||||
.should('contain.text', 'VAR2: val2')
|
||||
.should('contain.text', 'VAR1: val1')
|
||||
.should('not.contain.text', 'VAR3: val3');
|
||||
|
||||
//Edit
|
||||
cy.getByDataCy('container-edit').last().click();
|
||||
cy.getByDataCy('container-env-name-0').should('have.value', 'VAR2');
|
||||
cy.getByDataCy('container-env-value-0').should('have.value', 'val2');
|
||||
cy.getByDataCy('container-env-name-1').should('have.value', 'VAR1');
|
||||
cy.getByDataCy('container-env-value-1').should('have.value', 'val1');
|
||||
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-add').click();
|
||||
cy.getByDataCy('container-env-name-2').type("VAR2");
|
||||
cy.getByDataCy('container-env-value-2').type("val2");
|
||||
cy.getByDataCy('container-env-minus-4').click();
|
||||
cy.getByDataCy('container-env-minus-0').click();
|
||||
cy.getByDataCy('container-env-name-2').type("VAR3");
|
||||
cy.getByDataCy('container-env-value-2').type("val3");
|
||||
cy.getByDataCy('container-save').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'an-image')
|
||||
.should('contain.text', 'VAR2: val2')
|
||||
.should('contain.text', 'VAR1: val1')
|
||||
.should('contain.text', 'VAR3: val3');
|
||||
});
|
||||
|
||||
it('should update list of endpoints from multi-value field when adding and editing a container', () => {
|
||||
cy.init();
|
||||
cy.selectTab(TAB_CONTAINERS);
|
||||
|
||||
cy.getByDataCy('container-name').type('my-new-container');
|
||||
cy.getByDataCy('container-image').type('an-image');
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
|
||||
cy.getByDataCy('endpoint-name-0').type("ep2");
|
||||
cy.getByDataCy('endpoint-targetPort-0').clear().type("4002");
|
||||
cy.getByDataCy('endpoint-name-1').type("ep3");
|
||||
cy.getByDataCy('endpoint-targetPort-1').clear().type("4003");
|
||||
cy.getByDataCy('endpoint-name-2').type("ep1");
|
||||
cy.getByDataCy('endpoint-targetPort-2').clear().type("4001");
|
||||
cy.getByDataCy('endpoint-minus-1').click();
|
||||
|
||||
cy.getByDataCy('container-create').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'ep2')
|
||||
.should('contain.text', '4002')
|
||||
.should('contain.text', 'ep1')
|
||||
.should('contain.text', '4001')
|
||||
.should('not.contain.text', 'ep3')
|
||||
.should('not.contain.text', '4003');
|
||||
|
||||
//Edit
|
||||
cy.getByDataCy('container-edit').last().click();
|
||||
cy.getByDataCy('endpoint-name-0').should('have.value', 'ep2');
|
||||
cy.getByDataCy('endpoint-targetPort-0').should('have.value', '4002');
|
||||
cy.getByDataCy('endpoint-name-1').should('have.value', 'ep1');
|
||||
cy.getByDataCy('endpoint-targetPort-1').should('have.value', '4001');
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoint-name-2').type("ep2");
|
||||
cy.getByDataCy('endpoint-targetPort-2').clear().type("4002");
|
||||
cy.getByDataCy('endpoint-minus-4').click();
|
||||
cy.getByDataCy('endpoint-minus-0').click();
|
||||
cy.getByDataCy('endpoint-name-2').type("ep3");
|
||||
cy.getByDataCy('endpoint-targetPort-2').clear().type("4003");
|
||||
cy.getByDataCy('container-save').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'ep1')
|
||||
.should('contain.text', '4001')
|
||||
.should('contain.text', 'ep2')
|
||||
.should('contain.text', '4002')
|
||||
.should('contain.text', 'ep3')
|
||||
.should('contain.text', '4003');
|
||||
});
|
||||
|
||||
it('should update list of volume mounts from multi-value field when adding and editing a container', () => {
|
||||
cy.init();
|
||||
cy.fixture('input/with-volume.yaml').then(yaml => {
|
||||
cy.setDevfile(yaml);
|
||||
});
|
||||
|
||||
cy.selectTab(TAB_CONTAINERS);
|
||||
|
||||
cy.getByDataCy('container-name').type('my-new-container');
|
||||
cy.getByDataCy('container-image').type('an-image');
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
|
||||
cy.getByDataCy('volume-mount-path-0').type("/mnt/vol2", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-0').click().get('mat-option').contains('volume2').click();
|
||||
cy.getByDataCy('volume-mount-path-1').type("/mnt/vol3", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-1').click().get('mat-option').contains('volume3').click();
|
||||
cy.getByDataCy('volume-mount-path-2').type("/mnt/vol1", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-2').click().get('mat-option').contains('volume1').click();
|
||||
cy.getByDataCy('volume-mount-minus-1').click();
|
||||
cy.getByDataCy('container-create').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'volume2')
|
||||
.should('contain.text', '/mnt/vol2')
|
||||
.should('contain.text', 'volume1')
|
||||
.should('contain.text', '/mnt/vol1')
|
||||
.should('not.contain.text', 'volume3')
|
||||
.should('not.contain.text', '/mnt/vol3');
|
||||
|
||||
//Edit
|
||||
cy.getByDataCy('container-edit').last().click();
|
||||
cy.getByDataCy('volume-mount-name-0').should('have.text', 'volume2');
|
||||
cy.getByDataCy('volume-mount-path-0').should('have.value', '/mnt/vol2');
|
||||
cy.getByDataCy('volume-mount-name-1').should('have.text', 'volume1');
|
||||
cy.getByDataCy('volume-mount-path-1').should('have.value', '/mnt/vol1');
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-path-2').type("/mnt/vol2", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-2').click().get('mat-option').contains('volume2').click();
|
||||
cy.getByDataCy('volume-mount-minus-4').click();
|
||||
cy.getByDataCy('volume-mount-minus-0').click();
|
||||
cy.getByDataCy('volume-mount-path-2').type("/mnt/vol3", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-2').click().get('mat-option').contains('volume3').click();
|
||||
cy.getByDataCy('container-save').click();
|
||||
|
||||
cy.getByDataCy('container-info').last()
|
||||
.should('contain.text', 'my-new-container')
|
||||
.should('contain.text', 'volume1')
|
||||
.should('contain.text', '/mnt/vol1')
|
||||
.should('contain.text', 'volume2')
|
||||
.should('contain.text', '/mnt/vol2')
|
||||
.should('contain.text', 'volume3')
|
||||
.should('contain.text', '/mnt/vol3');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -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:
|
||||
|
||||
12
ui/cypress/fixtures/input/with-volume.yaml
Normal file
12
ui/cypress/fixtures/input/with-volume.yaml
Normal file
@@ -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
|
||||
@@ -1,2 +1,17 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
button.adjust-position {
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
@@ -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" class="adjust-position" mat-icon-button matTooltip="Delete endpoint" (click)="removeEndpoint(i)">
|
||||
<mat-icon class="tab-icon material-icons-outlined">delete_forever</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>
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
h3 { margin-bottom: 0; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
|
||||
button.adjust-position {
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
<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" class="adjust-position" mat-icon-button matTooltip="Delete command" (click)="removeCommand(i)">
|
||||
<mat-icon class="tab-icon material-icons-outlined">delete_forever</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>
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
div.group { margin-bottom: 16px; }
|
||||
.mid-width { width: 50%; }
|
||||
.kv-width { width: 45%; }
|
||||
|
||||
button.adjust-position {
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
|
||||
@@ -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" class="adjust-position" mat-icon-button [matTooltip]="deleteLabel" (click)="removeEntry(i)">
|
||||
<mat-icon class="tab-icon material-icons-outlined">delete_forever</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>
|
||||
@@ -38,6 +38,7 @@ export class MultiKeyValueComponent implements ControlValueAccessor, Validator {
|
||||
|
||||
@Input() dataCyPrefix: string = "";
|
||||
@Input() addLabel: string = "";
|
||||
@Input() deleteLabel: string = "";
|
||||
|
||||
form = new FormArray<FormGroup>([]);
|
||||
|
||||
@@ -71,6 +72,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) {
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
h3 { margin-bottom: 0; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
|
||||
button.adjust-position {
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
<h3 *ngIf="title">{{title}}</h3>
|
||||
<div class="group">
|
||||
<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">
|
||||
</mat-form-field>
|
||||
</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>
|
||||
<mat-card *ngIf="form.controls.length > 0">
|
||||
<mat-card-content>
|
||||
<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 [attr.data-cy]="dataCyPrefix+'-text-'+i" matInput [formControl]="control">
|
||||
</mat-form-field>
|
||||
<button [attr.data-cy]="dataCyPrefix+'-minus-'+i" class="adjust-position" mat-icon-button [matTooltip]="deleteLabel" (click)="removeText(i)">
|
||||
<mat-icon class="tab-icon material-icons-outlined">delete_forever</mat-icon>
|
||||
</button>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button [attr.data-cy]="'add-text'" mat-flat-button (click)="addText('')">{{addLabel}}</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
<button *ngIf="form.controls.length == 0" [attr.data-cy]="'add-text'" mat-flat-button (click)="addText('')">{{addLabel}}</button>
|
||||
</div>
|
||||
@@ -30,8 +30,10 @@ import {
|
||||
})
|
||||
export class MultiTextComponent implements ControlValueAccessor, Validator {
|
||||
|
||||
@Input() dataCyPrefix: string = "";
|
||||
@Input() label: string = "";
|
||||
@Input() addLabel: string = "";
|
||||
@Input() deleteLabel: string = "";
|
||||
@Input() title: string = "";
|
||||
|
||||
onChange = (_: string[]) => {};
|
||||
@@ -62,6 +64,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) {
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
h3 { margin-bottom: 0; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
div.group { margin-bottom: 16px; }
|
||||
|
||||
button.adjust-position {
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
@@ -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" class="adjust-position" mat-icon-button matTooltip="Delete Volume Mount" (click)="remove(i)">
|
||||
<mat-icon class="tab-icon material-icons-outlined">delete_forever</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>
|
||||
|
||||
|
||||
@@ -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 == "!";
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
</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" deleteLabel="Delete command"></app-multi-text>
|
||||
<app-multi-text dataCyPrefix="container-arg" formControlName="args" label="Arg" addLabel="Add arg" deleteLabel="Delete arg"></app-multi-text>
|
||||
|
||||
<h3>Environment Variables</h3>
|
||||
<div class="description">Environment Variables to define in the running container</div>
|
||||
<app-multi-key-value dataCyPrefix="container-env" addLabel="Add Environment Variable" formControlName="env"></app-multi-key-value>
|
||||
<app-multi-key-value dataCyPrefix="container-env" addLabel="Add Environment Variable" deleteLabel="Delete Environment Variable" formControlName="env"></app-multi-key-value>
|
||||
|
||||
<h3>Volume Mounts</h3>
|
||||
<div class="description">Volumes to mount into the container's filesystem</div>
|
||||
@@ -76,11 +76,11 @@
|
||||
|
||||
<h3>Deployment Annotations</h3>
|
||||
<div class="description">Annotations added to the Kubernetes Deployment created for running this container</div>
|
||||
<app-multi-key-value dataCyPrefix="container-deploy-anno" addLabel="Add Annotation" formControlName="deployAnnotations"></app-multi-key-value>
|
||||
<app-multi-key-value dataCyPrefix="container-deploy-anno" addLabel="Add Annotation" deleteLabel="Delete Deployment Annotation" formControlName="deployAnnotations"></app-multi-key-value>
|
||||
|
||||
<h3>Service Annotations</h3>
|
||||
<div class="description">Annotations added to the Kubernetes Service created for accessing this container</div>
|
||||
<app-multi-key-value dataCyPrefix="container-svc-anno" addLabel="Add Annotation" formControlName="svcAnnotations"></app-multi-key-value>
|
||||
<app-multi-key-value dataCyPrefix="container-svc-anno" addLabel="Add Annotation" deleteLabel="Delete Service Annotation" formControlName="svcAnnotations"></app-multi-key-value>
|
||||
</div>
|
||||
|
||||
<div class="outbutton"><button data-cy="container-less-params" *ngIf="seeMore" mat-flat-button (click)="less()">Less parameters...</button></div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<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" deleteLabel="Delete Build Args"></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">
|
||||
|
||||
Reference in New Issue
Block a user