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

feat(cyclops-ui): Dropdown menu to accept other then just enum fields #620

Merged
Show file tree
Hide file tree
Changes from all 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: 2 additions & 0 deletions cyclops-ctrl/internal/mapper/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func HelmSchemaToFields(name string, schema helm.Property, defs map[string]helm.
Properties: dependency.RootField.Properties,
Items: dependency.RootField.Items,
Enum: dependency.RootField.Enum,
Suggestions: dependency.RootField.Suggestions,
Required: dependency.RootField.Required,
FileExtension: dependency.RootField.FileExtension,
Minimum: dependency.RootField.Minimum,
Expand All @@ -80,6 +81,7 @@ func HelmSchemaToFields(name string, schema helm.Property, defs map[string]helm.
ManifestKey: name,
Properties: fields,
Enum: schema.Enum,
Suggestions: schema.Suggestions,
Required: schema.Required,
FileExtension: schema.FileExtension,
Minimum: schema.Minimum,
Expand Down
1 change: 1 addition & 0 deletions cyclops-ctrl/internal/models/helm/helmschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Property struct {
Properties map[string]Property `json:"properties"`
Items *Property `json:"items"`
Enum []interface{} `json:"enum"`
Suggestions []interface{} `json:"x-suggestions"`
Required []string `json:"required"`
FileExtension string `json:"fileExtension"`
Reference string `json:"$ref"`
Expand Down
1 change: 1 addition & 0 deletions cyclops-ctrl/internal/models/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Field struct {
Properties []Field `json:"properties"`
Items *Field `json:"items"`
Enum []interface{} `json:"enum"`
Suggestions []interface{} `json:"x-suggestions"`
Required []string `json:"required"`
FileExtension string `json:"fileExtension"`
Immutable bool `json:"immutable"`
Expand Down
14 changes: 13 additions & 1 deletion cyclops-ui/src/components/form/TemplateFormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Alert, Row } from "antd";
import { WarningTwoTone } from "@ant-design/icons";
import Link from "antd/lib/typography/Link";
import { SuggestionInputField } from "./fields/string/SuggestionInput";

interface Props {
isModuleEdit: boolean;
Expand Down Expand Up @@ -67,7 +68,6 @@ export function mapFields(
if (arrayIndexLifetime > 0) {
arrayIndexLifetime = arrayIndexLifetime - 1;
}

switch (field.type) {
case "string":
if (field.enum) {
Expand All @@ -82,6 +82,18 @@ export function mapFields(
);
return;
}
if (field["x-suggestions"]) {
formFields.push(
<SuggestionInputField
field={field}
formItemName={formItemName}
arrayField={arrayField}
isRequired={isRequired}
isModuleEdit={isModuleEdit}
/>,
);
return;
}

if (field.fileExtension && field.fileExtension.length > 0) {
formFields.push(
Expand Down
137 changes: 137 additions & 0 deletions cyclops-ui/src/components/form/fields/string/SuggestionInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React, { useState } from "react";
import { Button, Col, Divider, Form, Input, Row, Select } from "antd";
import { PlusOutlined } from "@ant-design/icons";

interface Option {
value: string;
label: string;
}

interface Props {
field: any;
formItemName: string | string[];
arrayField: any;
isRequired: boolean;
isModuleEdit: boolean;
}

export const SuggestionInputField = ({
field,
formItemName,
arrayField,
isRequired,
isModuleEdit,
}: Props) => {
const [suggestedOptions, setSuggestedOptions] = useState<Option[]>([]);
const [newOption, setNewOption] = useState("");

const selectOptions = (field: any) => {
let options: Option[] = [];

if (!field || !field["x-suggestions"]) {
return options;
}

field["x-suggestions"].forEach((option: any) => {
options.push({
value: option,
label: option,
});
});

return options;
};

const addNewOption = (
e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,
) => {
e.preventDefault();
if (
newOption !== "" &&
!suggestedOptions.find((option) => option.label === newOption) &&
!selectOptions(field).find((option) => option.label === newOption)
) {
setSuggestedOptions((prev) => [
...prev,
{ value: newOption, label: newOption },
]);
setNewOption("");
}
};

const addOptionOnEnter = () => {
if (newOption !== "") {
setSuggestedOptions((prev) => [
...prev,
{ value: newOption, label: newOption },
]);
setNewOption("");
}
};

return (
<Form.Item
{...arrayField}
name={formItemName}
rules={[{ required: isRequired }]}
style={{
paddingTop: "8px",
marginBottom: "12px",
}}
label={
<div>
{field.display_name}
<p style={{ color: "#8b8e91", marginBottom: "0px" }}>
{field.description}
</p>
</div>
}
>
<Select
showSearch
placeholder={field.name}
optionFilterProp="children"
onSearch={(value) => {
setNewOption(value);
}}
filterOption={(input, option) => {
return (option?.label ?? "")
.toLowerCase()
.includes(input.toLowerCase());
}}
options={[...selectOptions(field), ...suggestedOptions]}
disabled={field.immutable && isModuleEdit}
dropdownRender={(menu) => (
<>
{menu}
<Divider style={{ margin: "8px 0" }} />
<Row>
<Col span={16}>
<Input
placeholder="Enter New Option"
value={newOption}
onChange={(event) => setNewOption(event.target.value)}
onKeyDown={(e) => {
e.stopPropagation();
if (e.key === "Enter") {
addOptionOnEnter();
}
}}
/>
</Col>
<Col span={8}>
<Button
type="text"
icon={<PlusOutlined />}
onClick={addNewOption}
>
Add New Option
</Button>
</Col>
</Row>
</>
)}
/>
</Form.Item>
);
};
Loading