Skip to content

Commit

Permalink
Validate of container name is already in use
Browse files Browse the repository at this point in the history
Fixes #609
  • Loading branch information
skobyda committed Oct 18, 2023
1 parent 5a74ca2 commit 9a509ca
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 8 deletions.
42 changes: 34 additions & 8 deletions src/ImageRunModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { Button } from "@patternfly/react-core/dist/esm/components/Button";
import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox";
import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form";
import { FormHelper } from "cockpit-components-form-helper.jsx";
import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect";
import { Grid, GridItem } from "@patternfly/react-core/dist/esm/layouts/Grid";
import { Modal } from "@patternfly/react-core/dist/esm/components/Modal";
Expand Down Expand Up @@ -258,7 +259,7 @@ export class ImageRunModal extends React.Component {
};

async onCreateClicked(runImage = false) {
if (!this.validateForm())
if (!await this.validateForm())
return;

const Dialogs = this.props.dialogs;
Expand Down Expand Up @@ -595,11 +596,21 @@ export class ImageRunModal extends React.Component {
// If at least one group is invalid, then the whole form is invalid
return validationFailed.publish?.some(groupHasError) ||
validationFailed.volumes?.some(groupHasError) ||
validationFailed.env?.some(groupHasError);
validationFailed.env?.some(groupHasError) ||
validationFailed.containerName;
};

validateForm = () => {
const { publish, volumes, env } = this.state;
async validateContainerName(containerName) {
try {
await client.containerExists(this.isSystem(), containerName);
} catch (error) {
return;
}
return _("Name already in use");
}

async validateForm() {
const { publish, volumes, env, containerName } = this.state;
const validationFailed = { };

const publishValidation = publish.map(a => {
Expand Down Expand Up @@ -630,10 +641,15 @@ export class ImageRunModal extends React.Component {
if (envValidation.some(entry => Object.keys(entry).length > 0))
validationFailed.env = envValidation;

const containerNameValidation = await this.validateContainerName(containerName);

if (containerNameValidation)
validationFailed.containerName = containerNameValidation;

this.setState({ validationFailed });

return this.isFormValid(validationFailed);
};
return !this.isFormInvalid(validationFailed);
}

/* Updates a validation object of the whole dynamic list's form (e.g. the whole port-mapping form)
*
Expand Down Expand Up @@ -708,12 +724,22 @@ export class ImageRunModal extends React.Component {
const defaultBody = (
<Form>
{this.state.dialogError && <ErrorNotification errorMessage={this.state.dialogError} errorDetail={this.state.dialogErrorDetail} />}
<FormGroup fieldId='run-image-dialog-name' label={_("Name")} className="ct-m-horizontal">
<FormGroup id="image-name-group" fieldId='run-image-dialog-name' label={_("Name")} className="ct-m-horizontal">
<TextInput id='run-image-dialog-name'
className="image-name"
placeholder={_("Container name")}
validated={dialogValues.validationFailed.containerName ? "error" : "default"}
value={dialogValues.containerName}
onChange={(_, value) => this.onValueChanged('containerName', value)} />
onChange={(_, value) => {
utils.validationClear(dialogValues.validationFailed, "containerName", (value) => this.onValueChanged("validationFailed", value));
utils.validationDebounce(async () => {
const delta = await this.validateContainerName(value);
if (delta)
this.onValueChanged("validationFailed", { ...dialogValues.validationFailed, containerName: delta });
});
this.onValueChanged('containerName', value);
}} />
<FormHelper helperTextInvalid={dialogValues.validationFailed.containerName} />
</FormGroup>
<Tabs activeKey={activeTabKey} onSelect={this.handleTabClick}>
<Tab eventKey={0} title={<TabTitleText>{_("Details")}</TabTitleText>} className="pf-v5-c-form pf-m-horizontal">
Expand Down
2 changes: 2 additions & 0 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,5 @@ export const pruneUnusedImages = system => podmanJson("libpod/images/prune?all=t
export const imageHistory = (system, id) => podmanJson(`libpod/images/${id}/history`, "GET", {}, system);

export const imageExists = (system, id) => podmanCall("libpod/images/" + id + "/exists", "GET", {}, system);

export const containerExists = (system, id) => podmanCall("libpod/containers/" + id + "/exists", "GET", {}, system);
2 changes: 2 additions & 0 deletions test/check-application
Original file line number Diff line number Diff line change
Expand Up @@ -2287,6 +2287,8 @@ class TestApplication(testlib.MachineCase):
b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create')
b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")')

validateField("#image-name-group", "registry", "Name already in use")

# Switch to Integration tab
b.click("#pf-tab-1-create-image-dialog-tab-integration")

Expand Down

0 comments on commit 9a509ca

Please sign in to comment.