mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
[ui] Edit container (#7077)
* [api] patch container * [ui] edit container * [ui] Initialize endpoint component * e2e tests * static ui files
This commit is contained in:
@@ -116,6 +116,118 @@ describe('devfile editor spec', () => {
|
||||
.should('contain.text', 'volume2');
|
||||
});
|
||||
|
||||
|
||||
it.only('displays a modified container', () => {
|
||||
cy.init();
|
||||
|
||||
cy.selectTab(TAB_VOLUMES);
|
||||
cy.getByDataCy('volume-name').type('volume1');
|
||||
cy.getByDataCy('volume-size').type('512Mi');
|
||||
cy.getByDataCy('volume-ephemeral').click();
|
||||
cy.getByDataCy('volume-create').click();
|
||||
|
||||
cy.selectTab(TAB_CONTAINERS);
|
||||
cy.getByDataCy('container-name').type('created-container');
|
||||
cy.getByDataCy('container-image').type('an-image');
|
||||
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-name-1').type("VAR2");
|
||||
cy.getByDataCy('container-env-value-1').type("val2");
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-name-2').type("VAR3");
|
||||
cy.getByDataCy('container-env-value-2').type("val3");
|
||||
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-path-0').type("/mnt/vol1", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-0').click().get('mat-option').contains('volume1').click();
|
||||
|
||||
cy.getByDataCy('endpoints-add').click();
|
||||
cy.getByDataCy('endpoint-name-0').type("ep1");
|
||||
cy.getByDataCy('endpoint-targetPort-0').type("4001");
|
||||
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-path-1').type("/mnt/vol2", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-1').click().get('mat-option').contains('(New Volume)').click();
|
||||
cy.getByDataCy('volume-name').type('volume2');
|
||||
cy.getByDataCy('volume-create').click();
|
||||
|
||||
cy.getByDataCy('container-more-params').click();
|
||||
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-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-name-1').type("SVCANNO2");
|
||||
cy.getByDataCy('container-svc-anno-value-1').type("svcval2");
|
||||
|
||||
cy.getByDataCy('container-create').click();
|
||||
|
||||
cy.getByDataCy('container-edit').click();
|
||||
|
||||
cy.getByDataCy('container-image').type('{selectAll}{del}another-image');
|
||||
cy.getByDataCy('container-env-plus').click();
|
||||
cy.getByDataCy('container-env-name-3').type("VAR4");
|
||||
cy.getByDataCy('container-env-value-3').type("val4");
|
||||
|
||||
cy.getByDataCy('volume-mount-path-0').type("{selectAll}{del}/mnt/other/vol1", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-0').click().get('mat-option').contains('volume1').click();
|
||||
|
||||
cy.getByDataCy('endpoint-targetPort-0').type("{selectAll}{del}4002");
|
||||
|
||||
cy.getByDataCy('volume-mount-add').click();
|
||||
cy.getByDataCy('volume-mount-path-2').type("/mnt/vol3", {force: true});
|
||||
cy.getByDataCy('volume-mount-name-2').click().get('mat-option').contains('(New Volume)').click();
|
||||
cy.getByDataCy('volume-name').type('volume3');
|
||||
cy.getByDataCy('volume-create').click();
|
||||
|
||||
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-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-name-2').type("SVCANNO3");
|
||||
cy.getByDataCy('container-svc-anno-value-2').type("svcval3");
|
||||
|
||||
cy.getByDataCy('container-save').click();
|
||||
|
||||
cy.getByDataCy('container-info').first()
|
||||
.should('contain.text', 'another-image')
|
||||
.should('contain.text', 'VAR1: val1')
|
||||
.should('contain.text', 'VAR2: val2')
|
||||
.should('contain.text', 'VAR3: val3')
|
||||
.should('contain.text', 'VAR4: val4')
|
||||
.should('contain.text', 'volume1')
|
||||
.should('contain.text', '/mnt/other/vol1')
|
||||
.should('contain.text', 'volume2')
|
||||
.should('contain.text', '/mnt/vol2')
|
||||
.should('not.contain.text', 'Mount Sources')
|
||||
.should('contain.text', 'ep1')
|
||||
.should('contain.text', '4002')
|
||||
.should('contain.text', 'Deployment Annotations')
|
||||
.should('contain.text', 'DEPANNO1b: depval1b')
|
||||
.should('contain.text', 'DEPANNO2: depval2')
|
||||
.should('contain.text', 'DEPANNO3: depval3')
|
||||
.should('contain.text', 'Service Annotations')
|
||||
.should('contain.text', 'SVCANNO1b: svcval1b')
|
||||
.should('contain.text', 'SVCANNO2: svcval2')
|
||||
.should('contain.text', 'SVCANNO3: svcval3');
|
||||
|
||||
cy.selectTab(TAB_VOLUMES);
|
||||
cy.getByDataCy('volume-info').eq(1)
|
||||
.should('contain.text', 'volume2');
|
||||
});
|
||||
|
||||
it('displays a created container with source configuration', () => {
|
||||
cy.init();
|
||||
|
||||
|
||||
1
ui/src/app/api-gen/.openapi-generator/FILES
generated
1
ui/src/app/api-gen/.openapi-generator/FILES
generated
@@ -25,6 +25,7 @@ model/devstateCommandCommandNameMovePostRequest.ts
|
||||
model/devstateCommandCommandNameSetDefaultPostRequest.ts
|
||||
model/devstateCompositeCommandCommandNamePatchRequest.ts
|
||||
model/devstateCompositeCommandPostRequest.ts
|
||||
model/devstateContainerContainerNamePatchRequest.ts
|
||||
model/devstateContainerPostRequest.ts
|
||||
model/devstateDevfilePutRequest.ts
|
||||
model/devstateEventsPutRequest.ts
|
||||
|
||||
71
ui/src/app/api-gen/api/devstate.service.ts
generated
71
ui/src/app/api-gen/api/devstate.service.ts
generated
@@ -35,6 +35,8 @@ import { DevstateCompositeCommandCommandNamePatchRequest } from '../model/devsta
|
||||
// @ts-ignore
|
||||
import { DevstateCompositeCommandPostRequest } from '../model/devstateCompositeCommandPostRequest';
|
||||
// @ts-ignore
|
||||
import { DevstateContainerContainerNamePatchRequest } from '../model/devstateContainerContainerNamePatchRequest';
|
||||
// @ts-ignore
|
||||
import { DevstateContainerPostRequest } from '../model/devstateContainerPostRequest';
|
||||
// @ts-ignore
|
||||
import { DevstateDevfilePutRequest } from '../model/devstateDevfilePutRequest';
|
||||
@@ -769,6 +771,75 @@ export class DevstateService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a container
|
||||
* @param containerName Container name to update
|
||||
* @param devstateContainerContainerNamePatchRequest
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
*/
|
||||
public devstateContainerContainerNamePatch(containerName: string, devstateContainerContainerNamePatchRequest?: DevstateContainerContainerNamePatchRequest, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<DevfileContent>;
|
||||
public devstateContainerContainerNamePatch(containerName: string, devstateContainerContainerNamePatchRequest?: DevstateContainerContainerNamePatchRequest, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<DevfileContent>>;
|
||||
public devstateContainerContainerNamePatch(containerName: string, devstateContainerContainerNamePatchRequest?: DevstateContainerContainerNamePatchRequest, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<DevfileContent>>;
|
||||
public devstateContainerContainerNamePatch(containerName: string, devstateContainerContainerNamePatchRequest?: DevstateContainerContainerNamePatchRequest, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
|
||||
if (containerName === null || containerName === undefined) {
|
||||
throw new Error('Required parameter containerName was null or undefined when calling devstateContainerContainerNamePatch.');
|
||||
}
|
||||
|
||||
let localVarHeaders = this.defaultHeaders;
|
||||
|
||||
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
|
||||
if (localVarHttpHeaderAcceptSelected === undefined) {
|
||||
// to determine the Accept header
|
||||
const httpHeaderAccepts: string[] = [
|
||||
'application/json'
|
||||
];
|
||||
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
|
||||
}
|
||||
if (localVarHttpHeaderAcceptSelected !== undefined) {
|
||||
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
|
||||
}
|
||||
|
||||
let localVarHttpContext: HttpContext | undefined = options && options.context;
|
||||
if (localVarHttpContext === undefined) {
|
||||
localVarHttpContext = new HttpContext();
|
||||
}
|
||||
|
||||
|
||||
// to determine the Content-Type header
|
||||
const consumes: string[] = [
|
||||
'application/json'
|
||||
];
|
||||
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
|
||||
if (httpContentTypeSelected !== undefined) {
|
||||
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
|
||||
}
|
||||
|
||||
let responseType_: 'text' | 'json' | 'blob' = 'json';
|
||||
if (localVarHttpHeaderAcceptSelected) {
|
||||
if (localVarHttpHeaderAcceptSelected.startsWith('text')) {
|
||||
responseType_ = 'text';
|
||||
} else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) {
|
||||
responseType_ = 'json';
|
||||
} else {
|
||||
responseType_ = 'blob';
|
||||
}
|
||||
}
|
||||
|
||||
let localVarPath = `/devstate/container/${this.configuration.encodeParam({name: "containerName", value: containerName, in: "path", style: "simple", explode: false, dataType: "string", dataFormat: undefined})}`;
|
||||
return this.httpClient.request<DevfileContent>('patch', `${this.configuration.basePath}${localVarPath}`,
|
||||
{
|
||||
context: localVarHttpContext,
|
||||
body: devstateContainerContainerNamePatchRequest,
|
||||
responseType: <any>responseType_,
|
||||
withCredentials: this.configuration.withCredentials,
|
||||
headers: localVarHeaders,
|
||||
observe: observe,
|
||||
reportProgress: reportProgress
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new container to the Devfile
|
||||
* @param devstateContainerPostRequest
|
||||
|
||||
73
ui/src/app/api-gen/model/devstateContainerContainerNamePatchRequest.ts
generated
Normal file
73
ui/src/app/api-gen/model/devstateContainerContainerNamePatchRequest.ts
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* odo dev
|
||||
* API interface for \'odo dev\'
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
import { Endpoint } from './endpoint';
|
||||
import { VolumeMount } from './volumeMount';
|
||||
import { Env } from './env';
|
||||
import { Annotation } from './annotation';
|
||||
|
||||
|
||||
export interface DevstateContainerContainerNamePatchRequest {
|
||||
/**
|
||||
* Container image
|
||||
*/
|
||||
image: string;
|
||||
/**
|
||||
* Entrypoint of the container
|
||||
*/
|
||||
command?: Array<string>;
|
||||
/**
|
||||
* Args passed to the Container entrypoint
|
||||
*/
|
||||
args?: Array<string>;
|
||||
/**
|
||||
* Environment variables to define
|
||||
*/
|
||||
env?: Array<Env>;
|
||||
/**
|
||||
* Requested memory for the deployed container
|
||||
*/
|
||||
memReq?: string;
|
||||
/**
|
||||
* Memory limit for the deployed container
|
||||
*/
|
||||
memLimit?: string;
|
||||
/**
|
||||
* Requested CPU for the deployed container
|
||||
*/
|
||||
cpuReq?: string;
|
||||
/**
|
||||
* CPU limit for the deployed container
|
||||
*/
|
||||
cpuLimit?: string;
|
||||
/**
|
||||
* Volume to mount into the container filesystem
|
||||
*/
|
||||
volumeMounts?: Array<VolumeMount>;
|
||||
/**
|
||||
* If false, mountSources and sourceMapping values are not considered
|
||||
*/
|
||||
configureSources?: boolean;
|
||||
/**
|
||||
* If true, sources are mounted into container\'s filesystem
|
||||
*/
|
||||
mountSources?: boolean;
|
||||
/**
|
||||
* Specific directory on which to mount sources
|
||||
*/
|
||||
sourceMapping?: string;
|
||||
annotation?: Annotation;
|
||||
/**
|
||||
* Endpoints exposed by the container
|
||||
*/
|
||||
endpoints?: Array<Endpoint>;
|
||||
}
|
||||
|
||||
1
ui/src/app/api-gen/model/models.ts
generated
1
ui/src/app/api-gen/model/models.ts
generated
@@ -15,6 +15,7 @@ export * from './devstateCommandCommandNameMovePostRequest';
|
||||
export * from './devstateCommandCommandNameSetDefaultPostRequest';
|
||||
export * from './devstateCompositeCommandCommandNamePatchRequest';
|
||||
export * from './devstateCompositeCommandPostRequest';
|
||||
export * from './devstateContainerContainerNamePatchRequest';
|
||||
export * from './devstateContainerPostRequest';
|
||||
export * from './devstateDevfilePutRequest';
|
||||
export * from './devstateEventsPutRequest';
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Component, forwardRef } from '@angular/core';
|
||||
import { AbstractControl, ControlValueAccessor, FormArray, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator, Validators } from '@angular/forms';
|
||||
|
||||
interface Endpoint {
|
||||
|
||||
}
|
||||
import { Endpoint } from 'src/app/api-gen';
|
||||
|
||||
@Component({
|
||||
selector: 'app-endpoints',
|
||||
@@ -35,23 +32,29 @@ export class EndpointsComponent implements ControlValueAccessor, Validator {
|
||||
});
|
||||
}
|
||||
|
||||
newEndpoint(): FormGroup {
|
||||
newEndpoint(ep: Endpoint): FormGroup {
|
||||
return new FormGroup({
|
||||
name: new FormControl("", [Validators.required]),
|
||||
targetPort: new FormControl("", [Validators.required, Validators.pattern("^[0-9]*$")]),
|
||||
exposure: new FormControl(""),
|
||||
path: new FormControl(""),
|
||||
protocol: new FormControl(""),
|
||||
secure: new FormControl(false),
|
||||
name: new FormControl(ep.name, [Validators.required]),
|
||||
targetPort: new FormControl(ep.targetPort, [Validators.required, Validators.pattern("^[0-9]*$")]),
|
||||
exposure: new FormControl(ep.exposure),
|
||||
path: new FormControl(ep.path),
|
||||
protocol: new FormControl(ep.protocol),
|
||||
secure: new FormControl(ep.secure),
|
||||
});
|
||||
}
|
||||
|
||||
addEndpoint() {
|
||||
this.form.push(this.newEndpoint());
|
||||
this.form.push(this.newEndpoint({
|
||||
name: '',
|
||||
targetPort: 0,
|
||||
}));
|
||||
}
|
||||
|
||||
/* ControlValueAccessor implementation */
|
||||
writeValue(value: Endpoint[]) {
|
||||
value.forEach(ep => {
|
||||
this.form.push(this.newEndpoint(ep));
|
||||
});
|
||||
}
|
||||
|
||||
registerOnChange(onChange: any) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<div class="main">
|
||||
<h2>Add a new container</h2>
|
||||
<h2 *ngIf="!container">Add a new container</h2>
|
||||
<h2 *ngIf="container">Edit container <i>{{container.name}}</i></h2>
|
||||
<div class="description">A Container is used to execute shell commands into a specific environment. The entrypoint of the container must be a non-terminating command. You can use an image pulled from a registry or an image built by an Image command.</div>
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field appearance="outline" class="mid-width">
|
||||
@@ -86,7 +87,8 @@
|
||||
</form>
|
||||
|
||||
<div class="buttonbar">
|
||||
<button data-cy="container-create" [disabled]="form.invalid" mat-flat-button color="primary" matTooltip="create new container" (click)="create()">Create</button>
|
||||
<button *ngIf="!container" data-cy="container-create" [disabled]="form.invalid" mat-flat-button color="primary" matTooltip="create new container" (click)="create()">Create</button>
|
||||
<button *ngIf="container" data-cy="container-save" [disabled]="form.invalid" mat-flat-button color="primary" matTooltip="save container" (click)="save()">Save</button>
|
||||
<button *ngIf="cancelable" mat-flat-button (click)="cancel()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output, SimpleChanges } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { PATTERN_COMPONENT_ID } from '../patterns';
|
||||
import { DevstateService } from 'src/app/services/devstate.service';
|
||||
@@ -18,8 +18,11 @@ export interface ToCreate {
|
||||
export class ContainerComponent {
|
||||
@Input() volumeNames: string[] = [];
|
||||
@Input() cancelable: boolean = false;
|
||||
@Input() container: Container | undefined;
|
||||
|
||||
@Output() canceled = new EventEmitter<void>();
|
||||
@Output() created = new EventEmitter<ToCreate>();
|
||||
@Output() saved = new EventEmitter<ToCreate>();
|
||||
|
||||
form: FormGroup;
|
||||
|
||||
@@ -79,17 +82,27 @@ export class ContainerComponent {
|
||||
}
|
||||
}
|
||||
|
||||
toObject(o: {name: string, value: string}[]) {
|
||||
if (o == null) {
|
||||
return {};
|
||||
}
|
||||
return o.reduce((acc: any, val: {name: string, value: string}) => { acc[val.name] = val.value; return acc; }, {});
|
||||
};
|
||||
|
||||
fromObject(o: any) {
|
||||
if (o == null) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(o).map(k => ({ name: k, value: o[k]}));
|
||||
}
|
||||
|
||||
create() {
|
||||
this.telemetry.track("[ui] create container");
|
||||
|
||||
const toObject = (o: {name: string, value: string}[]) => {
|
||||
return o.reduce((acc: any, val: {name: string, value: string}) => { acc[val.name] = val.value; return acc; }, {});
|
||||
};
|
||||
|
||||
const container = this.form.value;
|
||||
container.annotation = {
|
||||
deployment: toObject(container.deployAnnotations),
|
||||
service: toObject(container.svcAnnotations),
|
||||
deployment: this.toObject(container.deployAnnotations),
|
||||
service: this.toObject(container.svcAnnotations),
|
||||
};
|
||||
this.created.emit({
|
||||
container: this.form.value,
|
||||
@@ -97,10 +110,43 @@ export class ContainerComponent {
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
this.telemetry.track("[ui] edit container");
|
||||
const newValue = this.form.value;
|
||||
newValue.name = this.container?.name;
|
||||
newValue.annotation = {
|
||||
deployment: this.toObject(newValue.deployAnnotations),
|
||||
service: this.toObject(newValue.svcAnnotations),
|
||||
};
|
||||
this.saved.emit({
|
||||
container: newValue,
|
||||
volumes: this.volumesToCreate,
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.canceled.emit();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!changes['container']) {
|
||||
return;
|
||||
}
|
||||
const container = changes['container'].currentValue;
|
||||
if (container == undefined) {
|
||||
this.form.get('name')?.enable();
|
||||
} else {
|
||||
this.form.reset();
|
||||
this.form.patchValue(container);
|
||||
this.form.get('name')?.disable();
|
||||
if (this.form.get('sourceMapping')?.value != '') {
|
||||
this.form.get('_specificDir')?.setValue(true);
|
||||
}
|
||||
this.form.get('deployAnnotations')?.setValue(this.fromObject(container.annotation.deployment));
|
||||
this.form.get('svcAnnotations')?.setValue(this.fromObject(container.annotation.service));
|
||||
}
|
||||
}
|
||||
|
||||
onCreateNewVolume(v: Volume) {
|
||||
this.volumesToCreate.push(v);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,28 @@ export class DevstateService {
|
||||
});
|
||||
}
|
||||
|
||||
saveContainer(container: Container): Observable<DevfileContent> {
|
||||
return this.http.patch<DevfileContent>(this.base+"/container/"+container.name, {
|
||||
image: container.image,
|
||||
command: container.command,
|
||||
args: container.args,
|
||||
env: container.env,
|
||||
memReq: container.memoryRequest,
|
||||
memLimit: container.memoryLimit,
|
||||
cpuReq: container.cpuRequest,
|
||||
cpuLimit: container.cpuLimit,
|
||||
volumeMounts: container.volumeMounts,
|
||||
configureSources: container.configureSources,
|
||||
mountSources: container.mountSources,
|
||||
sourceMapping: container.sourceMapping,
|
||||
annotation: {
|
||||
deployment: container.annotation.deployment,
|
||||
service: container.annotation.service
|
||||
},
|
||||
endpoints: container.endpoints,
|
||||
});
|
||||
}
|
||||
|
||||
addImage(image: Image): Observable<DevfileContent> {
|
||||
return this.http.post<DevfileContent>(this.base+"/image", {
|
||||
name: image.name,
|
||||
|
||||
@@ -99,21 +99,24 @@
|
||||
|
||||
<mat-card-actions>
|
||||
<button mat-button color="warn" (click)="delete(container.name)">Delete</button>
|
||||
<button data-cy="container-edit" mat-button (click)="edit(container)">Edit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</mat-card>
|
||||
|
||||
<app-container
|
||||
*ngIf="forceDisplayAdd || containers == undefined || containers.length == 0"
|
||||
*ngIf="forceDisplayForm || containers == undefined || containers.length == 0"
|
||||
[volumeNames]="volumeNames ?? []"
|
||||
[cancelable]="forceDisplayAdd"
|
||||
[cancelable]="forceDisplayForm"
|
||||
(canceled)="undisplayAddForm()"
|
||||
(created)="onCreated($event)"
|
||||
[container]="editingContainer"
|
||||
(saved)="onSaved($event)"
|
||||
></app-container>
|
||||
</div>
|
||||
|
||||
|
||||
<ng-container *ngIf="!forceDisplayAdd && containers != undefined && containers.length > 0">
|
||||
<ng-container *ngIf="!forceDisplayForm && containers != undefined && containers.length > 0">
|
||||
<button data-cy="add" class="fab" mat-fab color="primary" (click)="displayAddForm()">
|
||||
<mat-icon class="material-icons-outlined">add</mat-icon>
|
||||
</button>
|
||||
|
||||
@@ -11,10 +11,12 @@ import { ToCreate } from 'src/app/forms/container/container.component';
|
||||
})
|
||||
export class ContainersComponent implements OnInit {
|
||||
|
||||
forceDisplayAdd: boolean = false;
|
||||
forceDisplayForm: boolean = false;
|
||||
containers: Container[] | undefined = [];
|
||||
volumeNames: string[] | undefined = [];
|
||||
|
||||
editingContainer: Container | undefined;
|
||||
|
||||
constructor(
|
||||
private state: StateService,
|
||||
private devstate: DevstateService,
|
||||
@@ -28,19 +30,24 @@ export class ContainersComponent implements OnInit {
|
||||
if (this.containers == null) {
|
||||
return
|
||||
}
|
||||
that.forceDisplayAdd = false;
|
||||
that.forceDisplayForm = false;
|
||||
});
|
||||
}
|
||||
|
||||
displayAddForm() {
|
||||
this.forceDisplayAdd = true;
|
||||
this.editingContainer = undefined;
|
||||
this.displayForm();
|
||||
}
|
||||
|
||||
displayForm() {
|
||||
this.forceDisplayForm = true;
|
||||
setTimeout(() => {
|
||||
this.scrollToBottom();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
undisplayAddForm() {
|
||||
this.forceDisplayAdd = false;
|
||||
this.forceDisplayForm = false;
|
||||
}
|
||||
|
||||
delete(name: string) {
|
||||
@@ -73,6 +80,11 @@ export class ContainersComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
edit(container: Container) {
|
||||
this.editingContainer = container;
|
||||
this.displayForm();
|
||||
}
|
||||
|
||||
onCreated(toCreate: ToCreate) {
|
||||
const container = toCreate.container;
|
||||
this.createVolumes(toCreate.volumes, 0, () => {
|
||||
@@ -86,7 +98,21 @@ export class ContainersComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onSaved(toCreate: ToCreate) {
|
||||
const container = toCreate.container;
|
||||
this.createVolumes(toCreate.volumes, 0, () => {
|
||||
const result = this.devstate.saveContainer(container);
|
||||
result.subscribe({
|
||||
next: value => {
|
||||
this.state.changeDevfileYaml(value);
|
||||
},
|
||||
error: error => {
|
||||
alert(error.error.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
|
||||
Reference in New Issue
Block a user