mirror of
https://github.com/eduardolat/pgbackweb.git
synced 2026-01-26 14:39:24 -06:00
Add edit webhook functionality
This commit is contained in:
@@ -3,6 +3,7 @@ UPDATE webhooks
|
||||
SET
|
||||
name = COALESCE(sqlc.narg('name'), name),
|
||||
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
||||
event_type = COALESCE(sqlc.narg('event_type'), event_type),
|
||||
target_ids = COALESCE(sqlc.narg('target_ids'), target_ids),
|
||||
url = COALESCE(sqlc.narg('url'), url),
|
||||
method = COALESCE(sqlc.narg('method'), method),
|
||||
|
||||
@@ -137,23 +137,53 @@ func createAndUpdateWebhookForm(
|
||||
))
|
||||
}
|
||||
|
||||
pickedTargetIds := ""
|
||||
if len(pickedWebhook.TargetIds) > 0 {
|
||||
for _, tid := range pickedWebhook.TargetIds {
|
||||
pickedTargetIds += fmt.Sprintf("'%s',", tid.String())
|
||||
}
|
||||
}
|
||||
|
||||
return html.Div(
|
||||
html.Class("space-y-2"),
|
||||
|
||||
alpine.XData(`{
|
||||
eventType: "",
|
||||
targetIds: [],
|
||||
eventType: "`+pickedWebhook.EventType+`",
|
||||
targetIds: [`+pickedTargetIds+`],
|
||||
|
||||
isEventType(eventType) {
|
||||
return this.eventType === eventType
|
||||
},
|
||||
|
||||
init () {
|
||||
autoGrowHeadersTextarea() {
|
||||
textareaAutoGrow($refs.headersTextarea)
|
||||
},
|
||||
|
||||
autoGrowBodyTextarea() {
|
||||
textareaAutoGrow($refs.bodyTextarea)
|
||||
},
|
||||
|
||||
formatHeadersTextarea() {
|
||||
const el = $refs.headersTextarea
|
||||
el.value = formatJson(el.value)
|
||||
this.autoGrowHeadersTextarea()
|
||||
},
|
||||
|
||||
formatBodyTextarea() {
|
||||
const el = $refs.bodyTextarea
|
||||
el.value = formatJson(el.value)
|
||||
this.autoGrowBodyTextarea()
|
||||
},
|
||||
|
||||
init() {
|
||||
$watch('eventType', (value, oldValue) => {
|
||||
if (value !== oldValue) {
|
||||
this.targetIds = []
|
||||
}
|
||||
})
|
||||
|
||||
this.formatHeadersTextarea()
|
||||
this.formatBodyTextarea()
|
||||
}
|
||||
}`),
|
||||
|
||||
@@ -296,6 +326,9 @@ func createAndUpdateWebhookForm(
|
||||
Placeholder: `{ "Authorization": "Bearer my-token" }`,
|
||||
HelpText: `By default it will send a { "Content-Type": "application/json" } header.`,
|
||||
Children: []gomponents.Node{
|
||||
alpine.XRef("headersTextarea"),
|
||||
alpine.XOn("click.outside", "formatHeadersTextarea()"),
|
||||
alpine.XOn("input", "autoGrowHeadersTextarea()"),
|
||||
gomponents.If(
|
||||
shouldPrefill, gomponents.Text(pickedWebhook.Headers.String),
|
||||
),
|
||||
@@ -308,6 +341,9 @@ func createAndUpdateWebhookForm(
|
||||
Placeholder: `{ "key": "value" }`,
|
||||
HelpText: `By default it will send an empty json object {}.`,
|
||||
Children: []gomponents.Node{
|
||||
alpine.XRef("bodyTextarea"),
|
||||
alpine.XOn("click.outside", "formatBodyTextarea()"),
|
||||
alpine.XOn("input", "autoGrowBodyTextarea()"),
|
||||
gomponents.If(
|
||||
shouldPrefill, gomponents.Text(pickedWebhook.Body.String),
|
||||
),
|
||||
|
||||
@@ -86,7 +86,7 @@ func createWebhookForm(
|
||||
backups []dbgen.Backup,
|
||||
) gomponents.Node {
|
||||
return html.Form(
|
||||
htmx.HxPost("/dashboard/webhooks"),
|
||||
htmx.HxPost("/dashboard/webhooks/create"),
|
||||
htmx.HxDisabledELT("find button[type='submit']"),
|
||||
html.Class("space-y-2"),
|
||||
|
||||
@@ -111,7 +111,7 @@ func createWebhookButton() gomponents.Node {
|
||||
Title: "Create webhook",
|
||||
Content: []gomponents.Node{
|
||||
html.Div(
|
||||
htmx.HxGet("/dashboard/webhooks/create-form"),
|
||||
htmx.HxGet("/dashboard/webhooks/create"),
|
||||
htmx.HxSwap("outerHTML"),
|
||||
htmx.HxTrigger("intersect once"),
|
||||
html.Class("p-10 flex justify-center"),
|
||||
|
||||
153
internal/view/web/dashboard/webhooks/edit_webhook.go
Normal file
153
internal/view/web/dashboard/webhooks/edit_webhook.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package webhooks
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/database/dbgen"
|
||||
"github.com/eduardolat/pgbackweb/internal/util/echoutil"
|
||||
"github.com/eduardolat/pgbackweb/internal/validate"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/htmx"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
type editWebhookDTO struct {
|
||||
Name string `form:"name" validate:"required"`
|
||||
EventType string `form:"event_type" validate:"required"`
|
||||
TargetIds []uuid.UUID `form:"target_ids" validate:"required,gt=0"`
|
||||
IsActive string `form:"is_active" validate:"required,oneof=true false"`
|
||||
Url string `form:"url" validate:"required,url"`
|
||||
Method string `form:"method" validate:"required,oneof=GET POST"`
|
||||
Headers string `form:"headers" validate:"omitempty,json"`
|
||||
Body string `form:"body" validate:"omitempty,json"`
|
||||
}
|
||||
|
||||
func (h *handlers) editWebhookHandler(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
webhookID, err := uuid.Parse(c.Param("webhookID"))
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
var formData editWebhookDTO
|
||||
if err := c.Bind(&formData); err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
if err := validate.Struct(&formData); err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
_, err = h.servs.WebhooksService.UpdateWebhook(
|
||||
ctx, dbgen.WebhooksServiceUpdateWebhookParams{
|
||||
WebhookID: webhookID,
|
||||
Name: sql.NullString{String: formData.Name, Valid: true},
|
||||
EventType: sql.NullString{String: formData.EventType, Valid: true},
|
||||
TargetIds: formData.TargetIds,
|
||||
IsActive: sql.NullBool{Bool: formData.IsActive == "true", Valid: true},
|
||||
Url: sql.NullString{String: formData.Url, Valid: true},
|
||||
Method: sql.NullString{String: formData.Method, Valid: true},
|
||||
Headers: sql.NullString{String: formData.Headers, Valid: true},
|
||||
Body: sql.NullString{String: formData.Body, Valid: true},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
return htmx.RespondAlertWithRefresh(c, "Webhook updated")
|
||||
}
|
||||
|
||||
func (h *handlers) editWebhookFormHandler(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
webhookID, err := uuid.Parse(c.Param("webhookID"))
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
webhook, err := h.servs.WebhooksService.GetWebhook(ctx, webhookID)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
databases, err := h.servs.DatabasesService.GetAllDatabases(ctx)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
destinations, err := h.servs.DestinationsService.GetAllDestinations(ctx)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
backups, err := h.servs.BackupsService.GetAllBackups(ctx)
|
||||
if err != nil {
|
||||
return htmx.RespondToastError(c, err.Error())
|
||||
}
|
||||
|
||||
return echoutil.RenderGomponent(c, http.StatusOK, editWebhookForm(
|
||||
webhook, databases, destinations, backups,
|
||||
))
|
||||
}
|
||||
|
||||
func editWebhookForm(
|
||||
webhook dbgen.Webhook,
|
||||
databases []dbgen.DatabasesServiceGetAllDatabasesRow,
|
||||
destinations []dbgen.DestinationsServiceGetAllDestinationsRow,
|
||||
backups []dbgen.Backup,
|
||||
) gomponents.Node {
|
||||
return html.Form(
|
||||
htmx.HxPost("/dashboard/webhooks/"+webhook.ID.String()+"/edit"),
|
||||
htmx.HxDisabledELT("find button[type='submit']"),
|
||||
html.Class("space-y-2"),
|
||||
|
||||
createAndUpdateWebhookForm(databases, destinations, backups, webhook),
|
||||
|
||||
html.Div(
|
||||
html.Class("flex justify-end items-center space-x-2 pt-2"),
|
||||
component.HxLoadingMd(),
|
||||
html.Button(
|
||||
html.Class("btn btn-primary"),
|
||||
html.Type("submit"),
|
||||
component.SpanText("Save"),
|
||||
lucide.Save(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func editWebhookButton(webhookID uuid.UUID) gomponents.Node {
|
||||
mo := component.Modal(component.ModalParams{
|
||||
Size: component.SizeLg,
|
||||
Title: "Edit webhook",
|
||||
Content: []gomponents.Node{
|
||||
html.Div(
|
||||
htmx.HxGet("/dashboard/webhooks/"+webhookID.String()+"/edit"),
|
||||
htmx.HxSwap("outerHTML"),
|
||||
htmx.HxTrigger("intersect once"),
|
||||
html.Class("p-10 flex justify-center"),
|
||||
component.HxLoadingMd(),
|
||||
),
|
||||
},
|
||||
})
|
||||
|
||||
button := html.Button(
|
||||
mo.OpenerAttr,
|
||||
html.Class("btn btn-neutral btn-sm btn-square btn-ghost"),
|
||||
lucide.Pencil(),
|
||||
)
|
||||
|
||||
return html.Div(
|
||||
html.Class("inline-block"),
|
||||
mo.HTML,
|
||||
html.Div(
|
||||
html.Class("inline-block tooltip tooltip-right"),
|
||||
html.Data("tip", "Edit webhook"),
|
||||
button,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -57,11 +57,17 @@ func listWebhooks(
|
||||
html.Class("w-[40px]"),
|
||||
html.Div(
|
||||
html.Class("flex justify-start space-x-1"),
|
||||
// editWebhookButton(webhook),
|
||||
editWebhookButton(whook.ID),
|
||||
// deleteWebhookButton(webhook.ID),
|
||||
),
|
||||
),
|
||||
html.Td(component.SpanText(whook.Name)),
|
||||
html.Td(
|
||||
html.Div(
|
||||
html.Class("flex items-center space-x-2"),
|
||||
component.IsActivePing(whook.IsActive),
|
||||
component.SpanText(whook.Name),
|
||||
),
|
||||
),
|
||||
html.Td(component.SpanText(
|
||||
func() string {
|
||||
if name, ok := webhooks.FullEventTypes[whook.EventType]; ok {
|
||||
|
||||
@@ -21,8 +21,10 @@ func MountRouter(
|
||||
|
||||
parent.GET("", h.indexPageHandler)
|
||||
parent.GET("/list", h.listWebhooksHandler)
|
||||
parent.GET("/create-form", h.createWebhookFormHandler)
|
||||
parent.POST("", h.createWebhookHandler)
|
||||
parent.GET("/create", h.createWebhookFormHandler)
|
||||
parent.POST("/create", h.createWebhookHandler)
|
||||
parent.GET("/:webhookID/edit", h.editWebhookFormHandler)
|
||||
parent.POST("/:webhookID/edit", h.editWebhookHandler)
|
||||
// parent.DELETE("/:webhookID", h.deleteWebhookHandler)
|
||||
// parent.POST("/:webhookID/edit", h.editWebhookHandler)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user