Skip to content

Commit c93fa9e

Browse files
committed
docker working for frontend dev
1 parent 77a70fd commit c93fa9e

File tree

5 files changed

+134
-1
lines changed

5 files changed

+134
-1
lines changed

docker-compose.dev.yml

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ services:
5454
build:
5555
context: ./frontend
5656
dockerfile: Dockerfile.dev
57+
volumes:
58+
- ./frontend/src:/frontend/src
5759

5860
caddy:
5961
image: caddy:2.6.1

frontend/.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

frontend/Dockerfile.dev

+2
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ COPY . .
1111

1212
RUN pnpm i
1313

14+
VOLUME /frontend/src
15+
1416
CMD ["pnpm", "vite", "--port", "3000", "--host"]

frontend/src/Layout.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Overview from './pages/Overview/Overview'
99
import Clusters from './pages/Clusters/Clusters'
1010
import Backups from './pages/Backups/Backups'
1111
import ScheduledBackups from './pages/Backups/ScheduledBackups'
12+
import Replication from './pages/Replication/Replication'
1213
import Errors from './pages/Errors/Errors'
1314
import { Switch, Route, useHistory } from 'react-router-dom'
1415

@@ -53,6 +54,7 @@ const items: MenuItem[] = [
5354
},
5455
{ key: 'query_performance', label: 'Query performance', icon: <ClockCircleOutlined /> },
5556
{ key: 'running_queries', label: 'Running queries', icon: <DashboardOutlined /> },
57+
{ key: 'replication', label: 'Replication', icon: <DashboardOutlined /> },
5658
{ key: 'schema', label: 'Schema stats', icon: <HddOutlined /> },
5759
{ key: 'disk_usage', label: 'Disk usage', icon: <ApartmentOutlined /> },
5860
{ key: 'logs', label: 'Logs', icon: <BarsOutlined /> },
@@ -122,9 +124,9 @@ export default function AppLayout(): JSX.Element {
122124
<Route exact path="/query_performance" component={SlowQueries}></Route>
123125
<Route exact path="/schema" component={Schema}></Route>
124126
<Route exact path="/schema/:table" component={SchemaTable}></Route>
125-
126127
<Route exact path="/query_performance/:query_hash" component={QueryDetail}></Route>
127128
<Route exact path="/operations" component={Operations}></Route>
129+
<Route exact path="/replication" component={Replication}></Route>
128130
<Route exact path="/running_queries" component={RunningQueries}></Route>
129131
<Route exact path="/logs" component={Logs}></Route>
130132
<Route exact path="/errors" component={Errors}></Route>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { Table, Button, notification, Typography, Tooltip, Spin } from 'antd'
2+
import { usePollingEffect } from '../../utils/usePollingEffect'
3+
import React, { useState } from 'react'
4+
import { ColumnType } from 'antd/es/table'
5+
6+
const { Paragraph } = Typography
7+
8+
interface RunningQueryData {
9+
query: string
10+
read_rows: number
11+
read_rows_readable: string
12+
query_id: string
13+
total_rows_approx: number
14+
total_rows_approx_readable: string
15+
elapsed: number
16+
memory_usage: string
17+
}
18+
19+
function KillQueryButton({ queryId }: any) {
20+
const [isLoading, setIsLoading] = useState(false)
21+
const [isKilled, setIsKilled] = useState(false)
22+
23+
const killQuery = async () => {
24+
setIsLoading(true)
25+
try {
26+
const res = await fetch(`/api/analyze/${queryId}/kill_query`, {
27+
method: 'POST',
28+
headers: {
29+
'Content-Type': 'application/x-www-form-urlencoded',
30+
},
31+
body: new URLSearchParams({
32+
query_id: queryId,
33+
}),
34+
})
35+
setIsKilled(true)
36+
setIsLoading(false)
37+
return await res.json()
38+
} catch (err) {
39+
setIsLoading(false)
40+
notification.error({
41+
message: 'Killing query failed',
42+
})
43+
}
44+
}
45+
return (
46+
<>
47+
{isKilled ? (
48+
<Button disabled>Query killed</Button>
49+
) : (
50+
<Button danger onClick={killQuery} loading={isLoading}>
51+
Kill query
52+
</Button>
53+
)}
54+
</>
55+
)
56+
}
57+
58+
export default function Replication() {
59+
const [runningQueries, setRunningQueries] = useState([])
60+
const [loadingRunningQueries, setLoadingRunningQueries] = useState(false)
61+
62+
const columns: ColumnType<RunningQueryData>[] = [
63+
{
64+
title: 'Query',
65+
dataIndex: 'normalized_query',
66+
key: 'query',
67+
render: (_: any, item) => {
68+
let index = 0
69+
return (
70+
<Paragraph
71+
style={{ maxWidth: '100%', fontFamily: 'monospace' }}
72+
ellipsis={{
73+
rows: 2,
74+
expandable: true,
75+
}}
76+
>
77+
{item.query.replace(/(\?)/g, () => {
78+
index = index + 1
79+
return '$' + index
80+
})}
81+
</Paragraph>
82+
)
83+
},
84+
},
85+
{ title: 'User', dataIndex: 'user' },
86+
{ title: 'Elapsed time', dataIndex: 'elapsed' },
87+
{
88+
title: 'Rows read',
89+
dataIndex: 'read_rows',
90+
render: (_: any, item) => (
91+
<Tooltip title={`~${item.read_rows}/${item.total_rows_approx}`}>
92+
~{item.read_rows_readable}/{item.total_rows_approx_readable}
93+
</Tooltip>
94+
),
95+
},
96+
{ title: 'Memory Usage', dataIndex: 'memory_usage' },
97+
{
98+
title: 'Actions',
99+
render: (_: any, item) => <KillQueryButton queryId={item.query_id} />,
100+
},
101+
]
102+
103+
usePollingEffect(
104+
async () => {
105+
setLoadingRunningQueries(true)
106+
const res = await fetch('/api/analyze/running_queries')
107+
const resJson = await res.json()
108+
setRunningQueries(resJson)
109+
setLoadingRunningQueries(false)
110+
},
111+
[],
112+
{ interval: 5000 }
113+
)
114+
115+
return (
116+
<>
117+
<h1 style={{ textAlign: 'left' }}>Running queries {loadingRunningQueries ? <Spin /> : null}</h1>
118+
<br />
119+
<Table
120+
columns={columns}
121+
dataSource={runningQueries}
122+
loading={runningQueries.length == 0 && loadingRunningQueries}
123+
/>
124+
</>
125+
)
126+
}

0 commit comments

Comments
 (0)