view: added start download button to subreddit details page

This commit is contained in:
Tigor Hutasuhut 2024-05-02 20:59:32 +07:00
parent fe1ad50670
commit 08d81a2f94
5 changed files with 164 additions and 46 deletions

View file

@ -28,8 +28,10 @@ func (routes *Routes) Register(router chi.Router) {
router.Get("/hot_reload", routes.CreateHotReloadRoute()) router.Get("/hot_reload", routes.CreateHotReloadRoute())
} }
router.Group(routes.registerWWWRoutes) router.Route("/htmx", routes.registerHTMXRoutes)
router.Route("/api/v1", routes.registerV1APIRoutes) router.Route("/api/v1", routes.registerV1APIRoutes)
router.Group(routes.registerWWWRoutes)
} }
func (routes *Routes) registerV1APIRoutes(router chi.Router) { func (routes *Routes) registerV1APIRoutes(router chi.Router) {
@ -51,6 +53,14 @@ func (routes *Routes) registerV1APIRoutes(router chi.Router) {
router.Get("/events", routes.EventsAPI) router.Get("/events", routes.EventsAPI)
} }
func (routes *Routes) registerHTMXRoutes(router chi.Router) {
router.Use(otelchi.Middleware("redmage"))
router.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
router.Use(chimiddleware.SetHeader("Content-Type", "text/html; charset=utf-8"))
router.Post("/subreddits/start", routes.SubredditStartDownloadHTMX)
}
func (routes *Routes) registerWWWRoutes(router chi.Router) { func (routes *Routes) registerWWWRoutes(router chi.Router) {
router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir)))) router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir))))

View file

@ -1,41 +0,0 @@
package routes
import (
"encoding/json"
"net/http"
"github.com/tigorlazuardi/redmage/api"
"github.com/tigorlazuardi/redmage/pkg/errs"
"github.com/tigorlazuardi/redmage/pkg/log"
)
func (r *Routes) SubredditStartDownloadAPI(rw http.ResponseWriter, req *http.Request) {
enc := json.NewEncoder(rw)
if r.Config.String("download.directory") == "" {
rw.WriteHeader(http.StatusBadRequest)
_ = enc.Encode(map[string]string{"error": "cannot download subreddits when download directory is not configured"})
return
}
ctx := req.Context()
var body api.PubsubStartDownloadSubredditParams
err := json.NewDecoder(req.Body).Decode(&body)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
_ = enc.Encode(map[string]string{"error": err.Error()})
return
}
err = r.API.PubsubStartDownloadSubreddit(ctx, body)
if err != nil {
log.New(ctx).Err(err).Error("failed to start subreddit download", "subreddit", body.Subreddit)
code, message := errs.HTTPMessage(err)
rw.WriteHeader(code)
_ = enc.Encode(map[string]string{"error": message})
return
}
_ = enc.Encode(map[string]string{"message": "subreddit enqueued"})
}

View file

@ -0,0 +1,77 @@
package routes
import (
"encoding/json"
"fmt"
"net/http"
"github.com/tigorlazuardi/redmage/api"
"github.com/tigorlazuardi/redmage/pkg/errs"
"github.com/tigorlazuardi/redmage/pkg/log"
"github.com/tigorlazuardi/redmage/views/components"
)
func (r *Routes) SubredditStartDownloadAPI(rw http.ResponseWriter, req *http.Request) {
ctx, span := tracer.Start(req.Context(), "Routes.SubredditStartDownloadAPI")
defer span.End()
enc := json.NewEncoder(rw)
if r.Config.String("download.directory") == "" {
rw.WriteHeader(http.StatusBadRequest)
_ = enc.Encode(map[string]string{"error": "cannot download subreddits when download directory is not configured"})
return
}
var body api.PubsubStartDownloadSubredditParams
err := json.NewDecoder(req.Body).Decode(&body)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
_ = enc.Encode(map[string]string{"error": err.Error()})
return
}
err = r.API.PubsubStartDownloadSubreddit(ctx, body)
if err != nil {
log.New(ctx).Err(err).Error("failed to start subreddit download", "subreddit", body.Subreddit)
code, message := errs.HTTPMessage(err)
rw.WriteHeader(code)
_ = enc.Encode(map[string]string{"error": message})
return
}
_ = enc.Encode(map[string]string{"message": "subreddit enqueued"})
}
func (routes *Routes) SubredditStartDownloadHTMX(rw http.ResponseWriter, r *http.Request) {
ctx, span := tracer.Start(r.Context(), "Routes.SubredditStartDownloadHTMX")
defer span.End()
if routes.Config.String("download.directory") == "" {
rw.WriteHeader(http.StatusBadRequest)
if err := components.ErrorNotication("Cannot download subreddits when download directory is not configured").Render(ctx, rw); err != nil {
log.New(ctx).Err(err).Error("failed to render error notification")
}
return
}
var body api.PubsubStartDownloadSubredditParams
body.Subreddit = r.FormValue("subreddit")
err := routes.API.PubsubStartDownloadSubreddit(ctx, body)
if err != nil {
log.New(ctx).Err(err).Error("failed to start subreddit download", "subreddit", body.Subreddit)
code, message := errs.HTTPMessage(err)
rw.WriteHeader(code)
if err := components.ErrorNotication(message).Render(ctx, rw); err != nil {
log.New(ctx).Err(err).Error("failed to render error notification")
}
return
}
msg := fmt.Sprintf("Subreddit %s enqueued", body.Subreddit)
if err := components.SuccessNotification(msg).Render(ctx, rw); err != nil {
log.New(ctx).Err(err).Error("failed to render success notification")
}
}

View file

@ -0,0 +1,58 @@
package components
const NotificationContainerID = "#notification-container"
templ NotificationContainer() {
<div id="notification-container" class="fixed bottom-4 right-4 z-50"></div>
}
templ InfoNotication(messages ...string) {
<div
hx-on::load="setTimeout(() => this.remove(), 5000)"
class="toast"
onclick="this.remove()"
>
<div class="alert alert-info hover:bg-info-content transition-all">
for i, message := range messages {
<span>{ message }</span>
if i != len(messages) - 1 {
<br/>
}
}
</div>
</div>
}
templ ErrorNotication(messages ...string) {
<div
hx-on::load="setTimeout(() => this.remove(), 5000)"
class="toast"
onclick="this.remove()"
>
<div class="alert alert-error hover:bg-error-content transition-all">
for i, message := range messages {
<span>{ message }</span>
if i != len(messages) - 1 {
<br/>
}
}
</div>
</div>
}
templ SuccessNotification(messages ...string) {
<div
hx-on::load="setTimeout(() => this.remove(), 5000)"
class="toast"
onclick="this.remove()"
>
<div class="alert alert-success hover:bg-success-content transition-all">
for i, message := range messages {
<span>{ message }</span>
if i != len(messages) - 1 {
<br/>
}
}
</div>
</div>
}

View file

@ -20,6 +20,7 @@ templ Detailsview(c *views.Context, data Data) {
@components.Head(c, components.HeadTitle("Redmage - Subreddits")) @components.Head(c, components.HeadTitle("Redmage - Subreddits"))
@components.Body(c) { @components.Body(c) {
@DetailsContent(c, data) @DetailsContent(c, data)
@components.NotificationContainer()
} }
} }
} }
@ -31,10 +32,23 @@ templ DetailsContent(c *views.Context, data Data) {
<h1>Error: { data.Error }</h1> <h1>Error: { data.Error }</h1>
} else { } else {
<h1>Subreddit { data.Subreddit.Name }</h1> <h1>Subreddit { data.Subreddit.Name }</h1>
<h2> <div class="flex flex-wrap justify-between content-center">
Total Images: <h2 class="my-auto">
{ strconv.FormatInt(data.TotalImages, 10) } Total Images:
</h2> { strconv.FormatInt(data.TotalImages, 10) }
</h2>
<button
hx-post="/htmx/subreddits/start"
hx-include="this"
class="btn btn-info"
hx-target={ components.NotificationContainerID }
hx-target-error={ components.NotificationContainerID }
hx-swap="afterbegin"
>
Start Download
<input type="hidden" name="subreddit" value={ data.Subreddit.Name }/>
</button>
</div>
<div class="divider"></div> <div class="divider"></div>
<div class="flex gap-4 flex-wrap justify-between content-center"> <div class="flex gap-4 flex-wrap justify-between content-center">
@FilterBar(c, data) @FilterBar(c, data)