From a648a84971c3ffaed600d20159618a55a62c31ea Mon Sep 17 00:00:00 2001 From: petar-cvit Date: Sat, 4 May 2024 22:46:52 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20edit=20template=20ref?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cyclops-ctrl/api/v1alpha1/client/modules.go | 5 + cyclops-ctrl/api/v1alpha1/module_types.go | 3 - .../api/v1alpha1/zz_generated.deepcopy.go | 15 + cyclops-ctrl/internal/controller/modules.go | 2 + .../modulecontroller/module_controller.go | 6 +- .../src/components/pages/EditModule.tsx | 270 ++++++++++++++---- .../src/components/pages/ModuleDetails.tsx | 72 +---- cyclops-ui/src/utils/templateRef.tsx | 70 +++++ 8 files changed, 324 insertions(+), 119 deletions(-) create mode 100644 cyclops-ui/src/utils/templateRef.tsx diff --git a/cyclops-ctrl/api/v1alpha1/client/modules.go b/cyclops-ctrl/api/v1alpha1/client/modules.go index c8125ac3..5208b044 100644 --- a/cyclops-ctrl/api/v1alpha1/client/modules.go +++ b/cyclops-ctrl/api/v1alpha1/client/modules.go @@ -2,6 +2,7 @@ package client import ( "context" + "fmt" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -66,6 +67,8 @@ func (c *moduleClient) Create(project *cyclopsv1alpha1.Module) (*cyclopsv1alpha1 // Update takes the representation of a service and updates it. Returns the server's representation of the service, and an error, if there is any. func (c *moduleClient) Update(module *cyclopsv1alpha1.Module) (project *cyclopsv1alpha1.Module, err error) { + fmt.Println("raw", module.Status) + result := &cyclopsv1alpha1.Module{} err = c.restClient.Put(). Namespace(c.ns). @@ -74,6 +77,8 @@ func (c *moduleClient) Update(module *cyclopsv1alpha1.Module) (project *cyclopsv Body(module). Do(context.TODO()). Into(result) + + fmt.Println("raw after", result.Status) return } diff --git a/cyclops-ctrl/api/v1alpha1/module_types.go b/cyclops-ctrl/api/v1alpha1/module_types.go index f9fd6c91..2ccd962f 100644 --- a/cyclops-ctrl/api/v1alpha1/module_types.go +++ b/cyclops-ctrl/api/v1alpha1/module_types.go @@ -26,9 +26,6 @@ import ( // ModuleSpec defines the desired state of Module type ModuleSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - TemplateRef TemplateRef `json:"template"` Values apiextensionsv1.JSON `json:"values"` } diff --git a/cyclops-ctrl/api/v1alpha1/zz_generated.deepcopy.go b/cyclops-ctrl/api/v1alpha1/zz_generated.deepcopy.go index 6150b8de..dbccb196 100644 --- a/cyclops-ctrl/api/v1alpha1/zz_generated.deepcopy.go +++ b/cyclops-ctrl/api/v1alpha1/zz_generated.deepcopy.go @@ -42,6 +42,21 @@ func (in *HistoryEntry) DeepCopy() *HistoryEntry { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HistoryTemplateRef) DeepCopyInto(out *HistoryTemplateRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HistoryTemplateRef. +func (in *HistoryTemplateRef) DeepCopy() *HistoryTemplateRef { + if in == nil { + return nil + } + out := new(HistoryTemplateRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Module) DeepCopyInto(out *Module) { *out = *in diff --git a/cyclops-ctrl/internal/controller/modules.go b/cyclops-ctrl/internal/controller/modules.go index 9caecade..20b9d628 100644 --- a/cyclops-ctrl/internal/controller/modules.go +++ b/cyclops-ctrl/internal/controller/modules.go @@ -256,6 +256,8 @@ func (m *Modules) UpdateModule(ctx *gin.Context) { return } + fmt.Println(module.Status) + history := curr.History if curr.History == nil { history = make([]v1alpha1.HistoryEntry, 0) diff --git a/cyclops-ctrl/internal/modulecontroller/module_controller.go b/cyclops-ctrl/internal/modulecontroller/module_controller.go index ad62f09e..0ab63977 100644 --- a/cyclops-ctrl/internal/modulecontroller/module_controller.go +++ b/cyclops-ctrl/internal/modulecontroller/module_controller.go @@ -128,7 +128,7 @@ func (r *ModuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr if err != nil { r.logger.Error(err, "error fetching module template", "namespaced name", req.NamespacedName) - if err = r.setStatus(ctx, module, req.NamespacedName, cyclopsv1alpha1.Failed, template.ResolvedVersion, err.Error(), nil); err != nil { + if err = r.setStatus(ctx, module, req.NamespacedName, cyclopsv1alpha1.Failed, templateVersion, err.Error(), nil); err != nil { return ctrl.Result{}, err } @@ -188,6 +188,9 @@ func (r *ModuleReconciler) generateResources(kClient *k8sclient.KubernetesClient return nil, err } + fmt.Println(module.Name) + fmt.Println(out) + installErrors := make([]string, 0) for _, s := range strings.Split(out, "---") { @@ -282,7 +285,6 @@ func (r *ModuleReconciler) setStatus( Reason: reason, Errors: installErrors, }, - TemplateResolvedVersion: trv, } if err := r.Status().Update(ctx, &module); err != nil { diff --git a/cyclops-ui/src/components/pages/EditModule.tsx b/cyclops-ui/src/components/pages/EditModule.tsx index 8428f730..76f7715d 100644 --- a/cyclops-ui/src/components/pages/EditModule.tsx +++ b/cyclops-ui/src/components/pages/EditModule.tsx @@ -6,11 +6,9 @@ import { Collapse, Divider, Form, - FormListFieldData, Input, InputNumber, message, - Modal, Row, Select, Space, @@ -23,10 +21,10 @@ import axios from "axios"; import { useNavigate } from "react-router"; import { InfoCircleOutlined, - LinkOutlined, + LockFilled, MinusCircleOutlined, PlusOutlined, - WarningFilled, + UnlockFilled, } from "@ant-design/icons"; import AceEditor from "react-ace"; @@ -44,6 +42,10 @@ import { fileExtension, flattenObjectKeys } from "../../utils/form"; import "./custom.css"; import { numberInputValidators } from "../../utils/validators/number"; import { stringInputValidators } from "../../utils/validators/string"; +import { + moduleTemplateReferenceView, + templateRef, +} from "../../utils/templateRef"; const { TextArea } = Input; @@ -52,18 +54,26 @@ const layout = { wrapperCol: { span: 16 }, }; +interface module { + name: string; + values: any; + template: templateRef; +} + const EditModule = () => { - const [module, setModule] = useState({ + const [module, setModule] = useState({ name: "", values: {}, template: { repo: "", path: "", version: "", + resolvedVersion: "", }, }); const [form] = Form.useForm(); + const [editTemplateForm] = Form.useForm(); const [allConfigs, setAllConfigs] = useState([]); const [values, setValues] = useState({}); @@ -75,6 +85,15 @@ const EditModule = () => { required: [], }, }); + + const [templateRef, setTemplateRef] = useState({ + repo: "", + path: "", + version: "", + resolvedVersion: "", + }); + const [templateRefLock, setTemplateRefLock] = useState(true); + const [error, setError] = useState({ message: "", description: "", @@ -123,7 +142,7 @@ const EditModule = () => { break; case "object": objectArr.push( - mapsToArray(field.items.properties, valueFromList) + mapsToArray(field.items.properties, valueFromList), ); break; } @@ -165,6 +184,19 @@ const EditModule = () => { .then((res) => { setLoadValues(true); + editTemplateForm.setFieldsValue({ + repo: res.data.template.repo, + path: res.data.template.path, + version: res.data.template.version, + }); + + setTemplateRef({ + repo: res.data.template.repo, + path: res.data.template.path, + version: res.data.template.version, + resolvedVersion: res.data.template.resolvedVersion, + }); + axios .get( `/api/templates?repo=` + @@ -172,7 +204,7 @@ const EditModule = () => { `&path=` + res.data.template.path + `&commit=` + - res.data.template.version + res.data.template.resolvedVersion, ) .then((templatesRes) => { setConfig(templatesRes.data); @@ -180,7 +212,7 @@ const EditModule = () => { let values = mapsToArray( templatesRes.data.root.properties, - res.data.values + res.data.values, ); setModule({ @@ -300,6 +332,48 @@ const EditModule = () => { return out; }; + const handleSubmitTemplateEdit = (values: any) => { + setLoadTemplate(false); + axios + .get( + `/api/templates?repo=` + + values.repo + + `&path=` + + values.path + + `&commit=` + + values.version, + ) + .then((res) => { + setConfig(res.data); + setLoadTemplate(true); + setTemplateRef({ + repo: values.repo, + path: values.path, + version: values.version, + resolvedVersion: res.data.resolvedVersion, + }); + }) + .catch((error) => { + setLoadTemplate(true); + if (error?.response?.data) { + setError({ + message: error.response.data.message || String(error), + description: + error.response.data.description || + "Check if Cyclops backend is available on: " + + window.__RUNTIME_CONFIG__.REACT_APP_CYCLOPS_CTRL_HOST, + }); + } else { + setError({ + message: String(error), + description: + "Check if Cyclops backend is available on: " + + window.__RUNTIME_CONFIG__.REACT_APP_CYCLOPS_CTRL_HOST, + }); + } + }); + }; + const handleSubmit = (values: any) => { values = findMaps(config.root.properties, values); @@ -307,7 +381,7 @@ const EditModule = () => { .post(`/api/modules/update`, { values: values, name: module.name, - template: module.template, + template: templateRef, }) .then((res) => { window.location.href = "/modules/" + moduleName; @@ -346,7 +420,7 @@ const EditModule = () => { field: any, formItemName: string | string[], arrayField: any, - isRequired: boolean + isRequired: boolean, ) => { let options: { value: string; label: string }[] = []; field.enum.forEach((option: any) => { @@ -387,7 +461,7 @@ const EditModule = () => { field: any, formItemName: string | string[], arrayField: any, - isRequired: boolean + isRequired: boolean, ) => { return ( { parent: string, level: number, arrayField: any, - remove: Function + remove: Function, ) => { switch (field.items.type) { case "object": @@ -446,7 +520,7 @@ const EditModule = () => { level + 1, 2, arrayField, - field.items.required + field.items.required, )} { level: number, arrayIndexLifetime: number, arrayField?: any, - required?: string[] + required?: string[], ) { const formFields: {} | any = []; fields.forEach((field: any) => { @@ -532,14 +606,14 @@ const EditModule = () => { case "string": if (field.enum) { formFields.push( - selectInputField(field, formItemName, arrayField, isRequired) + selectInputField(field, formItemName, arrayField, isRequired), ); return; } if (field.fileExtension && field.fileExtension.length > 0) { formFields.push( - fileField(field, formItemName, arrayField, isRequired) + fileField(field, formItemName, arrayField, isRequired), ); return; } @@ -563,7 +637,7 @@ const EditModule = () => { rules={stringValidationRules} > - + , ); return; case "number": @@ -587,7 +661,7 @@ const EditModule = () => { rules={numberValidationRules} > - + , ); return; case "boolean": @@ -623,7 +697,7 @@ const EditModule = () => { valuePropName={checked} > - + , ); return; case "object": @@ -697,14 +771,14 @@ const EditModule = () => { level + 1, arrayIndexLifetime, arrayIndexLifetime > 0 ? arrayField : undefined, - field.required + field.required, )} )} - + , ); return; case "array": @@ -779,7 +853,7 @@ const EditModule = () => { "", level + 1, arrField, - remove + remove, )} @@ -800,7 +874,7 @@ const EditModule = () => { - + , ); return; case "map": @@ -858,7 +932,7 @@ const EditModule = () => { )} - + , ); } }); @@ -872,12 +946,63 @@ const EditModule = () => { ); } + + return ( +
+ {mapFields( + config.root.properties, + "", + "", + 0, + 0, + undefined, + config.root.required, + )} +
+ {" "} + +
+
+ ); }; const onFinishFailed = () => { message.error("Submit failed!"); }; + const lockButton = () => { + if (templateRefLock) { + return ( + + + + @@ -916,26 +1110,6 @@ const EditModule = () => { Edit Module
{formLoading()} - {mapFields( - config.root.properties, - "", - "", - 0, - 0, - undefined, - config.root.required - )} -
- {" "} - -
diff --git a/cyclops-ui/src/components/pages/ModuleDetails.tsx b/cyclops-ui/src/components/pages/ModuleDetails.tsx index 507a56ee..7ce59b20 100644 --- a/cyclops-ui/src/components/pages/ModuleDetails.tsx +++ b/cyclops-ui/src/components/pages/ModuleDetails.tsx @@ -31,6 +31,10 @@ import StatefulSet from "../k8s-resources/StatefulSet"; import Pod from "../k8s-resources/Pod"; import Service from "../k8s-resources/Service"; import ConfigMap from "../k8s-resources/ConfigMap"; +import { + moduleTemplateReferenceView, + templateRef, +} from "../../utils/templateRef"; const languages = [ "javascript", "java", @@ -74,12 +78,7 @@ const { Title } = Typography; interface module { name: string; namespace: string; - template: { - repo: string; - path: string; - version: string; - resolvedVersion: string; - }; + template: templateRef; } interface resourceRef { @@ -541,65 +540,6 @@ const ModuleDetails = () => { } }; - const githubTemplateReferenceView = () => { - let refView = module.template.repo; - let commitLink = - module.template.repo + - `/tree/` + - module.template.resolvedVersion + - `/` + - module.template.path; - - if (module.template.path && module.template.path !== "") { - refView += "/" + module.template.path; - } - - if (module.template.version && module.template.version !== "") { - refView += " @ " + module.template.version; - } - - refView += " - " + module.template.resolvedVersion.substring(0, 7); - - return ( - - - - {" " + refView} - - - ); - }; - - const defaultTemplateReferenceView = () => { - let refView = module.template.repo; - - if (module.template.path && module.template.path !== "") { - refView += "/" + module.template.path; - } - - if (module.template.version && module.template.version !== "") { - refView += " @ " + module.template.version; - } - - refView += " - " + module.template.resolvedVersion.substring(0, 7); - - return ( - - - {refView} - - - ); - }; - - const moduleTemplateReferenceView = () => { - if (module.template.repo.startsWith("https://github.com")) { - return githubTemplateReferenceView(); - } - - return defaultTemplateReferenceView(); - }; - const moduleLoading = () => { if (loadModule) { return ( @@ -617,7 +557,7 @@ const ModuleDetails = () => { - {moduleTemplateReferenceView()} + {moduleTemplateReferenceView(module.template)} ); diff --git a/cyclops-ui/src/utils/templateRef.tsx b/cyclops-ui/src/utils/templateRef.tsx new file mode 100644 index 00000000..1f7fd8e6 --- /dev/null +++ b/cyclops-ui/src/utils/templateRef.tsx @@ -0,0 +1,70 @@ +import { Row } from "antd"; +import Link from "antd/lib/typography/Link"; +import { LinkOutlined } from "@ant-design/icons"; +import React from "react"; + +export interface templateRef { + repo: string; + path: string; + version: string; + resolvedVersion: string; +} + +export function githubTemplateReferenceView(templateRef: templateRef) { + let refView = templateRef.repo; + let commitLink = + templateRef.repo + + `/tree/` + + templateRef.resolvedVersion + + `/` + + templateRef.path; + + if (templateRef.path && templateRef.path !== "") { + refView += "/" + templateRef.path; + } + + if (templateRef.version && templateRef.version !== "") { + refView += " @ " + templateRef.version; + } + + refView += " - " + templateRef.resolvedVersion.substring(0, 7); + + return ( + + + + {" " + refView} + + + ); +} + +export function defaultTemplateReferenceView(templateRef: templateRef) { + let refView = templateRef.repo; + + if (templateRef.path && templateRef.path !== "") { + refView += "/" + templateRef.path; + } + + if (templateRef.version && templateRef.version !== "") { + refView += " @ " + templateRef.version; + } + + refView += " - " + templateRef.resolvedVersion.substring(0, 7); + + return ( + + + {refView} + + + ); +} + +export function moduleTemplateReferenceView(templateRef: templateRef) { + if (templateRef.repo.startsWith("https://github.com")) { + return githubTemplateReferenceView(templateRef); + } + + return defaultTemplateReferenceView(templateRef); +}