Skip to content

Commit 0fb1b4b

Browse files
committed
feat(dashboard): admin dashboard
1 parent 1c115ca commit 0fb1b4b

110 files changed

Lines changed: 27586 additions & 21 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,22 @@ jobs:
2525
with:
2626
version: v2.11
2727
only-new-issues: true
28+
29+
ui-lint:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- uses: actions/setup-node@v4
35+
with:
36+
node-version: 24
37+
cache: npm
38+
cache-dependency-path: ui/package-lock.json
39+
40+
- name: install dependencies
41+
working-directory: ui
42+
run: npm ci
43+
44+
- name: eslint
45+
working-directory: ui
46+
run: npm run lint

.github/workflows/test.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,18 @@ jobs:
9595
token: ${{ secrets.CODECOV_TOKEN }}
9696
fail_ci_if_error: true
9797
flags: integration-o11
98+
99+
test-ui:
100+
runs-on: ubuntu-latest
101+
steps:
102+
- uses: actions/checkout@v4
103+
- uses: actions/setup-node@v4
104+
with:
105+
node-version: 24
106+
cache: npm
107+
cache-dependency-path: ui/package-lock.json
108+
- name: install dependencies
109+
working-directory: ui
110+
run: npm ci
111+
- name: runs ui tests
112+
run: npm --prefix ui run test:run

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
coverage.*
44
webhookx
55
*.log
6-
dist/
76
test/output
87
**/node_modules/
98
**/rust/target/

AGENTS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# AGENTS.md
2+
3+
This file provides guidance to AI coding assistants when working with code in this repository.
4+
5+
## Project Overview
6+
7+
8+
## UI
9+

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

Dockerfile

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1+
FROM node:24-alpine AS ui
2+
3+
WORKDIR /webhookx
4+
5+
COPY ui/package.json ui/package-lock.json ./ui/
6+
RUN npm --prefix ui ci
7+
8+
COPY openapi.yml ./openapi.yml
9+
COPY ui/ ./ui/
10+
RUN npm --prefix ui run build
11+
112
FROM golang:1.26.5 AS build-env
213

314
WORKDIR /go/src/webhookx-io/webhookx
415

516
COPY api/license api/license
6-
COPY go.mod /go/src/webhookx-io/webhookx
7-
COPY go.sum /go/src/webhookx-io/webhookx
17+
COPY go.mod go.sum ./
818
RUN go mod download
919

10-
COPY . .
20+
COPY --exclude=ui/dist . .
21+
COPY --from=ui /webhookx/ui/dist ./ui/dist
1122
RUN make build
1223

1324
FROM alpine:3.22
@@ -17,6 +28,7 @@ COPY --from=build-env /go/src/webhookx-io/webhookx/webhookx /usr/local/bin
1728
EXPOSE 9600
1829
EXPOSE 9601
1930
EXPOSE 9602
31+
EXPOSE 9605
2032

2133

2234
CMD ["webhookx", "start"]

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ LDFLAGS = --ldflags "\
1010
clean:
1111
go clean
1212
go clean -testcache
13+
rm -rf ui/dist/*
14+
mkdir -p ui/dist
15+
touch ui/dist/.gitkeep
1316

1417
build:
1518
CGO_ENABLED=0 go build -o webhookx ${LDFLAGS} ./cmd/main

admin/api/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ func (api *API) json(code int, w http.ResponseWriter, data interface{}) {
6363
response.JSON(w, code, data)
6464
}
6565

66-
6766
func (api *API) lookupOperation(path string, method string) *openapi3.Operation {
6867
operation := openapi.Spec.Paths.Find(path).GetOperation(method)
6968
if operation == nil {
@@ -151,6 +150,7 @@ func (api *API) Handler() http.Handler {
151150

152151
r.HandleFunc("/", api.Index).Methods("GET").Name("admin.root")
153152
r.HandleFunc("/license", api.GetLicense).Methods("GET").Name("admin.license.get")
153+
r.HandleFunc("/catalog", api.GetCatalog).Methods("GET").Name("admin.catalog")
154154

155155
r.HandleFunc("/workspaces/{workspace}/config/sync", api.Sync).Methods("POST").Name("admin.config.sync")
156156
r.HandleFunc("/workspaces/{workspace}/config/dump", api.Dump).Methods("POST").Name("admin.config.dump")

admin/api/catalog.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package api
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/getkin/kin-openapi/openapi3"
7+
"github.com/webhookx-io/webhookx/pkg/plugin"
8+
)
9+
10+
type Catalog struct {
11+
Plugins []CatalogPlugin `json:"plugins"`
12+
}
13+
14+
type CatalogPlugin struct {
15+
Name string `json:"name"`
16+
Type string `json:"type"`
17+
Description string `json:"description"`
18+
Schema *openapi3.Schema `json:"schema"`
19+
}
20+
21+
func (api *API) GetCatalog(w http.ResponseWriter, _ *http.Request) {
22+
registrations := plugin.ListRegistration()
23+
plugins := make([]CatalogPlugin, 0, len(registrations))
24+
25+
for _, registration := range registrations {
26+
p := registration.Factory()
27+
plugins = append(plugins, CatalogPlugin{
28+
Name: registration.Name,
29+
Type: string(registration.Type),
30+
Description: p.Description(),
31+
Schema: p.ConfigSchema(),
32+
})
33+
}
34+
35+
catalog := &Catalog{
36+
Plugins: plugins,
37+
}
38+
39+
api.json(http.StatusOK, w, catalog)
40+
}

app/app.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/webhookx-io/webhookx/config"
1919
"github.com/webhookx-io/webhookx/config/modules"
2020
"github.com/webhookx-io/webhookx/constants"
21+
"github.com/webhookx-io/webhookx/dashboard"
2122
"github.com/webhookx-io/webhookx/db"
2223
"github.com/webhookx-io/webhookx/db/dao"
2324
"github.com/webhookx-io/webhookx/db/migrator"
@@ -184,6 +185,11 @@ func (app *Application) initialize() error {
184185
return err
185186
}
186187

188+
// dashboard
189+
if err := app.initDashboard(&cfg.Dashboard); err != nil {
190+
return err
191+
}
192+
187193
// gateway
188194
if err := app.initGateway(&cfg.Proxy, services, dispatcher, metrics); err != nil {
189195
return err
@@ -287,6 +293,17 @@ func (app *Application) initAdmin(cfg *modules.AdminConfig, services *services.S
287293
return nil
288294
}
289295

296+
func (app *Application) initDashboard(cfg *modules.DashboardConfig) error {
297+
if cfg.IsEnabled() {
298+
dashboard, err := dashboard.NewDashboard(*cfg)
299+
if err != nil {
300+
return err
301+
}
302+
app.registerService(dashboard)
303+
}
304+
return nil
305+
}
306+
290307
func (app *Application) initGateway(cfg *modules.ProxyConfig, services *services.Services, d *dispatcher.Dispatcher, metrics *metrics.Metrics) error {
291308
if cfg.IsEnabled() {
292309
opts := proxy.Options{
@@ -507,6 +524,7 @@ func (app *Application) Start() error {
507524
fmt.Println("- Version:", utils.Colorize(webhookx.VERSION, utils.ColorDarkBlue, colored))
508525
fmt.Println("- Proxy URL:", utils.Colorize(app.cfg.Proxy.URL(), utils.ColorDarkBlue, colored))
509526
fmt.Println("- Admin URL:", utils.Colorize(app.cfg.Admin.URL(), utils.ColorDarkBlue, colored))
527+
fmt.Println("- Dashboard URL:", utils.Colorize(app.cfg.Dashboard.URL(), utils.ColorDarkBlue, colored))
510528
fmt.Println("- Status URL:", utils.Colorize(app.cfg.Status.URL(), utils.ColorDarkBlue, colored))
511529
fmt.Println("- Worker:", utils.Colorize(app.cfg.Worker.Status(), utils.ColorDarkBlue, colored))
512530
fmt.Println()
@@ -553,6 +571,7 @@ func (app *Application) Start() error {
553571
app.getService("eventbus"),
554572
app.getService("metrics"),
555573
app.getService("admin"),
574+
app.getService("dashboard"),
556575
app.getService("worker"),
557576
app.getService("proxy"),
558577
app.getService("status"),
@@ -578,7 +597,7 @@ func (app *Application) stop(ctx context.Context) error {
578597
defer func() { _ = app.log.Sync() }()
579598

580599
var errs []error
581-
errs = append(errs, stopServices(ctx, time.Second*10, app.getService("proxy"), app.getService("admin"), app.getService("status")))
600+
errs = append(errs, stopServices(ctx, time.Second*10, app.getService("proxy"), app.getService("admin"), app.getService("dashboard"), app.getService("status")))
582601
errs = append(errs, stopServices(ctx, 0, app.getService("eventbus")))
583602
errs = append(errs, stopServices(ctx, 0, app.getService("worker")))
584603
errs = append(errs, stopServices(ctx, time.Second*5, app.getService("metrics"), app.getService("tracing")))

0 commit comments

Comments
 (0)