diff --git a/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.test.tsx b/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.test.tsx
index 63e58be7d4..08aec0def0 100644
--- a/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.test.tsx
+++ b/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.test.tsx
@@ -34,6 +34,46 @@ describe("BasePowerField", () => {
expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
});
+ it("correctly renders a IP address field type", () => {
+ const field = factory.powerField({ field_type: PowerFieldType.IP_ADDRESS });
+ render(
+
+
+
+ );
+ expect(screen.getByRole("textbox")).toBeInTheDocument();
+ expect(screen.getByRole("textbox")).not.toHaveAttribute("type", "password");
+ expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
+ });
+
+ it("correctly renders a Virsh address field type", () => {
+ const field = factory.powerField({
+ field_type: PowerFieldType.VIRSH_ADDRESS,
+ });
+ render(
+
+
+
+ );
+ expect(screen.getByRole("textbox")).toBeInTheDocument();
+ expect(screen.getByRole("textbox")).not.toHaveAttribute("type", "password");
+ expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
+ });
+
+ it("correctly renders a LXD address field type", () => {
+ const field = factory.powerField({
+ field_type: PowerFieldType.LXD_ADDRESS,
+ });
+ render(
+
+
+
+ );
+ expect(screen.getByRole("textbox")).toBeInTheDocument();
+ expect(screen.getByRole("textbox")).not.toHaveAttribute("type", "password");
+ expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
+ });
+
it("correctly renders a password field type", () => {
const field = factory.powerField({
field_type: PowerFieldType.PASSWORD,
diff --git a/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.tsx b/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.tsx
index 6c5b4fc435..067f2dca68 100644
--- a/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.tsx
+++ b/src/app/base/components/PowerTypeFields/BasePowerField/BasePowerField.tsx
@@ -70,7 +70,11 @@ export const BasePowerField = ({
}
required={required}
type={
- (field_type === PowerFieldType.STRING && "text") ||
+ ((field_type === PowerFieldType.STRING ||
+ field_type === PowerFieldType.IP_ADDRESS ||
+ field_type === PowerFieldType.VIRSH_ADDRESS ||
+ field_type === PowerFieldType.LXD_ADDRESS) &&
+ "text") ||
(field_type === PowerFieldType.PASSWORD && "password") ||
undefined
}
diff --git a/src/app/store/general/types/enum.ts b/src/app/store/general/types/enum.ts
index 408f39c5dd..48f91894f7 100644
--- a/src/app/store/general/types/enum.ts
+++ b/src/app/store/general/types/enum.ts
@@ -46,4 +46,7 @@ export enum PowerFieldType {
MULTIPLE_CHOICE = "multiple_choice",
PASSWORD = "password",
STRING = "string",
+ IP_ADDRESS = "ip_address",
+ VIRSH_ADDRESS = "virsh_address",
+ LXD_ADDRESS = "lxd_address",
}
diff --git a/src/app/store/general/utils/powerTypes.ts b/src/app/store/general/utils/powerTypes.ts
index 4d08914425..06409386cd 100644
--- a/src/app/store/general/utils/powerTypes.ts
+++ b/src/app/store/general/utils/powerTypes.ts
@@ -1,3 +1,4 @@
+import { isIP } from "is-ip";
import * as Yup from "yup";
import type { ObjectShape } from "yup/lib/object";
@@ -50,6 +51,23 @@ export const formatPowerParameters = (
return params;
}, {}) || {};
+const getPowerFieldSchema = (fieldType: PowerFieldType) => {
+ switch (fieldType) {
+ case PowerFieldType.MULTIPLE_CHOICE:
+ return Yup.array().of(Yup.string());
+ case PowerFieldType.IP_ADDRESS:
+ case PowerFieldType.VIRSH_ADDRESS:
+ case PowerFieldType.LXD_ADDRESS:
+ return Yup.string().test({
+ name: "is-ip-address",
+ message: "Please enter a valid IP address.",
+ test: (value) => isIP(value as string),
+ });
+ default:
+ return Yup.string();
+ }
+};
+
/**
* Generates a Yup validation object shape for power parameters based on the
* selected power type and the field scopes.
@@ -63,10 +81,7 @@ export const generatePowerParametersSchema = (
): ObjectShape =>
powerType?.fields?.reduce((schema, field) => {
if (fieldScopes.includes(field.scope)) {
- let fieldSchema =
- field.field_type === PowerFieldType.MULTIPLE_CHOICE
- ? Yup.array().of(Yup.string())
- : Yup.string();
+ let fieldSchema = getPowerFieldSchema(field.field_type);
if (field.required) {
fieldSchema = fieldSchema.required(`${field.label} required`);
}
diff --git a/yarn.lock b/yarn.lock
index 56fa96cca9..f5a44a2bae 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12976,7 +12976,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
-"string-width-cjs@npm:string-width@^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -12994,15 +12994,6 @@ string-width@^4.1.0, string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
-string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@@ -13068,7 +13059,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -13082,13 +13073,6 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
-strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
@@ -14332,7 +14316,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -14350,15 +14334,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"