Skip to content

feat: React web UI dashboard #2241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e9b2159
chore: set up repository with React + Vite
orimdominic Feb 11, 2025
59c04c4
chore: set up shadcn (#2242)
orimdominic Feb 18, 2025
d89697d
feat: login page implementation (#2248)
orimdominic Feb 22, 2025
0ea02a1
feat: sign up page (UI and implementation logic) (#2249)
orimdominic Feb 23, 2025
8ba08aa
feat: dashboard UI framework (#2253)
orimdominic Mar 3, 2025
826b22c
feat: create organisation (#2254)
orimdominic Mar 5, 2025
31ab2c5
refactor: extract create-organisation to its own file
orimdominic Mar 5, 2025
ca4c7a0
fix: create organisation does not reflect app-wide (#2257)
orimdominic Mar 5, 2025
19e0740
feat: add another organisation (#2258)
orimdominic Mar 6, 2025
72d9db2
feat: organisation settings (#2259)
orimdominic Mar 9, 2025
abe6285
fix: incorrect handling of get orgId in http-service
orimdominic Mar 9, 2025
696e2b5
fix: clear sessionStorage on logout
orimdominic Mar 9, 2025
4863c6f
fix: clear all storage on logout
orimdominic Mar 9, 2025
52af036
chore: set indent size to 2
orimdominic Mar 9, 2025
ede1fd4
feat: create project (#2260)
orimdominic Mar 12, 2025
6fa5de0
fix: inconsistent state management of orgs
orimdominic Mar 12, 2025
1f95ace
fix: inconsistent organisation and project states (#2261)
orimdominic Mar 12, 2025
4eb632e
fix: duplicate id attribute on elements
orimdominic Mar 13, 2025
db8de57
fix: project is null on /projects loaded
orimdominic Mar 13, 2025
9a09afc
feat: update project config (#2262)
orimdominic Mar 14, 2025
2184a59
fix: use session storage
orimdominic Mar 14, 2025
d65df0d
feat: delete project (#2263)
orimdominic Mar 14, 2025
85414a5
refactor: update projects w/out api call
orimdominic Mar 14, 2025
36a30b4
fix: unable to update project caused by sig header field
orimdominic Mar 15, 2025
18fc653
feat: project signature config (#2265)
orimdominic Mar 16, 2025
90b24f4
feat: project endpoint config (#2267)
orimdominic Mar 16, 2025
87fa88f
feat: project meta events config (#2268)
orimdominic Mar 17, 2025
bc976fb
chore: remove keys
orimdominic Mar 18, 2025
32661d3
feat: project event types config (#2271)
orimdominic Mar 18, 2025
8447941
feat: project secrets config (#2272)
orimdominic Mar 19, 2025
54fece4
feat: create endpoint (#2274)
orimdominic Mar 20, 2025
38fa2a6
feat: list endpoints page (#2276)
orimdominic Mar 23, 2025
74c92e6
feat: update endpoint (#2277)
orimdominic Mar 24, 2025
0d624c8
feat: create source (#2279)
orimdominic Apr 1, 2025
09b3aca
feat: create subscription (#2281)
orimdominic Apr 2, 2025
91e2e32
feat: list sources, delete source (#2282)
orimdominic Apr 3, 2025
58a3a2d
feat: implement permissions for modifying source
orimdominic Apr 3, 2025
7bf95f5
feat: update source (#2283)
orimdominic Apr 4, 2025
63f37ed
feat: list, filter subscriptions, delete subscription (#2284)
orimdominic Apr 6, 2025
9cf6388
feat: update subscription (#2285)
orimdominic Apr 7, 2025
c9d1e6b
feat: list meta events (#2286)
orimdominic Apr 9, 2025
03670a3
feat: events log (#2287)
orimdominic Apr 12, 2025
40a45de
patch: event deliveries (#2288)
orimdominic Apr 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
443 changes: 241 additions & 202 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v25.1.1
v25.2.1
4 changes: 3 additions & 1 deletion api/server_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ package api

import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/frain-dev/convoy/internal/pkg/fflag"
"github.com/frain-dev/convoy/internal/pkg/keys"

"io"
"math/rand"
"net/http"
Expand Down Expand Up @@ -97,7 +99,7 @@ func getDB() database.Database {
_ = os.Setenv("TZ", "") // Use UTC by default :)

dbHooks := hooks.Init()
dbHooks.RegisterHook(datastore.EndpointCreated, func(data interface{}, changelog interface{}) {})
dbHooks.RegisterHook(datastore.EndpointCreated, func(ctx context.Context, data interface{}, changelog interface{}) {})

pDB = db
})
Expand Down
1 change: 1 addition & 0 deletions cmd/hooks/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ func PreRun(app *cli.App, db *postgres.Postgres) func(cmd *cobra.Command, args [
if err != nil {
return err
}
// todo(raymond): I don't think the check below needs to exist since we perform the check in the tracer.Init() above.
if cfg.Tracer.Type == config.DatadogTracerProvider && !app.Licenser.DatadogTracing() {
lo.Error("your instance does not have access to datadog tracing, upgrade to access this feature")
_ = app.TracerBackend.Shutdown(context.Background())
Expand Down
29 changes: 21 additions & 8 deletions cmd/worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
a.Licenser,
featureFlag,
net.LoggerOption(lo),
net.TracerOption(a.TracerBackend),
net.DetailedTraceOption(true),
net.ProxyOption(cfg.Server.HTTP.HttpProxy),
net.AllowListOption(cfg.Dispatcher.AllowList),
net.BlockListOption(cfg.Dispatcher.BlockList),
Expand Down Expand Up @@ -364,8 +366,8 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
attemptRepo,
circuitBreakerManager,
featureFlag,
a.TracerBackend,
), newTelemetry)
a.TracerBackend),
newTelemetry)

consumer.RegisterHandlers(convoy.CreateEventProcessor, task.ProcessEventCreation(
defaultCh,
Expand All @@ -375,7 +377,10 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
eventDeliveryRepo,
a.Queue,
subRepo,
deviceRepo, a.Licenser), newTelemetry)
deviceRepo,
a.Licenser,
a.TracerBackend),
newTelemetry)

consumer.RegisterHandlers(convoy.RetryEventProcessor, task.ProcessRetryEventDelivery(
endpointRepo,
Expand All @@ -388,8 +393,8 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
attemptRepo,
circuitBreakerManager,
featureFlag,
a.TracerBackend,
), newTelemetry)
a.TracerBackend),
newTelemetry)

consumer.RegisterHandlers(convoy.CreateBroadcastEventProcessor, task.ProcessBroadcastEventCreation(
broadcastCh,
Expand All @@ -400,7 +405,9 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
a.Queue,
subRepo,
deviceRepo,
a.Licenser), newTelemetry)
a.Licenser,
a.TracerBackend),
newTelemetry)

consumer.RegisterHandlers(convoy.CreateDynamicEventProcessor, task.ProcessDynamicEventCreation(
dynamicCh,
Expand All @@ -410,7 +417,10 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
eventDeliveryRepo,
a.Queue,
subRepo,
deviceRepo, a.Licenser), newTelemetry)
deviceRepo,
a.Licenser,
a.TracerBackend),
newTelemetry)

if a.Licenser.RetentionPolicy() {
consumer.RegisterHandlers(convoy.RetentionPolicies, task.RetentionPolicies(rd, ret), nil)
Expand All @@ -425,7 +435,10 @@ func StartWorker(ctx context.Context, a *cli.App, cfg config.Configuration, inte
eventDeliveryRepo,
a.Queue,
subRepo,
deviceRepo, a.Licenser), newTelemetry)
deviceRepo,
a.Licenser,
a.TracerBackend),
newTelemetry)

consumer.RegisterHandlers(convoy.MonitorTwitterSources, task.MonitorTwitterSources(a.DB, a.Queue, rd), nil)

Expand Down
9 changes: 5 additions & 4 deletions database/hooks/hooks.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package hooks

import (
"context"
"errors"
"sync/atomic"

"github.com/frain-dev/convoy/datastore"
)

type hookMap map[datastore.HookEventType]func(data interface{}, changelog interface{})
type hookMap map[datastore.HookEventType]func(ctx context.Context, data interface{}, changelog interface{})

type Hook struct {
fns hookMap
Expand All @@ -30,13 +31,13 @@ func Init() *Hook {
return &Hook{fns: hookMap{}}
}

func (h *Hook) Fire(eventType datastore.HookEventType, data interface{}, changelog interface{}) {
func (h *Hook) Fire(ctx context.Context, eventType datastore.HookEventType, data interface{}, changelog interface{}) {
if fn, ok := h.fns[eventType]; ok {
fn(data, changelog)
fn(ctx, data, changelog)
}
}

func (h *Hook) RegisterHook(eventType datastore.HookEventType, fn func(data interface{}, changelog interface{})) {
func (h *Hook) RegisterHook(eventType datastore.HookEventType, fn func(ctx context.Context, data interface{}, changelog interface{})) {
h.fns[eventType] = fn
hookSingleton.Store(h)
}
17 changes: 9 additions & 8 deletions database/listener/endpoint_listener.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package listener

import (
"context"
"github.com/frain-dev/convoy/datastore"
"github.com/frain-dev/convoy/pkg/log"
"github.com/frain-dev/convoy/queue"
Expand All @@ -16,26 +17,26 @@ func NewEndpointListener(queue queue.Queuer, projectRepo datastore.ProjectReposi
return &EndpointListener{mEvent: mEvent}
}

func (e *EndpointListener) AfterCreate(data interface{}, _ interface{}) {
e.metaEvent(string(datastore.EndpointCreated), data)
func (e *EndpointListener) AfterCreate(ctx context.Context, data interface{}, _ interface{}) {
e.metaEvent(ctx, datastore.EndpointCreated, data)
}

func (e *EndpointListener) AfterUpdate(data interface{}, _ interface{}) {
e.metaEvent(string(datastore.EndpointUpdated), data)
func (e *EndpointListener) AfterUpdate(ctx context.Context, data interface{}, _ interface{}) {
e.metaEvent(ctx, datastore.EndpointUpdated, data)
}

func (e *EndpointListener) AfterDelete(data interface{}, _ interface{}) {
e.metaEvent(string(datastore.EndpointDeleted), data)
func (e *EndpointListener) AfterDelete(ctx context.Context, data interface{}, _ interface{}) {
e.metaEvent(ctx, datastore.EndpointDeleted, data)
}

func (e *EndpointListener) metaEvent(eventType string, data interface{}) {
func (e *EndpointListener) metaEvent(ctx context.Context, eventType datastore.HookEventType, data interface{}) {
endpoint, ok := data.(*datastore.Endpoint)
if !ok {
log.Errorf("invalid type for event - %s", eventType)
return
}

if err := e.mEvent.Run(eventType, endpoint.ProjectID, endpoint); err != nil {
if err := e.mEvent.Run(ctx, string(eventType), endpoint.ProjectID, endpoint); err != nil {
log.WithError(err).Error("endpoint meta event failed")
}
}
8 changes: 4 additions & 4 deletions database/listener/event_delivery_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ func NewEventDeliveryListener(queue queue.Queuer, projectRepo datastore.ProjectR
return &EventDeliveryListener{mEvent: mEvent, attemptsRepo: attemptsRepo}
}

func (e *EventDeliveryListener) AfterUpdate(data interface{}, _ interface{}) {
func (e *EventDeliveryListener) AfterUpdate(ctx context.Context, data interface{}, _ interface{}) {
eventDelivery, ok := data.(*datastore.EventDelivery)
if !ok {
log.Error("invalid type for event - eventdelivery.updated")
return
}

mEventDelivery := getMetaEventDelivery(eventDelivery)
attempts, err := e.attemptsRepo.FindDeliveryAttempts(context.Background(), mEventDelivery.UID)
attempts, err := e.attemptsRepo.FindDeliveryAttempts(ctx, mEventDelivery.UID)
if err != nil {
log.WithError(err).Error("event delivery meta event failed")
}
Expand All @@ -65,14 +65,14 @@ func (e *EventDeliveryListener) AfterUpdate(data interface{}, _ interface{}) {
}

if eventDelivery.Status == datastore.SuccessEventStatus {
err := e.mEvent.Run(string(datastore.EventDeliverySuccess), eventDelivery.ProjectID, mEventDelivery)
err = e.mEvent.Run(ctx, string(datastore.EventDeliverySuccess), eventDelivery.ProjectID, mEventDelivery)
if err != nil {
log.WithError(err).Error("event delivery meta event failed")
}
}

if eventDelivery.Status == datastore.FailureEventStatus {
err := e.mEvent.Run(string(datastore.EventDeliveryFailed), eventDelivery.ProjectID, mEventDelivery)
err = e.mEvent.Run(ctx, string(datastore.EventDeliveryFailed), eventDelivery.ProjectID, mEventDelivery)
if err != nil {
log.WithError(err).Error("event delivery meta event failed")
}
Expand Down
7 changes: 4 additions & 3 deletions database/listener/project_listener.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package listener

import (
"context"
"encoding/json"
"time"

Expand All @@ -19,11 +20,11 @@ func NewProjectListener(queue queue.Queuer) *ProjectListener {
return &ProjectListener{queue: queue}
}

func (e *ProjectListener) AfterUpdate(data interface{}, changelog interface{}) {
e.run(string(datastore.ProjectUpdated), data, changelog)
func (e *ProjectListener) AfterUpdate(ctx context.Context, data interface{}, changelog interface{}) {
e.run(ctx, datastore.ProjectUpdated, data, changelog)
}

func (e *ProjectListener) run(eventType string, data interface{}, changelog interface{}) {
func (e *ProjectListener) run(_ context.Context, eventType datastore.HookEventType, data interface{}, changelog interface{}) {
project, ok := data.(*datastore.Project)
if !ok {
log.Errorf("invalid type for project - %s", eventType)
Expand Down
6 changes: 3 additions & 3 deletions database/postgres/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (e *endpointRepo) CreateEndpoint(ctx context.Context, endpoint *datastore.E
return ErrEndpointNotCreated
}

go e.hook.Fire(datastore.EndpointCreated, endpoint, nil)
go e.hook.Fire(context.Background(), datastore.EndpointCreated, endpoint, nil)

return nil
}
Expand Down Expand Up @@ -418,7 +418,7 @@ func (e *endpointRepo) UpdateEndpoint(ctx context.Context, endpoint *datastore.E
return ErrEndpointNotUpdated
}

go e.hook.Fire(datastore.EndpointUpdated, endpoint, nil)
go e.hook.Fire(context.Background(), datastore.EndpointUpdated, endpoint, nil)
return nil
}

Expand Down Expand Up @@ -467,7 +467,7 @@ func (e *endpointRepo) DeleteEndpoint(ctx context.Context, endpoint *datastore.E
return err
}

go e.hook.Fire(datastore.EndpointDeleted, endpoint, nil)
go e.hook.Fire(context.Background(), datastore.EndpointDeleted, endpoint, nil)
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion database/postgres/event_delivery.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ func (e *eventDeliveryRepo) UpdateEventDeliveryMetadata(ctx context.Context, pro
return ErrEventDeliveryAttemptsNotUpdated
}

go e.hook.Fire(datastore.EventDeliveryUpdated, delivery, nil)
e.hook.Fire(ctx, datastore.EventDeliveryUpdated, delivery, nil)

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion database/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func getDB(t *testing.T) (database.Database, func()) {
var err error

dbHooks := hooks.Init()
dbHooks.RegisterHook(datastore.EndpointCreated, func(data interface{}, changelog interface{}) {})
dbHooks.RegisterHook(datastore.EndpointCreated, func(ctx context.Context, data interface{}, changelog interface{}) {})

_db, err = NewDB(getConfig())
require.NoError(t, err)
Expand Down
3 changes: 2 additions & 1 deletion database/postgres/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ func (p *projectRepo) UpdateProject(ctx context.Context, project *datastore.Proj
return err
}

go p.hook.Fire(datastore.ProjectUpdated, project, changelog)
go p.hook.Fire(context.Background(), datastore.ProjectUpdated, project, changelog)

return nil
}

Expand Down
4 changes: 3 additions & 1 deletion datastore/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (
"encoding/json"
"errors"
"fmt"
cb "github.com/frain-dev/convoy/pkg/circuit_breaker"
"math"
"net/http"
"strings"
"time"

cb "github.com/frain-dev/convoy/pkg/circuit_breaker"

"github.com/frain-dev/convoy/pkg/flatten"

"github.com/oklog/ulid/v2"
Expand Down Expand Up @@ -963,6 +964,7 @@ type EventDelivery struct {
Headers httpheader.HTTPHeader `json:"headers" db:"headers"`
URLQueryParams string `json:"url_query_params" db:"url_query_params"`
IdempotencyKey string `json:"idempotency_key" db:"idempotency_key"`

// Deprecated: Latency is deprecated.
Latency string `json:"latency" db:"latency"`
LatencySeconds float64 `json:"latency_seconds" db:"latency_seconds"`
Expand Down
2 changes: 1 addition & 1 deletion ee/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v25.1.1 Enterprise Edition
v25.2.1 Enterprise Edition
1 change: 1 addition & 0 deletions generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ package convoy
//go:generate mockgen --source internal/pkg/dedup/dedup.go --destination mocks/dedup.go -package mocks
//go:generate mockgen --source internal/pkg/memorystore/table.go --destination mocks/table.go -package mocks
//go:generate mockgen --source internal/pkg/license/license.go --destination mocks/license.go -package mocks
//go:generate mockgen --source internal/pkg/tracer/tracer.go --destination mocks/tracer.go -package mocks
1 change: 0 additions & 1 deletion internal/pkg/keys/hcpvault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ func TestNewHCPVaultKeyManagerEnv(t *testing.T) {
key, err := h.GetCurrentKeyFromCache()
assert.Nil(t, err)
assert.NotEmpty(t, key)
t.Logf("Retrieved key: %s", key)

// Happy path for setting a key
newKey := "from-test-" + time.Now().String()
Expand Down
8 changes: 3 additions & 5 deletions internal/pkg/socket/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ import (

func provideClient(r *Repo, c WebSocketConnection) *Client {
return &Client{
conn: c,
deviceID: "1234",
deviceRepo: r.DeviceRepo,
// EventTypes: []string{"*"},
conn: c,
deviceID: "1234",
deviceRepo: r.DeviceRepo,
eventDeliveryRepo: r.EventDeliveryRepo,
Device: &datastore.Device{
UID: "1234",
Expand Down Expand Up @@ -349,7 +348,6 @@ func TestParseTime(t *testing.T) {
client := provideClient(r, c)

since, err := client.parseTime(tt.args.message)
t.Log(since)

if tt.args.wantErr {
require.Error(t, tt.args.err, err)
Expand Down
Loading