diff --git a/cmd/parka/cmds/examples.go b/cmd/parka/cmds/examples.go index ec334fc..d531c87 100644 --- a/cmd/parka/cmds/examples.go +++ b/cmd/parka/cmds/examples.go @@ -27,7 +27,7 @@ func NewExampleCommand() *ExampleCommand { ShortFlag: "t", Type: parameters.ParameterTypeString, Help: "Test string argument", - Required: true, + Default: "test", }, { Name: "string", @@ -133,8 +133,8 @@ func (e *ExampleCommand) Run( err = gp.AddRow(ctx, types.NewRow( types.MRP("test", "test"), - types.MRP("test2", []int{123, 123, 123, 123}), - types.MRP("test3", map[string]interface{}{ + types.MRP("integer_list", []int{123, 123, 123, 123}), + types.MRP("object_from_file", map[string]interface{}{ "test": "test", "test2": []int{123, 123, 123, 123}, }), diff --git a/cmd/parka/cmds/serve.go b/cmd/parka/cmds/serve.go index a839df2..8e509a3 100644 --- a/cmd/parka/cmds/serve.go +++ b/cmd/parka/cmds/serve.go @@ -22,10 +22,15 @@ var ServeCmd = &cobra.Command{ Short: "Starts the server", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - _, err := cmd.Flags().GetUint16("port") + port, err := cmd.Flags().GetUint16("port") + cobra.CheckErr(err) + host, err := cmd.Flags().GetString("host") cobra.CheckErr(err) - serverOptions := []server.ServerOption{} + serverOptions := []server.ServerOption{ + server.WithPort(port), + server.WithAddress(host), + } defaultLookups := []render.TemplateLookup{} dev, _ := cmd.Flags().GetBool("dev") @@ -64,8 +69,8 @@ var ServeCmd = &cobra.Command{ // NOTE(manuel, 2023-05-26) This could also be done with a simple Command config file struct once // implemented as part of sqleton serve - s.Router.GET("/api/example", s.HandleSimpleQueryCommand(NewExampleCommand())) - s.Router.POST("/api/example", s.HandleSimpleFormCommand(NewExampleCommand())) + s.Router.GET("/api/example", s.HandleJSONQueryHandler(NewExampleCommand())) + s.Router.GET("/sqleton/example", s.HandleDataTables(NewExampleCommand(), "", "example")) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -117,13 +122,14 @@ var LsServerCmd = &cobra.Command{ cobra.CheckErr(err) } - err = gp.RunTableMiddlewares(ctx) + err = gp.Close(ctx) cobra.CheckErr(err) }, } func init() { ServeCmd.Flags().Uint16("port", 8080, "Port to listen on") + ServeCmd.Flags().String("host", "localhost", "Port to listen on") ServeCmd.Flags().String("template-dir", "pkg/web/src/templates", "Directory containing templates") ServeCmd.Flags().Bool("dev", false, "Enable development mode") diff --git a/pkg/glazed/handlers/datatables/datatables.go b/pkg/glazed/handlers/datatables/datatables.go index 0af54c9..3c59fff 100644 --- a/pkg/glazed/handlers/datatables/datatables.go +++ b/pkg/glazed/handlers/datatables/datatables.go @@ -103,15 +103,13 @@ type QueryHandlerOption func(qh *QueryHandler) func NewQueryHandler( cmd cmds.GlazeCommand, - lookup render.TemplateLookup, - templateName string, options ...QueryHandlerOption, ) *QueryHandler { qh := &QueryHandler{ cmd: cmd, dt: &DataTables{}, - lookup: lookup, - templateName: templateName, + lookup: NewDataTablesLookupTemplate(), + templateName: "data-tables.tmpl.html", } for _, option := range options { @@ -127,19 +125,37 @@ func WithDataTables(dt *DataTables) QueryHandlerOption { } } -func WithQueryHandlerContextMiddlewares(middlewares ...glazed.ContextMiddleware) QueryHandlerOption { +func WithContextMiddlewares(middlewares ...glazed.ContextMiddleware) QueryHandlerOption { return func(h *QueryHandler) { h.contextMiddlewares = middlewares } } -// WithQueryHandlerParserOptions sets the parser options for the QueryHandler -func WithQueryHandlerParserOptions(options ...parser.ParserOption) QueryHandlerOption { +// WithParserOptions sets the parser options for the QueryHandler +func WithParserOptions(options ...parser.ParserOption) QueryHandlerOption { return func(h *QueryHandler) { h.parserOptions = options } } +func WithTemplateLookup(lookup render.TemplateLookup) QueryHandlerOption { + return func(h *QueryHandler) { + h.lookup = lookup + } +} + +func WithTemplateName(templateName string) QueryHandlerOption { + return func(h *QueryHandler) { + h.templateName = templateName + } +} + +func WithAdditionalData(data map[string]interface{}) QueryHandlerOption { + return func(h *QueryHandler) { + h.dt.AdditionalData = data + } +} + func (qh *QueryHandler) Handle(c *gin.Context, w io.Writer) error { pc := glazed.NewCommandContext(qh.cmd) diff --git a/pkg/handlers/command-dir/command-dir.go b/pkg/handlers/command-dir/command-dir.go index 9488e1f..d2d4cdd 100644 --- a/pkg/handlers/command-dir/command-dir.go +++ b/pkg/handlers/command-dir/command-dir.go @@ -7,18 +7,13 @@ import ( "github.com/go-go-golems/glazed/pkg/cmds" "github.com/go-go-golems/glazed/pkg/cmds/layers" "github.com/go-go-golems/parka/pkg/glazed/handlers/datatables" - "github.com/go-go-golems/parka/pkg/glazed/handlers/json" "github.com/go-go-golems/parka/pkg/glazed/parser" "github.com/go-go-golems/parka/pkg/handlers/config" "github.com/go-go-golems/parka/pkg/render" - "github.com/go-go-golems/parka/pkg/render/layout" parka "github.com/go-go-golems/parka/pkg/server" "github.com/pkg/errors" - "github.com/rs/zerolog/log" - "net/http" "os" "strings" - "time" ) type HandlerParameters struct { @@ -416,33 +411,20 @@ func (cd *CommandDirHandler) Serve(server *parka.Server, path string) error { server.Router.GET(path+"/data/*path", func(c *gin.Context) { commandPath := c.Param("path") - commandPath = strings.TrimPrefix(commandPath, "/") + commandPath = strings.TrimPrefix(commandPath, path) sqlCommand, ok := getRepositoryCommand(c, cd.Repository, commandPath) if !ok { c.JSON(404, gin.H{"error": "command not found"}) return } - handler := json.NewQueryHandler(sqlCommand, - json.WithQueryHandlerParserOptions(cd.computeParserOptions()...), - ) - handle := func(c *gin.Context) { - err := handler.Handle(c, c.Writer) - if err != nil { - log.Error().Err(err).Msg("failed to handle query") - c.JSON(http.StatusInternalServerError, gin.H{ - "error": err.Error(), - }) - } - } - - handle(c) + server.HandleJSONQueryHandler(sqlCommand) }) server.Router.GET(path+"/sqleton/*path", func(c *gin.Context) { - // Get command path from the route - commandPath := strings.TrimPrefix(c.Param("path"), "/") + commandPath := c.Param("path") + commandPath = strings.TrimPrefix(commandPath, path) // Get repository command sqlCommand, ok := getRepositoryCommand(c, cd.Repository, commandPath) @@ -451,68 +433,14 @@ func (cd *CommandDirHandler) Serve(server *parka.Server, path string) error { return } - name := sqlCommand.Description().Name - dateTime := time.Now().Format("2006-01-02--15-04-05") - links := []layout.Link{ - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.csv", path, commandPath, dateTime, name), - Text: "Download CSV", - Class: "download", - }, - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.json", path, commandPath, dateTime, name), - Text: "Download JSON", - Class: "download", - }, - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.xlsx", path, commandPath, dateTime, name), - Text: "Download Excel", - Class: "download", - }, - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.md", path, commandPath, dateTime, name), - Text: "Download Markdown", - Class: "download", - }, - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.html", path, commandPath, dateTime, name), - Text: "Download HTML", - Class: "download", - }, - { - Href: fmt.Sprintf("%s/download/%s/%s-%s.txt", path, commandPath, dateTime, name), - Text: "Download Text", - Class: "download", - }, - } - - // TODO(manuel, 2023-05-25) Ignore indexTemplateName for now - // See https://github.com/go-go-golems/sqleton/issues/162 - _ = cd.IndexTemplateName - - dt := &datatables.DataTables{ - Command: sqlCommand.Description(), - Links: links, - BasePath: path, - JSRendering: true, - UseDataTables: false, - AdditionalData: cd.AdditionalData, + options := []datatables.QueryHandlerOption{ + datatables.WithParserOptions(cd.computeParserOptions()...), + datatables.WithTemplateLookup(cd.TemplateLookup), + datatables.WithTemplateName(cd.TemplateName), + datatables.WithAdditionalData(cd.AdditionalData), } - handler := datatables.NewQueryHandler(sqlCommand, - cd.TemplateLookup, - cd.TemplateName, - datatables.WithDataTables(dt), - datatables.WithQueryHandlerParserOptions(cd.computeParserOptions()...), - ) - - err := handler.Handle(c, c.Writer) - if err != nil { - log.Error().Err(err).Msg("error handling query") - c.JSON(http.StatusInternalServerError, gin.H{ - "error": err.Error(), - }) - } + server.HandleDataTables(sqlCommand, path, commandPath, options...) }) server.Router.GET(path+"/download/*path", func(c *gin.Context) { diff --git a/pkg/server/server.go b/pkg/server/server.go index 76cb984..d03f096 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -7,14 +7,17 @@ import ( "github.com/gin-gonic/contrib/gzip" "github.com/gin-gonic/gin" "github.com/go-go-golems/glazed/pkg/cmds" + "github.com/go-go-golems/parka/pkg/glazed/handlers/datatables" "github.com/go-go-golems/parka/pkg/glazed/handlers/json" "github.com/go-go-golems/parka/pkg/glazed/parser" "github.com/go-go-golems/parka/pkg/render" + "github.com/go-go-golems/parka/pkg/render/layout" utils_fs "github.com/go-go-golems/parka/pkg/utils/fs" "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" "io/fs" "net/http" + "time" ) //go:embed "web/src/templates/*" @@ -237,3 +240,71 @@ func (s *Server) HandleJSONQueryHandler( } } } + +func (s *Server) HandleDataTables( + cmd cmds.GlazeCommand, + path string, + commandPath string, + options ...datatables.QueryHandlerOption, +) gin.HandlerFunc { + // TODO(manuel, 2023-07-02) Move this to the datatables package + return func(c *gin.Context) { + name := cmd.Description().Name + dateTime := time.Now().Format("2006-01-02--15-04-05") + links := []layout.Link{ + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.csv", path, commandPath, dateTime, name), + Text: "Download CSV", + Class: "download", + }, + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.json", path, commandPath, dateTime, name), + Text: "Download JSON", + Class: "download", + }, + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.xlsx", path, commandPath, dateTime, name), + Text: "Download Excel", + Class: "download", + }, + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.md", path, commandPath, dateTime, name), + Text: "Download Markdown", + Class: "download", + }, + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.html", path, commandPath, dateTime, name), + Text: "Download HTML", + Class: "download", + }, + { + Href: fmt.Sprintf("%s/download/%s/%s-%s.txt", path, commandPath, dateTime, name), + Text: "Download Text", + Class: "download", + }, + } + + dt := &datatables.DataTables{ + Command: cmd.Description(), + Links: links, + BasePath: path, + JSRendering: true, + UseDataTables: false, + } + + options_ := []datatables.QueryHandlerOption{ + datatables.WithDataTables(dt), + } + options_ = append(options_, options...) + + handler := datatables.NewQueryHandler(cmd, options_...) + + err := handler.Handle(c, c.Writer) + if err != nil { + log.Error().Err(err).Msg("error handling query") + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + } + } +}