From 1c281db46071a9816893c7cf3aaade1296731daa Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 13 Feb 2023 14:18:20 +0545 Subject: [PATCH 1/4] feat: Custom renderer --- api/renderers.go | 27 ++++++++++ cmd/server.go | 3 ++ go.mod | 6 ++- go.sum | 16 ++++++ topology/controllers.go | 111 ++++++++++++++++++++++++++++++++++++++++ topology/query.go | 34 ++++++++++++ 6 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 api/renderers.go create mode 100644 topology/controllers.go create mode 100644 topology/query.go diff --git a/api/renderers.go b/api/renderers.go new file mode 100644 index 000000000..132657c8f --- /dev/null +++ b/api/renderers.go @@ -0,0 +1,27 @@ +package api + +import "fmt" + +type Renderers struct { + Components []RenderComponent `json:"components,omitempty"` + Properties []RenderComponent `json:"properties,omitempty"` +} + +type RenderComponent struct { + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + JSX string `json:"jsx,omitempty"` +} + +func (c *RenderComponent) Key(isProp bool) string { + prefix := "component" + if isProp { + prefix = "property" + } + + if c.Type != "" { + return fmt.Sprintf("%s_%s_%s", prefix, c.Type, c.Name) + } + + return fmt.Sprintf("%s_%s", prefix, c.Name) +} diff --git a/cmd/server.go b/cmd/server.go index 2fc20e91e..2ecaabb06 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -18,6 +18,7 @@ import ( "github.com/flanksource/incident-commander/events" "github.com/flanksource/incident-commander/jobs" "github.com/flanksource/incident-commander/snapshot" + "github.com/flanksource/incident-commander/topology" "github.com/flanksource/incident-commander/utils" ) @@ -69,6 +70,8 @@ var Serve = &cobra.Command{ e.GET("/snapshot/incident/:id", snapshot.Incident) e.GET("/snapshot/config/:id", snapshot.Config) + e.GET("/custom_renderer", topology.GetCustomRenderer) + // Serve openapi schemas schemaServer, err := utils.HTTPFileserver(openapi.Schemas) if err != nil { diff --git a/go.mod b/go.mod index c39da1a40..c690831c1 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.17.7 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/cloudflare/circl v1.3.1 // indirect + github.com/dlclark/regexp2 v1.8.0 // indirect + github.com/dop251/goja v0.0.0-20230203172422-5460598cfa32 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/flanksource/gomplate/v3 v3.20.1 // indirect github.com/go-errors/errors v1.0.1 // indirect @@ -65,6 +67,7 @@ require ( github.com/go-git/go-git/v5 v5.5.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/inflect v0.19.0 // indirect + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -74,6 +77,7 @@ require ( github.com/hashicorp/hcl/v2 v2.16.0 // indirect github.com/jackc/pgx/v5 v5.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/jvatic/goja-babel v0.0.0-20230204121733-ac82a55cfa50 // indirect github.com/klauspost/compress v1.15.13 // indirect github.com/liamylian/jsontime/v2 v2.0.0 // indirect github.com/lib/pq v1.10.7 // indirect @@ -225,7 +229,7 @@ require ( golang.org/x/oauth2 v0.3.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.105.0 // indirect diff --git a/go.sum b/go.sum index d0507f2d2..8ccc6d435 100644 --- a/go.sum +++ b/go.sum @@ -535,6 +535,10 @@ github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8 github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm0xbEVw2LCs= github.com/digitalocean/godo v1.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.8.0 h1:rJD5HeGIT/2b5CDk63FVCwZA3qgYElfg+oQK7uH5pfE= +github.com/dlclark/regexp2 v1.8.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -556,6 +560,11 @@ github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230203172422-5460598cfa32 h1:audXtK7nV3y4W9ckAxRBE+eQV5Bljf5Non4NTa9kLVE= +github.com/dop251/goja v0.0.0-20230203172422-5460598cfa32/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -717,6 +726,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -1132,6 +1143,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jvatic/goja-babel v0.0.0-20230204121733-ac82a55cfa50 h1:ewpo/HSvn4zCct4LvULM3Oc1PB9gDUR2f5RzgONOVIY= +github.com/jvatic/goja-babel v0.0.0-20230204121733-ac82a55cfa50/go.mod h1:e6baxuoF3V4g/q0HMjzOtziMK//6Ui0RjfwbFgPQWB4= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= @@ -1603,6 +1616,7 @@ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stvp/assert v0.0.0-20170616060220-4bc16443988b/go.mod h1:CC7OXV9IjEZRA+znA6/Kz5vbSwh69QioernOHeDCatU= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -2191,6 +2205,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/topology/controllers.go b/topology/controllers.go new file mode 100644 index 000000000..1a2826527 --- /dev/null +++ b/topology/controllers.go @@ -0,0 +1,111 @@ +package topology + +import ( + "bytes" + "fmt" + "io" + "net/http" + "text/template" + + "github.com/flanksource/commons/logger" + "github.com/flanksource/incident-commander/api" + babel "github.com/jvatic/goja-babel" + "github.com/labstack/echo/v4" +) + +var jsComponentTpl *template.Template + +func init() { + tpl, err := template.New("registry").Parse(jsComponentRegistryTpl) + if err != nil { + logger.Fatalf("error parsing template 'jsComponentRegistryTpl'. %v", err) + } + + jsComponentTpl = tpl +} + +type component struct { + Name string + JS string +} + +// GetCustomRenderer returns an application/javascript HTTP response +// with custom components and a registry. +// This registry needs to be used to select custom components +// for rendering of properties and cards. +func GetCustomRenderer(ctx echo.Context) error { + // 1. Read the template of the topology + sysTplID := ctx.QueryParams().Get("id") + results, err := QueryRenderComponents(ctx.Request().Context(), sysTplID) + if err != nil { + return errorResonse(ctx, err, http.StatusBadRequest) + } + + // 2. Create a registry of all the components + var components = make(map[string]component) + for _, r := range results { + if err := compileComponents(components, r.Components, false); err != nil { + return errorResonse(ctx, err, http.StatusInternalServerError) + } + + if err := compileComponents(components, r.Properties, true); err != nil { + return errorResonse(ctx, err, http.StatusInternalServerError) + } + } + + registryResp, err := renderComponents(components) + if err != nil { + return errorResonse(ctx, err, http.StatusInternalServerError) + } + + return ctx.Stream(http.StatusOK, "application/javascript", registryResp) +} + +func compileComponents(output map[string]component, components []api.RenderComponent, isProp bool) error { + if err := babel.Init(len(components)); err != nil { + return fmt.Errorf("failed to init babel; %w", err) + } + + for _, c := range components { + res, err := babel.TransformString(c.JSX, map[string]interface{}{ + "plugins": []string{ + "transform-react-jsx", + "transform-block-scoping", + }, + }) + if err != nil { + return fmt.Errorf("error transforming jsx; %w", err) + } + + output[c.Key(isProp)] = component{ + Name: c.Name, + JS: res, + } + } + + return nil +} + +func renderComponents(components map[string]component) (io.Reader, error) { + var buf bytes.Buffer + if err := jsComponentTpl.Execute(&buf, components); err != nil { + return nil, fmt.Errorf("error generating components; %w", err) + } + + return &buf, nil +} + +const jsComponentRegistryTpl = ` +{{range $k, $v := .}} +const {{$k}} = {{$v.JS}} +{{end}} +const componentRegistry = { + {{range $k, $v := .}}"{{$k}}": {{$k}}, + {{end}} +}; +` + +func errorResonse(c echo.Context, err error, code int) error { + e := map[string]string{"error": err.Error()} + return c.JSON(code, e) +} diff --git a/topology/query.go b/topology/query.go new file mode 100644 index 000000000..29e1fd27d --- /dev/null +++ b/topology/query.go @@ -0,0 +1,34 @@ +package topology + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/flanksource/incident-commander/api" + "github.com/flanksource/incident-commander/db" +) + +func QueryRenderComponents(ctx context.Context, systemTemplateID string) ([]api.Renderers, error) { + rows, err := db.Gorm.WithContext(ctx).Table("templates").Select("spec->'renderers'").Where("id = ?", systemTemplateID).Rows() + if err != nil { + return nil, fmt.Errorf("failed to query renderers(); %w", err) + } + defer rows.Close() + + var results []api.Renderers + for rows.Next() { + var renderer api.Renderers + var s string + if err := rows.Scan(&s); err != nil { + return nil, fmt.Errorf("rows.Scan(); %w", err) + } + + if err := json.Unmarshal([]byte(s), &renderer); err != nil { + return nil, fmt.Errorf("json.Unmarshal(); %w", err) + } + results = append(results, renderer) + } + + return results, nil +} From 946c07874f4faf459ef08d10975dde653a789ead Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 16 Feb 2023 16:55:04 +0545 Subject: [PATCH 2/4] fix: PR reviews --- topology/controllers.go | 30 +++++++++++++++--------------- topology/query.go | 12 ++++++------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/topology/controllers.go b/topology/controllers.go index 1a2826527..e2af208eb 100644 --- a/topology/controllers.go +++ b/topology/controllers.go @@ -34,28 +34,26 @@ type component struct { // This registry needs to be used to select custom components // for rendering of properties and cards. func GetCustomRenderer(ctx echo.Context) error { - // 1. Read the template of the topology - sysTplID := ctx.QueryParams().Get("id") - results, err := QueryRenderComponents(ctx.Request().Context(), sysTplID) + id := ctx.QueryParams().Get("id") + results, err := QueryRenderComponents(ctx.Request().Context(), id) if err != nil { - return errorResonse(ctx, err, http.StatusBadRequest) + return errorResponse(ctx, http.StatusBadRequest, err, "failed to query components by id") } - // 2. Create a registry of all the components var components = make(map[string]component) for _, r := range results { if err := compileComponents(components, r.Components, false); err != nil { - return errorResonse(ctx, err, http.StatusInternalServerError) + return errorResponse(ctx, http.StatusInternalServerError, err, "failed to compile components") } if err := compileComponents(components, r.Properties, true); err != nil { - return errorResonse(ctx, err, http.StatusInternalServerError) + return errorResponse(ctx, http.StatusInternalServerError, err, "failed to compile property components") } } registryResp, err := renderComponents(components) if err != nil { - return errorResonse(ctx, err, http.StatusInternalServerError) + return errorResponse(ctx, http.StatusInternalServerError, err, "failed to render components") } return ctx.Stream(http.StatusOK, "application/javascript", registryResp) @@ -63,18 +61,18 @@ func GetCustomRenderer(ctx echo.Context) error { func compileComponents(output map[string]component, components []api.RenderComponent, isProp bool) error { if err := babel.Init(len(components)); err != nil { - return fmt.Errorf("failed to init babel; %w", err) + return fmt.Errorf("failed to init babel: %w", err) } for _, c := range components { - res, err := babel.TransformString(c.JSX, map[string]interface{}{ + res, err := babel.TransformString(c.JSX, map[string]any{ "plugins": []string{ "transform-react-jsx", "transform-block-scoping", }, }) if err != nil { - return fmt.Errorf("error transforming jsx; %w", err) + return fmt.Errorf("error transforming jsx: %w", err) } output[c.Key(isProp)] = component{ @@ -89,7 +87,7 @@ func compileComponents(output map[string]component, components []api.RenderCompo func renderComponents(components map[string]component) (io.Reader, error) { var buf bytes.Buffer if err := jsComponentTpl.Execute(&buf, components); err != nil { - return nil, fmt.Errorf("error generating components; %w", err) + return nil, fmt.Errorf("error generating components: %w", err) } return &buf, nil @@ -105,7 +103,9 @@ const componentRegistry = { }; ` -func errorResonse(c echo.Context, err error, code int) error { - e := map[string]string{"error": err.Error()} - return c.JSON(code, e) +func errorResponse(c echo.Context, code int, err error, msg string) error { + return c.JSON(code, api.HTTPErrorMessage{ + Error: err.Error(), + Message: msg, + }) } diff --git a/topology/query.go b/topology/query.go index 29e1fd27d..49014b4f3 100644 --- a/topology/query.go +++ b/topology/query.go @@ -12,22 +12,22 @@ import ( func QueryRenderComponents(ctx context.Context, systemTemplateID string) ([]api.Renderers, error) { rows, err := db.Gorm.WithContext(ctx).Table("templates").Select("spec->'renderers'").Where("id = ?", systemTemplateID).Rows() if err != nil { - return nil, fmt.Errorf("failed to query renderers(); %w", err) + return nil, fmt.Errorf("failed to query renderers: %w", err) } defer rows.Close() var results []api.Renderers for rows.Next() { - var renderer api.Renderers + var renderers api.Renderers var s string if err := rows.Scan(&s); err != nil { - return nil, fmt.Errorf("rows.Scan(); %w", err) + return nil, fmt.Errorf("error scanning row: %w", err) } - if err := json.Unmarshal([]byte(s), &renderer); err != nil { - return nil, fmt.Errorf("json.Unmarshal(); %w", err) + if err := json.Unmarshal([]byte(s), &renderers); err != nil { + return nil, fmt.Errorf("error unmarshalling to renderers: %w", err) } - results = append(results, renderer) + results = append(results, renderers) } return results, nil From 4331ff8c9c8e6cfe4abc5f01c698f2ab53ebe87b Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 16 Feb 2023 22:13:45 +0545 Subject: [PATCH 3/4] go mod tidy --- go.mod | 2 +- go.sum | 2 +- topology/controllers.go | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c690831c1..ca9760a08 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/google/cel-go v0.13.0 github.com/google/uuid v1.3.0 github.com/jackc/pgx/v4 v4.17.2 + github.com/jvatic/goja-babel v0.0.0-20230204121733-ac82a55cfa50 github.com/labstack/echo/v4 v4.7.2 github.com/microsoft/kiota-authentication-azure-go v0.5.0 github.com/microsoftgraph/msgraph-sdk-go v0.48.0 @@ -77,7 +78,6 @@ require ( github.com/hashicorp/hcl/v2 v2.16.0 // indirect github.com/jackc/pgx/v5 v5.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/jvatic/goja-babel v0.0.0-20230204121733-ac82a55cfa50 // indirect github.com/klauspost/compress v1.15.13 // indirect github.com/liamylian/jsontime/v2 v2.0.0 // indirect github.com/lib/pq v1.10.7 // indirect diff --git a/go.sum b/go.sum index 8ccc6d435..aca821709 100644 --- a/go.sum +++ b/go.sum @@ -1616,6 +1616,7 @@ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stvp/assert v0.0.0-20170616060220-4bc16443988b h1:GlTM/aMVIwU3luIuSN2SIVRuTqGPt1P97YxAi514ulw= github.com/stvp/assert v0.0.0-20170616060220-4bc16443988b/go.mod h1:CC7OXV9IjEZRA+znA6/Kz5vbSwh69QioernOHeDCatU= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -2203,7 +2204,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= diff --git a/topology/controllers.go b/topology/controllers.go index e2af208eb..5bd4778ff 100644 --- a/topology/controllers.go +++ b/topology/controllers.go @@ -60,6 +60,10 @@ func GetCustomRenderer(ctx echo.Context) error { } func compileComponents(output map[string]component, components []api.RenderComponent, isProp bool) error { + if len(components) == 0 { + return nil + } + if err := babel.Init(len(components)); err != nil { return fmt.Errorf("failed to init babel: %w", err) } From 67c9aad7231bcbe3658c736d5eadb9481a5a50fb Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 16 Feb 2023 22:52:01 +0545 Subject: [PATCH 4/4] Added go-cache to babel transformation. - initialize babel only once --- topology/controllers.go | 47 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/topology/controllers.go b/topology/controllers.go index 5bd4778ff..54b24c1a7 100644 --- a/topology/controllers.go +++ b/topology/controllers.go @@ -6,22 +6,32 @@ import ( "io" "net/http" "text/template" + "time" "github.com/flanksource/commons/logger" "github.com/flanksource/incident-commander/api" babel "github.com/jvatic/goja-babel" "github.com/labstack/echo/v4" + "github.com/patrickmn/go-cache" ) -var jsComponentTpl *template.Template +var ( + jsComponentTpl *template.Template + templateCache *cache.Cache +) func init() { tpl, err := template.New("registry").Parse(jsComponentRegistryTpl) if err != nil { logger.Fatalf("error parsing template 'jsComponentRegistryTpl'. %v", err) } - jsComponentTpl = tpl + + templateCache = cache.New(time.Hour*24, time.Hour*12) + + if err := babel.Init(10); err != nil { + logger.Fatalf("failed to init babel: %v", err) + } } type component struct { @@ -64,17 +74,8 @@ func compileComponents(output map[string]component, components []api.RenderCompo return nil } - if err := babel.Init(len(components)); err != nil { - return fmt.Errorf("failed to init babel: %w", err) - } - for _, c := range components { - res, err := babel.TransformString(c.JSX, map[string]any{ - "plugins": []string{ - "transform-react-jsx", - "transform-block-scoping", - }, - }) + res, err := transformJSX(c.JSX) if err != nil { return fmt.Errorf("error transforming jsx: %w", err) } @@ -88,6 +89,28 @@ func compileComponents(output map[string]component, components []api.RenderCompo return nil } +// transformJSX transforms the provided jsx and also +// caches the result. +func transformJSX(jsx string) (string, error) { + if val, ok := templateCache.Get(jsx); ok { + return val.(string), nil + } + + res, err := babel.TransformString(jsx, map[string]any{ + "plugins": []string{ + "transform-react-jsx", + "transform-block-scoping", + }, + }) + if err != nil { + return "", fmt.Errorf("error transforming jsx: %w", err) + } + + templateCache.Set(jsx, res, cache.DefaultExpiration) + + return res, nil +} + func renderComponents(components map[string]component) (io.Reader, error) { var buf bytes.Buffer if err := jsComponentTpl.Execute(&buf, components); err != nil {