1
0
Fork 0

Migrate Traefik Proxy dashboard UI to React

This commit is contained in:
Gina A. 2025-05-28 11:26:04 +02:00 committed by GitHub
parent 4790e4910f
commit f16fff577a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
324 changed files with 28303 additions and 19567 deletions

View file

@ -0,0 +1,5 @@
import { setupWorker } from 'msw/browser'
import { getHandlers } from './handlers'
export const worker = setupWorker(...getHandlers(false))

View file

@ -0,0 +1,144 @@
[
{
"address": ":8080",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "traefik"
},
{
"address": ":8000",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "web"
},
{
"address": ":8443",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "web-mtls"
},
{
"address": ":80",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "web-redirect"
},
{
"address": ":443",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "web-secured"
},
{
"address": ":8100",
"transport": {
"lifeCycle": {
"graceTimeOut": 10000000000
},
"respondingTimeouts": {
"idleTimeout": 180000000000
}
},
"forwardedHeaders": {},
"name": "web-tcp"
},
{
"address": ":8002",
"transport": {
"lifeCycle": {
"requestAcceptGraceTimeout": 42000000000,
"graceTimeOut": 42000000000
},
"respondingTimeouts": {
"readTimeout": 42000000000,
"writeTimeout": 42000000000,
"idleTimeout": 42000000000
}
},
"forwardedHeaders": {},
"name": "web2"
},
{
"address": ":8003",
"transport": {
"lifeCycle": {
"requestAcceptGraceTimeout": 42000000000,
"graceTimeOut": 42000000000
},
"respondingTimeouts": {
"readTimeout": 42000000000,
"writeTimeout": 42000000000,
"idleTimeout": 42000000000
}
},
"forwardedHeaders": {},
"name": "web3"
},
{
"address": ":65535/udp",
"transport": {
"lifeCycle": {
"requestAcceptGraceTimeout": 42000000000,
"graceTimeOut": 42000000000
},
"respondingTimeouts": {
"readTimeout": 42000000000,
"writeTimeout": 42000000000,
"idleTimeout": 42000000000
}
},
"forwardedHeaders": {},
"name": "a-port-with-a-very-long-name"
},
{
"address": ":65535/tcp",
"transport": {
"lifeCycle": {
"requestAcceptGraceTimeout": 42000000000,
"graceTimeOut": 42000000000
},
"respondingTimeouts": {
"readTimeout": 42000000000,
"writeTimeout": 42000000000,
"idleTimeout": 42000000000
}
},
"forwardedHeaders": {},
"name": "supercalifragilisticexpialidocious"
}
]

View file

@ -0,0 +1,418 @@
[
{
"addPrefix": {
"prefix": "/foo"
},
"status": "enabled",
"usedBy": ["web@docker"],
"name": "add-foo@docker",
"type": "addprefix",
"provider": "docker"
},
{
"redirectScheme": {
"scheme": "https"
},
"status": "enabled",
"usedBy": ["server-mtls@docker", "server-redirect@docker", "orphan-router@file"],
"name": "redirect@file",
"type": "redirectscheme",
"provider": "file"
},
{
"chain": {
"middlewares": ["whitelist", "simple-auth"]
},
"status": "enabled",
"name": "secure-chain@file",
"type": "chain",
"provider": "file"
},
{
"basicAuth": {
"usersFile": ".htpasswd",
"removeHeader": true
},
"status": "enabled",
"name": "simple-auth@file",
"type": "basicauth",
"provider": "file"
},
{
"ipWhiteList": {
"sourceRange": ["127.0.0.1/6", "172.8.8.1"],
"ipStrategy": {
"depth": 3,
"excludedIPs": ["172.0.0.1/31"]
}
},
"status": "enabled",
"name": "whitelist@file",
"type": "ipwhitelist",
"provider": "file"
},
{
"addPrefix": {
"prefix": "/path",
"aCustomObject": {
"array of arrays": [[1, 2], [3, 4]],
"array of objects": [{ "some": "value" }, { "another": "value" }],
"array of booleans": [true, false, true],
"array of numbers": [10, 100, 1000],
"array of strings": ["value1", "value2"]
}
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware00@docker",
"provider": "docker",
"type": "addprefix"
},
{
"buffering": {
"maxRequestBodyBytes": 42,
"memRequestBodyBytes": 42,
"maxResponseBodyBytes": 42,
"memResponseBodyBytes": 42,
"retryExpression": "IsNetworkError() && Attempts() < 2",
"oauthIntrospection > clientConfig > url": "https://keycloak.traefiklabs.tech/realms/keycloak-demo/protocol/openid-connect/token/introspect",
"oauthIntrospection > clientConfig > headers > authorization": "Basic UZShXHjj2XcRSL8PZjuVDRqyqJ7ThjaZiSwJMoQeMJ2yHTgRyhAgLmfT4A1PvHGh"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware02@docker",
"provider": "docker",
"type": "buffering"
},
{
"errors": {
"status": ["500-599", "400-405", "300"],
"service": "service@docker",
"query": "/{status}.html"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware07@docker",
"provider": "docker",
"type": "errors"
},
{
"inFlightReq": {
"amount": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": ["10.0.0.1", "11.0.0.1", "12.0.0.1", "13.0.0.1"]
},
"requestHeaderName": "X-Host-IP",
"requestHost": true
}
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware11@docker",
"provider": "docker",
"type": "inflightreq"
},
{
"redirectScheme": {
"scheme": "https",
"port": "80",
"permanent": true
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware15@docker",
"provider": "docker",
"type": "redirectscheme"
},
{
"retry": {
"attempts": 42
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware18@docker",
"provider": "docker",
"type": "retry"
},
{
"basicAuth": {
"users": ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP4HxwgUir3HP4EsggP/QNo0"],
"usersFile": "/etc/foo/my/file/path/.htpasswd",
"realm": "Hello you are here",
"removeHeader": true,
"headerField": "X-WebAuth-User"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware01@docker",
"provider": "docker",
"type": "basicauth"
},
{
"chain": {
"middlewares": [
"middleware01@docker",
"middleware021@docker",
"middleware03@docker",
"middleware06@docker",
"middleware10@docker"
]
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware03@docker",
"provider": "docker",
"type": "chain"
},
{
"compress": {},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware05@docker",
"provider": "docker",
"type": "compress"
},
{
"digestAuth": {
"users": ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"],
"usersFile": "/etc/foo/my/file/path/.htpasswd",
"realm": "Hello you are here",
"removeHeader": true,
"headerField": "X-WebAuth-User"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware06@docker",
"provider": "docker",
"type": "digestauth"
},
{
"forwardAuth": {
"address": "https://authserver.com/auth",
"tls": {
"ca": "path/to/local.crt",
"caOptional": true,
"cert": "path/to/foo.cert",
"key": "path/to/foo.key",
"insecureSkipVerify": true
},
"trustForwardHeader": true,
"authResponseHeaders": ["X-Auth-User", "X-Secret"]
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware08@docker",
"provider": "docker",
"type": "forwardauth"
},
{
"passTLSClientCert": {
"pem": true,
"info": {
"notAfter": true,
"notBefore": true,
"sans": true,
"subject": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
},
"issuer": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
}
}
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware12@docker",
"provider": "docker",
"type": "passtlsclientcert"
},
{
"stripPrefix": {
"prefixes": ["/foobar", "/fiibar"]
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware19@docker",
"provider": "docker",
"type": "stripprefix"
},
{
"stripPrefixRegex": {
"regex": ["^/foo/(.*)", "/b/{regex}/", "/c/{category}/{id:[0-9]+}/"]
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware20@docker",
"provider": "docker",
"type": "stripprefixregex"
},
{
"redirectRegex": {
"regex": "^http://localhost/(.*)",
"replacement": "http://mydomain/${1}",
"permanent": true
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware14@docker",
"provider": "docker",
"type": "redirectregex"
},
{
"replacePathRegex": {
"regex": "^/foo/(.*)",
"replacement": "/bar/$1"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware17@docker",
"provider": "docker",
"type": "replacepathregex"
},
{
"circuitBreaker": {
"expression": "LatencyAtQuantileMS(50.0) > 100"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware04@docker",
"provider": "docker",
"type": "circuitbreaker"
},
{
"headers": {
"customRequestHeaders": {
"X-Script-Name1": "test",
"X-Script-Name2": "test"
},
"customResponseHeaders": {
"X-Script-Name1": "test",
"X-Script-Name2": "test"
},
"accessControlAllowCredentials": true,
"accessControlAllowHeaders": ["origin", "X-Forwarded-For"],
"accessControlAllowMethods": ["GET", "OPTIONS"],
"accessControlAllowOrigin": "origin-list-or-null",
"accessControlExposeHeaders": ["origin", "X-Forwarded-For"],
"accessControlMaxAge": 42,
"addVaryHeader": true,
"allowedHosts": ["foo.com", "bar.com"],
"hostsProxyHeaders": ["X-Forwarded-Host", "X-Foo"],
"sslRedirect": true,
"sslTemporaryRedirect": true,
"sslHost": "ssl.example.com",
"sslProxyHeaders": {
"X-Forwarded-Proto": "https",
"X-Name1": "foobar"
},
"sslForceHost": true,
"stsSeconds": 42,
"stsIncludeSubdomains": true,
"stsPreload": true,
"forceSTSHeader": true,
"frameDeny": true,
"customFrameOptionsValue": "foobar",
"contentTypeNosniff": true,
"browserXssFilter": true,
"customBrowserXSSValue": "1; report=https://example.com/xss-report",
"contentSecurityPolicy": "default-src 'self'",
"publicKey": "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubdomains; report-uri=\"https://www.example.com/hpkp-report\"",
"referrerPolicy": "same-origin",
"featurePolicy": "vibrate 'none';",
"isDevelopment": true
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware09@docker",
"provider": "docker",
"type": "headers"
},
{
"ipWhiteList": {
"sourceRange": ["127.0.0.1/32", "192.168.1.7"],
"ipStrategy": {
"depth": 42,
"excludedIPs": ["10.0.0.1", "11.0.0.1", "12.0.0.1", "13.0.0.1"]
}
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware10@docker",
"provider": "docker",
"type": "ipwhitelist"
},
{
"rateLimit": {
"average": 42,
"burst": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": ["10.0.0.1", "11.0.0.1", "12.0.0.1", "13.0.0.1"]
},
"requestHeaderName": "X_Foo_Host",
"requestHost": true
}
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware13@docker",
"provider": "docker",
"type": "ratelimit"
},
{
"replacePath": {
"path": "/foobar/goo"
},
"error": ["message 1", "message 2"],
"status": "enabled",
"usedBy": ["foo@docker", "bar@file"],
"name": "middleware16@docker",
"provider": "docker",
"type": "replacepath"
},
{
"addPrefix": {
"prefix": "/foo"
},
"status": "enabled",
"usedBy": ["web@docker"],
"name": "whoami-app-hello-tls-jwt-ef36e528ebdc93bc4f2a-service-middleware",
"type": "whoami-app-hello-tls-jwt-ef36e528ebdc93bc4f2a-service-middleware",
"provider": "docker"
}
]

View file

@ -0,0 +1,171 @@
[
{
"service": "jaeger_v2-example-beta1",
"rule": "Host(`jaeger-v2-example-beta1`)",
"status": "enabled",
"name": "jaeger_v2-example-beta1@docker",
"using": [
"web-secured",
"web"
],
"priority": 10,
"provider": "docker"
},
{
"service": "unexistingservice",
"rule": "Path(`somethingreallyunexpectedbutalsoverylongitgetsoutofthecontainermaybe`)",
"error": [
"the service \"unexistingservice@file\" does not exist",
"the service \"unexistingservicewithaveryveryveryveryveryverylongname@file2\" does not exist and the error message is really long"
],
"status": "disabled",
"name": "orphan-router@file",
"middlewares": [
"middleware00@docker",
"middleware01@docker",
"middleware02@docker",
"middleware03@docker",
"middleware04@docker",
"middleware05@docker",
"middleware06@docker",
"middleware07@docker",
"middleware08@docker",
"middleware09@docker",
"middleware10@docker",
"middleware11@docker",
"middleware12@docker",
"middleware13@docker",
"middleware14@docker",
"middleware15@docker",
"middleware16@docker",
"middleware17@docker",
"middleware18@docker",
"middleware19@docker",
"middleware20@docker"
],
"using": [
"web-secured",
"web",
"traefik",
"web2",
"web3"
],
"priority": 30,
"provider": "file"
},
{
"entryPoints": [
"web-mtls"
],
"service": "api3_v2-example-beta1",
"rule": "Host(`server`) \u0026\u0026 Path(`/mtls`)",
"tls": {
"options": "foo@file",
"certResolver": "acme-dns-challenge",
"domains": [
{
"main": "example.com",
"sans": [
"foo.example.com",
"bar.example.com"
]
},
{
"main": "domain.com",
"sans": [
"foo.domain.com",
"bar.domain.com"
]
},
{
"main": "my.domain.com",
"sans": [
"foo.my.domain.com",
"bar.my.domain.com"
]
}
]
},
"status": "enabled",
"priority": 42,
"name": "server-mtls@docker",
"provider": "docker",
"using": [
"web-mtls"
]
},
{
"entryPoints": [
"web-redirect"
],
"middlewares": [
"redirect@file"
],
"service": "api2_v2-example-beta1",
"rule": "Host(`server`)",
"status": "enabled",
"name": "server-redirect@docker",
"using": [
"web-redirect"
],
"priority": 9223372036854776000,
"provider": "docker"
},
{
"entryPoints": [
"web-secured"
],
"service": "api2_v2-example-beta1",
"rule": "Host(`server`)",
"tls": {},
"status": "enabled",
"name": "server-secured@docker",
"using": [
"web-secured"
],
"provider": "docker"
},
{
"service": "traefik_v2-example-beta1",
"rule": "Host(`traefik-v2-example-beta1`)",
"status": "enabled",
"name": "traefik_v2-example-beta1@docker",
"using": [
"web-secured",
"web"
],
"provider": "docker"
},
{
"entryPoints": [
"web"
],
"middlewares": [
"add-foo"
],
"service": "api_v2-example-beta1",
"rule": "Host(`jorge.dockeree.containous.cloud`)",
"status": "enabled",
"name": "web@docker",
"using": [
"web"
],
"provider": "docker"
},
{
"entryPoints": [
"web"
],
"middlewares": [
"whoami-app-hello-tls-jwt-ef36e528ebdc93bc4f2a-service-middleware"
],
"service": "whoami-app-hello-tls-jwt-ef36e528ebdc93bc4f2a-service",
"rule": "Host(`jorge.dockeree.containous.cloud`)",
"status": "enabled",
"name": "whoami-app-hello-tls-jwt-ef36e528ebdc93bc4f2a@kubernetescrd",
"using": [
"web"
],
"provider": "docker"
}
]

View file

@ -0,0 +1,245 @@
[
{
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.12:80"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"server-redirect@docker",
"server-secured@docker"
],
"serverStatus": {
"http://10.0.1.12:80": "UP"
},
"name": "api2_v2-example-beta1@docker",
"type": "loadbalancer",
"provider": "docker"
},
{
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.20:80"
},
{
"url": "http://10.0.1.21:80"
},
{
"url": "http://10.0.1.22:80"
},
{
"url": "http://10.0.1.23:80"
},
{
"url": "http://10.0.1.24:80"
},
{
"url": "http://10.0.1.25:80"
},
{
"url": "http://10.0.1.26:80"
},
{
"url": "http://10.0.1.27:80"
},
{
"url": "http://10.0.1.28:80"
},
{
"url": "http://10.0.1.29:80"
},
{
"url": "http://10.0.1.30:80"
},
{
"url": "http://10.0.1.31:80"
},
{
"url": "http://10.0.1.32:80"
},
{
"url": "http://10.0.1.33:80"
},
{
"url": "http://10.0.1.34:80"
},
{
"url": "http://10.0.1.35:80"
}
],
"passHostHeader": true,
"responseForwarding": {
"flushInterval": "6s"
},
"stickiness": {
"cookieName": "mycoockie",
"secureCookie": true,
"httpOnlyCookie": true
},
"healthCheck": {
"scheme": "https",
"path": "/health",
"port": 80,
"interval": "5s",
"timeout": "10s",
"hostname": "domain.com",
"headers": {
"X-Custom-A": "foobar,gi,ji;ji,ok",
"X-Custom-B": "foobar foobar foobar foobar foobar"
}
}
},
"status": "enabled",
"usedBy": [
"server-mtls@docker"
],
"serverStatus": {
"http://10.0.1.20:80": "UP",
"http://10.0.1.21:80": "UP",
"http://10.0.1.22:80": "UP",
"http://10.0.1.23:80": "UP",
"http://10.0.1.24:80": "UP",
"http://10.0.1.25:80": "UP"
},
"name": "api3_v2-example-beta1@docker",
"type": "loadbalancer",
"provider": "docker"
},
{
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.11:80"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"web@docker"
],
"serverStatus": {
"http://10.0.1.11:80": "UP"
},
"name": "api_v2-example-beta1@docker",
"type": "loadbalancer",
"provider": "docker"
},
{
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.20:5775"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"jaeger_v2-example-beta1@docker"
],
"serverStatus": {
"http://10.0.1.20:5775": "UP"
},
"name": "jaeger_v2-example-beta1@docker",
"type": "loadbalancer",
"provider": "docker"
},
{
"loadBalancer": {
"servers": [
{
"url": "foo"
}
],
"passHostHeader": false
},
"status": "enabled",
"name": "orphan-service@file",
"type": "loadbalancer",
"provider": "file"
},
{
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.10:80"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"traefik_v2-example-beta1@docker"
],
"serverStatus": {
"http://10.0.1.10:80": "UP"
},
"name": "traefik_v2-example-beta1@docker",
"type": "loadbalancer",
"provider": "docker"
},
{
"name": "canary1@docker",
"provider": "docker",
"status": "enabled",
"type": "weighted",
"usedBy": [
"foo@docker"
],
"weighted": {
"sticky": {
"cookie": {
"httpOnly": true,
"name": "chocolat",
"secure": true
}
}
}
},
{
"name": "canary2@docker",
"provider": "docker",
"status": "enabled",
"type": "weighted",
"usedBy": [
"fii@docker"
],
"weighted": {
"sticky": {
"cookie": {}
}
}
},
{
"mirroring": {
"mirrors": [
{
"name": "two@docker",
"percent": 10
},
{
"name": "three@docker",
"percent": 15
},
{
"name": "four@docker",
"percent": 80
}
],
"service": "one@docker"
},
"name": "mirror@docker",
"provider": "docker",
"status": "enabled",
"type": "mirroring",
"usedBy": [
"foo@docker"
]
}
]

View file

@ -0,0 +1,73 @@
{
"http": {
"routers": {
"total": 126,
"warnings": 42,
"errors": 42
},
"services": {
"total": 126,
"warnings": 38,
"errors": 5
},
"middlewares": {
"total": 126,
"warnings": 10,
"errors": 15
}
},
"tcp": {
"routers": {
"total": 126,
"warnings": 20,
"errors": 32
},
"services": {
"total": 126,
"warnings": 8,
"errors": 7
},
"middlewares": {
"total": 126,
"warnings": 23,
"errors": 11
}
},
"udp": {
"routers": {
"total": 0,
"warnings": 0,
"errors": 0
},
"services": {
"total": 0,
"warnings": 0,
"errors": 0
}
},
"features": {
"tracing": "Prometheus",
"metrics": "",
"accessLog": true
},
"providers": [
"Consul",
"ConsulCatalog",
"Docker",
"ECS",
"etcd",
"File",
"Http",
"Hub",
"Internal",
"Kubernetes",
"KubernetesCRD",
"KubernetesGateway",
"KubernetesIngress",
"Nomad",
"Plugin",
"Redis",
"Swarm",
"ZooKeeper"
]
}

View file

@ -0,0 +1,32 @@
[
{
"inFlightConn": {
"amount": 10
},
"status": "enabled",
"usedBy": ["tcp-all@docker"],
"name": "test-inflightconn",
"type": "inflightconn",
"provider": "docker"
},
{
"ipWhiteList": {
"sourceRange": ["127.0.0.1/32", "192.168.1.7"]
},
"status": "enabled",
"usedBy": ["tcp-all@docker"],
"name": "test-ipwhitelist",
"type": "ipwhitelist",
"provider": "docker"
},
{
"ipAllowList": {
"sourceRange": ["127.0.0.1/32", "192.168.1.7"]
},
"status": "enabled",
"usedBy": ["tcp-all@docker"],
"name": "test-ipallowlist",
"type": "ipallowlist",
"provider": "docker"
}
]

View file

@ -0,0 +1,18 @@
[
{
"entryPoints": [
"web-tcp"
],
"service": "tcp-all",
"rule": "HostSNI(`*`)",
"status": "enabled",
"middlewares": ["test-inflightconn", "test-ipwhitelist", "test-ipallowlist"],
"name": "tcp-all@docker",
"using": [
"web-secured",
"web"
],
"priority": 10,
"provider": "docker"
}
]

View file

@ -0,0 +1,19 @@
[
{
"loadBalancer": {
"terminationDelay": 10,
"servers": [
{
"address": "10.0.1.14:8080"
}
]
},
"status": "enabled",
"usedBy": [
"tcp-all@docker"
],
"name": "tcp-all@docker",
"type": "loadbalancer",
"provider": "docker"
}
]

View file

@ -0,0 +1,15 @@
[
{
"entryPoints": [
"udp"
],
"service": "whoami",
"status": "enabled",
"using": [
"udp"
],
"name": "to-whoami-a@file",
"priority": 10,
"provider": "file"
}
]

View file

@ -0,0 +1,52 @@
[
{
"loadBalancer": {
"servers": [
{
"address": "172.17.0.6:8080"
},
{
"address": "172.17.0.4:8080"
}
]
},
"status": "enabled",
"name": "whoami-a@file",
"provider": "file",
"type": "loadbalancer"
},
{
"loadBalancer": {
"servers": [
{
"address": "172.17.0.5:8080"
}
]
},
"status": "enabled",
"name": "whoami-b@file",
"provider": "file",
"type": "loadbalancer"
},
{
"weighted": {
"services": [
{
"name": "whoami-a",
"weight": 3
},
{
"name": "whoami-b",
"weight": 1
}
]
},
"status": "enabled",
"usedBy": [
"to-whoami-a@file"
],
"name": "whoami@file",
"provider": "file",
"type": "weighted"
}
]

View file

@ -0,0 +1,6 @@
{
"Version": "3.4.0",
"Codename": "montdor",
"disableDashboardAd": false,
"startDate": "2025-03-28T14:58:25.8937758+01:00"
}

View file

@ -0,0 +1,23 @@
[
{
"status": "error",
"protocol": "tcp",
"type": "service",
"name": "service-one",
"message": "Error message"
},
{
"status": "warning",
"protocol": "tcp",
"type": "service",
"name": "service-two",
"message": "Warning message"
},
{
"status": "error",
"protocol": "http",
"type": "service",
"name": "service-three",
"message": "Error message"
}
]

View file

@ -0,0 +1,32 @@
import { http, passthrough } from 'msw'
import apiEntrypoints from './data/api-entrypoints.json'
import apiHttpMiddlewares from './data/api-http_middlewares.json'
import apiHttpRouters from './data/api-http_routers.json'
import apiHttpServices from './data/api-http_services.json'
import apiOverview from './data/api-overview.json'
import apiTcpMiddlewares from './data/api-tcp_middlewares.json'
import apiTcpRouters from './data/api-tcp_routers.json'
import apiTcpServices from './data/api-tcp_services.json'
import apiUdpRouters from './data/api-udp_routers.json'
import apiUdpServices from './data/api-udp_services.json'
import apiVersion from './data/api-version.json'
import eeApiErrors from './data/ee-api-errors.json'
import { listHandlers } from './utils'
export const getHandlers = (noDelay: boolean = false) => [
...listHandlers('/api/entrypoints', apiEntrypoints, noDelay, true),
...listHandlers('/api/errors', eeApiErrors, noDelay),
...listHandlers('/api/http/middlewares', apiHttpMiddlewares, noDelay),
...listHandlers('/api/http/routers', apiHttpRouters, noDelay),
...listHandlers('/api/http/services', apiHttpServices, noDelay),
...listHandlers('/api/overview', apiOverview, noDelay),
...listHandlers('/api/tcp/middlewares', apiTcpMiddlewares, noDelay),
...listHandlers('/api/tcp/routers', apiTcpRouters, noDelay),
...listHandlers('/api/tcp/services', apiTcpServices, noDelay),
...listHandlers('/api/udp/routers', apiUdpRouters, noDelay),
...listHandlers('/api/udp/services', apiUdpServices, noDelay),
...listHandlers('/api/version', apiVersion, noDelay),
http.get('*.tsx', () => passthrough()),
http.get('/img/*', () => passthrough()),
]

View file

@ -0,0 +1,5 @@
import { setupServer } from 'msw/node'
import { getHandlers } from './handlers'
export const server = setupServer(...getHandlers(true))

66
webui/src/mocks/utils.ts Normal file
View file

@ -0,0 +1,66 @@
import { chunk, cloneDeep, orderBy } from 'lodash'
import { http, HttpResponse } from 'msw'
const waitAsync = (noDelay = false) => {
if (noDelay) return Promise.resolve()
let delay = Math.random() + 0.5
if (delay > 1) delay = 1
return new Promise((res) => setTimeout(res, delay * 1000))
}
interface DataItem {
name: string
status?: string
}
export const listHandlers = (
route: string,
data: DataItem[] | Record<string, unknown> | null = null,
noDelay: boolean = false,
skipPagination = false,
) => [
http.get(route, async ({ request }) => {
await waitAsync(noDelay)
const url = new URL(request.url)
const direction = (url.searchParams.get('direction') as 'asc' | 'desc' | null) || 'asc'
const search = url.searchParams.get('search')
const sortBy = url.searchParams.get('sortBy') || 'name'
const status = url.searchParams.get('status')
let results = cloneDeep(data)
if (Array.isArray(results)) {
if (search) results = results.filter((x) => x.name.toLowerCase().includes(search.toLowerCase()))
if (status) results = results.filter((x) => x.status === status)
if (!results.length) return HttpResponse.json([], { headers: { 'X-Next-Page': '1' }, status: 200 })
if (sortBy) results = orderBy(results as DataItem[], [sortBy], [direction || 'asc'])
const page = +(url.searchParams.get('page') || 1)
const pageSize = +(url.searchParams.get('per_page') || 10)
const chunks = skipPagination ? [results] : chunk(results, pageSize)
const totalPages = chunks.length
const nextPage = page + 1 <= totalPages ? page + 1 : 1 // 1 means "no more pages".
return HttpResponse.json(chunks[page - 1], { headers: { 'X-Next-Page': nextPage.toString() }, status: 200 })
}
return HttpResponse.json(results, { status: 200 })
}),
http.get(`${route}/:name`, async ({ params }) => {
await waitAsync(noDelay)
if (!Array.isArray(data)) {
return HttpResponse.json({}, { status: 501 })
}
const { name } = params
const res = data.find((x) => x.name === name)
if (!res) {
const parts = route.split('/')
const lastPart = parts[parts.length - 1]
return HttpResponse.json(
{
message: `${lastPart.substring(0, lastPart.length - 1)} not found: ${name}`,
},
{ status: 404 },
)
}
return HttpResponse.json(res, { status: 200 })
}),
]