Skip to content
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

feat(dashboard): allow specifying API endpoint for development #14361

Merged
merged 3 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions dashboard/mock-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
*/

const express = require("express")
const cors = require("cors")

const app = express()
app.use(cors())

app.listen(32333, () => {
console.log("Server running on port 32333")
})
Expand Down
10 changes: 0 additions & 10 deletions dashboard/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@
*/
const nextConfig = {
trailingSlash: true,

rewrites: () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for rewrites now as we directly send requests to the mock server with CORS allowed.

return [
{
source: "/api/:path*",
// To test with a RisingWave Meta node, use "http://127.0.0.1:5691/api/:path*"
destination: "http://localhost:32333/:path*",
},
]
},
}

module.exports = nextConfig
43 changes: 43 additions & 0 deletions dashboard/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@monaco-editor/react": "^4.4.6",
"@types/d3": "^7.4.0",
"@types/lodash": "^4.14.184",
"@uidotdev/usehooks": "^2.4.1",
"base64url": "^3.0.1",
"bootstrap-icons": "^1.9.1",
"d3": "^7.6.1",
Expand Down Expand Up @@ -48,6 +49,7 @@
"@types/node": "^18.7.14",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.52.0",
"cors": "^2.8.5",
"eslint": "^8.45.0",
"eslint-config-next": "13.4.12",
"eslint-config-prettier": "^8.8.0",
Expand Down
28 changes: 27 additions & 1 deletion dashboard/pages/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,34 @@
*
*/

const PROD_API_ENDPOINT = "/api"
const MOCK_API_ENDPOINT = "http://localhost:32333"
const EXTERNAL_META_NODE_API_ENDPOINT = "http://localhost:5691/api"

export const PREDEFINED_API_ENDPOINTS = [
PROD_API_ENDPOINT,
MOCK_API_ENDPOINT,
EXTERNAL_META_NODE_API_ENDPOINT,
]

export const DEFAULT_API_ENDPOINT: string =
process.env.NODE_ENV === "production" ? PROD_API_ENDPOINT : MOCK_API_ENDPOINT
Comment on lines +28 to +29
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default we still use the mock_server for development and /api for production. Developers may set it to http://localhost:5691/api so that they can develop dashboard with a real local cluster.


export const API_ENDPOINT_KEY = "risingwave.dashboard.api.endpoint"

class Api {
async get(url: string) {
urlFor(path: string) {
let apiEndpoint: string = (
JSON.parse(localStorage.getItem(API_ENDPOINT_KEY) || "null") ||
DEFAULT_API_ENDPOINT
).replace(/\/+$/, "") // remove trailing slashes

return `${apiEndpoint}${path}`
}

async get(path: string) {
const url = this.urlFor(path)

try {
const res = await fetch(url)
const data = await res.json()
Expand Down
6 changes: 3 additions & 3 deletions dashboard/pages/api/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ import { WorkerNode } from "../../proto/gen/common"
import api from "./api"

export async function getClusterMetrics() {
const res = await api.get("/api/metrics/cluster")
const res = await api.get("/metrics/cluster")
return res
}

export async function getClusterInfoFrontend() {
const res: WorkerNode[] = (await api.get("/api/clusters/1")).map(
const res: WorkerNode[] = (await api.get("/clusters/1")).map(
WorkerNode.fromJSON
)
return res
}

export async function getClusterInfoComputeNode() {
const res: WorkerNode[] = (await api.get("/api/clusters/2")).map(
const res: WorkerNode[] = (await api.get("/clusters/2")).map(
WorkerNode.fromJSON
)
return res
Expand Down
2 changes: 1 addition & 1 deletion dashboard/pages/api/metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { MetricsSample } from "../../components/metrics"
import api from "./api"

export async function getActorBackPressures() {
const res = await api.get("/api/metrics/actor/back_pressures")
const res = await api.get("/metrics/actor/back_pressures")
return res
}

Expand Down
14 changes: 6 additions & 8 deletions dashboard/pages/api/streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import { ColumnCatalog, Field } from "../../proto/gen/plan_common"
import api from "./api"

export async function getActors(): Promise<ActorLocation[]> {
return (await api.get("/api/actors")).map(ActorLocation.fromJSON)
return (await api.get("/actors")).map(ActorLocation.fromJSON)
}

export async function getFragments(): Promise<TableFragments[]> {
let fragmentList: TableFragments[] = (await api.get("/api/fragments2")).map(
let fragmentList: TableFragments[] = (await api.get("/fragments2")).map(
TableFragments.fromJSON
)
fragmentList = sortBy(fragmentList, (x) => x.tableId)
Expand Down Expand Up @@ -75,7 +75,7 @@ export async function getRelations() {
async function getTableCatalogsInner(
path: "tables" | "materialized_views" | "indexes" | "internal_tables"
) {
let list: Table[] = (await api.get(`/api/${path}`)).map(Table.fromJSON)
let list: Table[] = (await api.get(`/${path}`)).map(Table.fromJSON)
list = sortBy(list, (x) => x.id)
return list
}
Expand All @@ -97,21 +97,19 @@ export async function getInternalTables() {
}

export async function getSinks() {
let sinkList: Sink[] = (await api.get("/api/sinks")).map(Sink.fromJSON)
let sinkList: Sink[] = (await api.get("/sinks")).map(Sink.fromJSON)
sinkList = sortBy(sinkList, (x) => x.id)
return sinkList
}

export async function getSources() {
let sourceList: Source[] = (await api.get("/api/sources")).map(
Source.fromJSON
)
let sourceList: Source[] = (await api.get("/sources")).map(Source.fromJSON)
sourceList = sortBy(sourceList, (x) => x.id)
return sourceList
}

export async function getViews() {
let views: View[] = (await api.get("/api/views")).map(View.fromJSON)
let views: View[] = (await api.get("/views")).map(View.fromJSON)
views = sortBy(views, (x) => x.id)
return views
}
2 changes: 1 addition & 1 deletion dashboard/pages/await_tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default function AwaitTreeDump() {

try {
const response: StackTraceResponse = StackTraceResponse.fromJSON(
await api.get(`/api/monitor/await_tree/${computeNodeId}`)
await api.get(`/monitor/await_tree/${computeNodeId}`)
)

const actorTraces = _(response.actorTraces)
Expand Down
6 changes: 3 additions & 3 deletions dashboard/pages/heap_profiling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default function HeapProfiling() {
try {
let list: ListHeapProfilingResponse =
ListHeapProfilingResponse.fromJSON(
await api.get(`/api/monitor/list_heap_profile/${computeNodeId}`)
await api.get(`/monitor/list_heap_profile/${computeNodeId}`)
)
setProfileList(list)
} catch (e: any) {
Expand Down Expand Up @@ -119,7 +119,7 @@ export default function HeapProfiling() {
}, [selectedProfileList])

async function dumpProfile() {
api.get(`/api/monitor/dump_heap_profile/${computeNodeId}`)
api.get(`/monitor/dump_heap_profile/${computeNodeId}`)
getProfileList(computeNodes, computeNodeId)
}

Expand Down Expand Up @@ -149,7 +149,7 @@ export default function HeapProfiling() {
try {
let analyzeFilePathBase64 = base64url(analyzeFilePath)
let resObj = await fetch(
`/api/monitor/analyze/${computeNodeId}/${analyzeFilePathBase64}`
`/monitor/analyze/${computeNodeId}/${analyzeFilePathBase64}`
).then(async (res) => ({
filename: res.headers.get("content-disposition"),
blob: await res.blob(),
Expand Down
36 changes: 27 additions & 9 deletions dashboard/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,28 @@
*/

import { Box, FormControl, FormLabel, Input, VStack } from "@chakra-ui/react"
import { useIsClient, useLocalStorage } from "@uidotdev/usehooks"
import Head from "next/head"
import { Fragment } from "react"
import Title from "../components/Title"
import {
API_ENDPOINT_KEY,
DEFAULT_API_ENDPOINT,
PREDEFINED_API_ENDPOINTS,
} from "./api/api"

export default function Settings() {
const isClient = useIsClient()
return isClient && <ClientSettings />
}

// Local storage is only available on the client side.
function ClientSettings() {
const [apiEndpoint, saveApiEndpoint] = useLocalStorage(
API_ENDPOINT_KEY,
DEFAULT_API_ENDPOINT
)
Comment on lines +36 to +39
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint will be stored in the local storage of the browser.


return (
<Fragment>
<Head>
Expand All @@ -31,15 +48,16 @@ export default function Settings() {
<VStack spacing={4} w="full">
<FormControl>
<FormLabel>RisingWave Meta Node HTTP API</FormLabel>
<Input value="/api" />
</FormControl>
<FormControl>
<FormLabel>Grafana HTTP API</FormLabel>
<Input value="/api" />
</FormControl>
<FormControl>
<FormLabel>Prometheus HTTP API</FormLabel>
<Input value="/api" />
<Input
value={apiEndpoint}
onChange={(event) => saveApiEndpoint(event.target.value)}
list="predefined"
/>
<datalist id="predefined">
{PREDEFINED_API_ENDPOINTS.map((endpoint) => (
<option key={endpoint} value={endpoint} />
))}
</datalist>
</FormControl>
</VStack>
</Box>
Expand Down
Loading