From a9ee66a6a6ae925bb25b4267d1135bbcc1b59ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20D=C3=B6ll?= Date: Wed, 22 May 2024 12:23:27 +0000 Subject: [PATCH] wip: add new form --- cmd/web/cmd/root.go | 1 + go.mod | 2 +- go.sum | 12 +- internal/api/models/operator.go | 5 + internal/web/adapters/handlers/handlers.go | 7 +- .../components/operators/operators_table.go | 131 +++++++++++++++ .../operators/list_operators_controller.go | 16 +- .../operators/new_operator_controller.go | 151 ++++++++++++++++++ internal/web/ports/handlers.go | 2 + 9 files changed, 309 insertions(+), 18 deletions(-) create mode 100644 internal/web/components/operators/operators_table.go create mode 100644 internal/web/controllers/operators/new_operator_controller.go diff --git a/cmd/web/cmd/root.go b/cmd/web/cmd/root.go index d7f20d06..fb1ff180 100644 --- a/cmd/web/cmd/root.go +++ b/cmd/web/cmd/root.go @@ -115,6 +115,7 @@ func (s *WebSrv) Start(ctx context.Context, ready server.ReadyFunc, run server.R // Operators handler app.Get("/operators", handlers.ListOperators()) + app.Get("/operators/new", handlers.NewOperator()) err = app.Listen(s.cfg.Flags.Addr) if err != nil { diff --git a/go.mod b/go.mod index 8967df3c..47d6ebba 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/xdg-go/scram v1.0.2 github.com/zeiss/fiber-authz v1.0.24 github.com/zeiss/fiber-goth v1.2.1 + github.com/zeiss/fiber-htmx v1.2.8-0.20240522115326-7199b75ca39e github.com/zeiss/snow-go v0.0.0-20240312201415-88f059622cff go.opencensus.io v0.24.0 go.uber.org/zap v1.27.0 @@ -312,7 +313,6 @@ require ( github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zeiss/fiber-htmx v1.2.8-0.20240522090130-3a5a33b84c41 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect go-simpler.org/musttag v0.12.2 // indirect go-simpler.org/sloglint v0.6.0 // indirect diff --git a/go.sum b/go.sum index fc287e23..bf980beb 100644 --- a/go.sum +++ b/go.sum @@ -737,8 +737,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1018,8 +1016,6 @@ github.com/rickb777/date v1.13.0/go.mod h1:GZf3LoGnxPWjX+/1TXOuzHefZFDovTyNLHDMd github.com/rickb777/plural v1.2.1 h1:UitRAgR70+yHFt26Tmj/F9dU9aV6UfjGXSbO1DcC9/U= github.com/rickb777/plural v1.2.1/go.mod h1:j058+3M5QQFgcZZ2oKIOekcygoZUL8gKW5yRO14BuAw= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= @@ -1227,12 +1223,10 @@ github.com/zeiss/fiber-authz v1.0.24 h1:rNaBl56GGsn5CJmcsCCTEvC+tqRD57utGvl7tagO github.com/zeiss/fiber-authz v1.0.24/go.mod h1:q3yxf4CcCkIrXPaBc+n+TW7XsZLpNi7YhF28r55pYCY= github.com/zeiss/fiber-goth v1.2.1 h1:mXjQx5ekV6jfe3Gi0apyTGh2IoQ8zRw2oY1o8iy+CmQ= github.com/zeiss/fiber-goth v1.2.1/go.mod h1:AVhqrCUdrqRdtu+N0mkq/JI2rZd01Ss46LKbdXZ3bsA= -github.com/zeiss/fiber-htmx v1.2.6 h1:z23WMufCkDsaIhBZ0eONI4nxO/U85gXVWZAx1bmkQb0= -github.com/zeiss/fiber-htmx v1.2.6/go.mod h1:sgKAl4W80gA7spNSy/fdocbC+C7K7zeoaVz/ZcCBuxw= -github.com/zeiss/fiber-htmx v1.2.7 h1:DdC1zDwCpmY1gqGgz54RuLmk/WRBNjryUBCkokUAaHw= -github.com/zeiss/fiber-htmx v1.2.7/go.mod h1:nqmi5gmVPlH6AFHpIiC+QxaTSP8Bl3AuobRM9IXLE48= github.com/zeiss/fiber-htmx v1.2.8-0.20240522090130-3a5a33b84c41 h1:z/oRe+OnEr1+kXXqwBQhZ5oHCigEbzDEGK4KvY/D4TQ= github.com/zeiss/fiber-htmx v1.2.8-0.20240522090130-3a5a33b84c41/go.mod h1:aZjZpybS/yfTU53EHmmPPlpHIhj+9ETLWMl1z9VqUhc= +github.com/zeiss/fiber-htmx v1.2.8-0.20240522115326-7199b75ca39e h1:fX51DUIikOoLzqVy5FIEFQjGjpiiz+T9p/+EfzlsNdM= +github.com/zeiss/fiber-htmx v1.2.8-0.20240522115326-7199b75ca39e/go.mod h1:aZjZpybS/yfTU53EHmmPPlpHIhj+9ETLWMl1z9VqUhc= github.com/zeiss/snow-go v0.0.0-20240312201415-88f059622cff h1:IguG+jnCnFyAzZ8Fp+6v2lJNvUFPfu8Q2UUgSFw4doU= github.com/zeiss/snow-go v0.0.0-20240312201415-88f059622cff/go.mod h1:HvitS/QkqgqhV/bNWxPKn0NjByjTaEACZnNgHKZEuio= gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= @@ -1329,8 +1323,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= diff --git a/internal/api/models/operator.go b/internal/api/models/operator.go index acc91062..06a0f410 100644 --- a/internal/api/models/operator.go +++ b/internal/api/models/operator.go @@ -40,6 +40,11 @@ type Operator struct { DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` } +// Compare ... +func (o Operator) Compare() int { + return 0 +} + // Claims returns the operator claims. func (o Operator) Claims() (*jwt.OperatorClaims, error) { claims, err := jwt.DecodeOperatorClaims(o.Token.Token) diff --git a/internal/web/adapters/handlers/handlers.go b/internal/web/adapters/handlers/handlers.go index f5ff9c7a..51c53eba 100644 --- a/internal/web/adapters/handlers/handlers.go +++ b/internal/web/adapters/handlers/handlers.go @@ -39,5 +39,10 @@ func (h *handlers) Me() fiber.Handler { // ListOperators ... func (h *handlers) ListOperators() fiber.Handler { - return htmx.NewHxControllerHandler(operators.NewListOperatorsController(h.db)) + return htmx.NewHxControllerHandler(operators.NewListOperatorsController(h.db), htmx.Config{Resolvers: []htmx.ResolveFunc{resolvers.ListOperators(h.db)}}) +} + +// NewOperator ... +func (h *handlers) NewOperator() fiber.Handler { + return htmx.NewHxControllerHandler(operators.NewOperatorController(h.db)) } diff --git a/internal/web/components/operators/operators_table.go b/internal/web/components/operators/operators_table.go new file mode 100644 index 00000000..77b245e5 --- /dev/null +++ b/internal/web/components/operators/operators_table.go @@ -0,0 +1,131 @@ +package operators + +import ( + htmx "github.com/zeiss/fiber-htmx" + "github.com/zeiss/fiber-htmx/components/buttons" + "github.com/zeiss/fiber-htmx/components/forms" + "github.com/zeiss/fiber-htmx/components/tables" + "github.com/zeiss/typhoon/internal/api/models" +) + +// OperatorsTableProps ... +type OperatorsTableProps struct { + Operators []*models.Operator + Offset int + Limit int + Total int +} + +// OperatorsTable ... +func OperatorsTable(props OperatorsTableProps, children ...htmx.Node) htmx.Node { + return htmx.Div( + htmx.ClassNames{ + "bg-base-100": true, + "m-4": true, + }, + + tables.Table( + tables.TableProps[*models.Operator]{ + ID: "operators-tables", + Columns: []tables.ColumnDef[*models.Operator]{ + { + ID: "id", + AccessorKey: "id", + Header: func(p tables.TableProps[*models.Operator]) htmx.Node { + return htmx.Th(htmx.Text("ID")) + }, + Cell: func(p tables.TableProps[*models.Operator], row *models.Operator) htmx.Node { + return htmx.Td( + htmx.Text(row.ID.String()), + ) + }, + }, + { + ID: "name", + AccessorKey: "name", + Header: func(p tables.TableProps[*models.Operator]) htmx.Node { + return htmx.Th(htmx.Text("Name")) + }, + Cell: func(p tables.TableProps[*models.Operator], row *models.Operator) htmx.Node { + return htmx.Td( + // links.Link( + // links.LinkProps{ + // Href: fmt.Sprintf("/%s/profiles/%s", props.Team.Slug, row.ID.String()), + // }, + // htmx.Text(row.Name), + // ), + ) + }, + }, + { + Header: func(p tables.TableProps[*models.Operator]) htmx.Node { + return nil + }, + Cell: func(p tables.TableProps[*models.Operator], row *models.Operator) htmx.Node { + return htmx.Td( + buttons.Button( + buttons.ButtonProps{ + ClassNames: htmx.ClassNames{ + "btn-square": true, + }, + }, + + // htmx.HxDelete(fmt.Sprintf("/%s/profiles/%s", props.Team.Slug, row.ID.String())), + // htmx.HxTarget("closest "), + // htmx.HxConfirm("Are you sure you want to delete this profile?"), + // icons.TrashOutline( + // icons.IconProps{}, + // ), + ), + ) + }, + }, + }, + Rows: tables.NewRows(props.Operators), + Toolbar: tables.TableToolbar( + tables.TableToolbarProps[*models.Operator]{ + ClassName: htmx.ClassNames{ + "flex": true, + "items-center": true, + "justify-between": true, + "px-5": true, + "pt-5": true, + }, + }, + htmx.Div( + htmx.ClassNames{ + "inline-flex": true, + "items-center": true, + "gap-3": true, + }, + forms.TextInputBordered( + forms.TextInputProps{ + Placeholder: "Search ...", + }, + ), + ), + htmx.A( + htmx.Href("/operators/new"), + buttons.Outline( + buttons.ButtonProps{ + ClassNames: htmx.ClassNames{ + "btn-sm": true, + }, + }, + htmx.Text("Create Operator"), + ), + ), + ), + // Pagination: ProfileListTablePaginationComponent( + // ProfileListTablePaginationProps{ + // Limit: props.Limit, + // Offset: props.Offset, + // Total: props.Total, + // Target: "profiles-tables", + // Team: props.Team, + // }, + // ), + }, + ), + ) +} diff --git a/internal/web/controllers/operators/list_operators_controller.go b/internal/web/controllers/operators/list_operators_controller.go index 2348ff1a..4a70d03c 100644 --- a/internal/web/controllers/operators/list_operators_controller.go +++ b/internal/web/controllers/operators/list_operators_controller.go @@ -1,11 +1,10 @@ package operators import ( - "fmt" - htmx "github.com/zeiss/fiber-htmx" "github.com/zeiss/typhoon/internal/api/models" "github.com/zeiss/typhoon/internal/web/components" + "github.com/zeiss/typhoon/internal/web/components/operators" "github.com/zeiss/typhoon/internal/web/ports" "github.com/zeiss/typhoon/pkg/resolvers" ) @@ -24,9 +23,7 @@ func NewListOperatorsController(db ports.Operators) *ListOperatorsController { // Prepare ... func (l *ListOperatorsController) Get() error { - ops := htmx.Values[models.Pagination[models.Operator]](l.Ctx().UserContext(), resolvers.ValuesKeyOperators) - - fmt.Println(ops) + ops := htmx.Values[models.Pagination[*models.Operator]](l.Ctx().UserContext(), resolvers.ValuesKeyOperators) return htmx.RenderComp( l.Ctx(), @@ -34,7 +31,14 @@ func (l *ListOperatorsController) Get() error { components.PageProps{}, components.Layout( components.LayoutProps{}, - htmx.Text("Operators"), + operators.OperatorsTable( + operators.OperatorsTableProps{ + Operators: ops.Rows, + Offset: ops.Offset, + Limit: ops.Limit, + Total: ops.TotalRows, + }, + ), ), ), ) diff --git a/internal/web/controllers/operators/new_operator_controller.go b/internal/web/controllers/operators/new_operator_controller.go new file mode 100644 index 00000000..d7995678 --- /dev/null +++ b/internal/web/controllers/operators/new_operator_controller.go @@ -0,0 +1,151 @@ +package operators + +import ( + htmx "github.com/zeiss/fiber-htmx" + "github.com/zeiss/fiber-htmx/components/buttons" + "github.com/zeiss/fiber-htmx/components/cards" + "github.com/zeiss/fiber-htmx/components/forms" + "github.com/zeiss/typhoon/internal/web/components" + "github.com/zeiss/typhoon/internal/web/ports" +) + +// NewOperatorControllerImpl ... +type NewOperatorControllerImpl struct { + htmx.DefaultController +} + +// NewOperatorsController ... +func NewOperatorController(db ports.Operators) *NewOperatorControllerImpl { + return &NewOperatorControllerImpl{} +} + +// Prepare ... +func (l *NewOperatorControllerImpl) Get() error { + return htmx.RenderComp( + l.Ctx(), + components.Page( + components.PageProps{}, + components.Layout( + components.LayoutProps{}, + htmx.FormElement( + htmx.HxPost(""), + cards.CardBordered( + cards.CardProps{}, + cards.Body( + cards.BodyProps{}, + cards.Title( + cards.TitleProps{}, + htmx.Text("Properties"), + ), + forms.FormControl( + forms.FormControlProps{ + ClassNames: htmx.ClassNames{ + "py-4": true, + }, + }, + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "-my-4": true, + }, + }, + htmx.Text("Name"), + ), + ), + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "text-neutral-500": true, + }, + }, + htmx.Text("A unique identifier for operator."), + ), + ), + forms.TextInputBordered( + forms.TextInputProps{ + Name: "name", + }, + ), + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "text-neutral-500": true, + }, + }, + htmx.Text("The name must be from 3 to 100 characters. At least 3 characters must be non-whitespace."), + ), + ), + forms.FormControl( + forms.FormControlProps{ + ClassNames: htmx.ClassNames{ + "py-4": true, + }, + }, + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "-my-4": true, + }, + }, + htmx.Text("Description"), + ), + ), + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "text-neutral-500": true, + }, + }, + htmx.Text("A brief description of the operator to provide context."), + ), + ), + forms.TextareaBordered( + forms.TextareaProps{ + Name: "description", + }, + ), + forms.FormControlLabel( + forms.FormControlLabelProps{}, + forms.FormControlLabelText( + forms.FormControlLabelTextProps{ + ClassNames: htmx.ClassNames{ + "text-neutral-500": true, + }, + }, + htmx.Text("The description must be from 3 to 1024 characters."), + ), + ), + ), + ), + ), + ), + cards.CardBordered( + cards.CardProps{}, + cards.Body( + cards.BodyProps{}, + cards.Title( + cards.TitleProps{}, + htmx.Text("Tags - Optional"), + ), + ), + ), + buttons.OutlinePrimary( + buttons.ButtonProps{}, + htmx.Attribute("type", "submit"), + htmx.Text("Create Operator"), + ), + ), + ), + ), + ) +} diff --git a/internal/web/ports/handlers.go b/internal/web/ports/handlers.go index 9a697ec9..4d2923dc 100644 --- a/internal/web/ports/handlers.go +++ b/internal/web/ports/handlers.go @@ -12,4 +12,6 @@ type Handlers interface { Me() fiber.Handler // ListOperators ... ListOperators() fiber.Handler + // NewOperator ... + NewOperator() fiber.Handler }