konduktor-nightly 0.1.0.dev20251128104812__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- konduktor/__init__.py +49 -0
- konduktor/adaptors/__init__.py +0 -0
- konduktor/adaptors/aws.py +221 -0
- konduktor/adaptors/common.py +118 -0
- konduktor/adaptors/gcp.py +126 -0
- konduktor/authentication.py +124 -0
- konduktor/backends/__init__.py +6 -0
- konduktor/backends/backend.py +86 -0
- konduktor/backends/constants.py +21 -0
- konduktor/backends/deployment.py +204 -0
- konduktor/backends/deployment_utils.py +1351 -0
- konduktor/backends/jobset.py +225 -0
- konduktor/backends/jobset_utils.py +726 -0
- konduktor/backends/pod_utils.py +501 -0
- konduktor/check.py +184 -0
- konduktor/cli.py +1945 -0
- konduktor/config.py +420 -0
- konduktor/constants.py +36 -0
- konduktor/controller/__init__.py +0 -0
- konduktor/controller/constants.py +56 -0
- konduktor/controller/launch.py +44 -0
- konduktor/controller/node.py +116 -0
- konduktor/controller/parse.py +111 -0
- konduktor/dashboard/README.md +30 -0
- konduktor/dashboard/backend/main.py +169 -0
- konduktor/dashboard/backend/sockets.py +154 -0
- konduktor/dashboard/frontend/.eslintrc.json +3 -0
- konduktor/dashboard/frontend/.gitignore +36 -0
- konduktor/dashboard/frontend/app/api/jobs/route.js +71 -0
- konduktor/dashboard/frontend/app/api/namespaces/route.js +69 -0
- konduktor/dashboard/frontend/app/components/Grafana.jsx +66 -0
- konduktor/dashboard/frontend/app/components/JobsData.jsx +197 -0
- konduktor/dashboard/frontend/app/components/LogsData.jsx +139 -0
- konduktor/dashboard/frontend/app/components/NavMenu.jsx +39 -0
- konduktor/dashboard/frontend/app/components/NavTabs.jsx +73 -0
- konduktor/dashboard/frontend/app/components/NavTabs2.jsx +30 -0
- konduktor/dashboard/frontend/app/components/SelectBtn.jsx +27 -0
- konduktor/dashboard/frontend/app/components/lib/utils.js +6 -0
- konduktor/dashboard/frontend/app/components/ui/chip-select.jsx +78 -0
- konduktor/dashboard/frontend/app/components/ui/input.jsx +19 -0
- konduktor/dashboard/frontend/app/components/ui/navigation-menu.jsx +104 -0
- konduktor/dashboard/frontend/app/components/ui/select.jsx +120 -0
- konduktor/dashboard/frontend/app/favicon.ico +0 -0
- konduktor/dashboard/frontend/app/globals.css +120 -0
- konduktor/dashboard/frontend/app/jobs/page.js +10 -0
- konduktor/dashboard/frontend/app/layout.js +22 -0
- konduktor/dashboard/frontend/app/logs/page.js +11 -0
- konduktor/dashboard/frontend/app/page.js +12 -0
- konduktor/dashboard/frontend/jsconfig.json +7 -0
- konduktor/dashboard/frontend/next.config.mjs +4 -0
- konduktor/dashboard/frontend/package-lock.json +6687 -0
- konduktor/dashboard/frontend/package.json +37 -0
- konduktor/dashboard/frontend/postcss.config.mjs +8 -0
- konduktor/dashboard/frontend/server.js +64 -0
- konduktor/dashboard/frontend/tailwind.config.js +17 -0
- konduktor/data/__init__.py +9 -0
- konduktor/data/aws/__init__.py +15 -0
- konduktor/data/aws/s3.py +1138 -0
- konduktor/data/constants.py +7 -0
- konduktor/data/data_utils.py +268 -0
- konduktor/data/gcp/__init__.py +19 -0
- konduktor/data/gcp/constants.py +42 -0
- konduktor/data/gcp/gcs.py +994 -0
- konduktor/data/gcp/utils.py +9 -0
- konduktor/data/registry.py +19 -0
- konduktor/data/storage.py +812 -0
- konduktor/data/storage_utils.py +535 -0
- konduktor/execution.py +447 -0
- konduktor/kube_client.py +237 -0
- konduktor/logging.py +111 -0
- konduktor/manifests/aibrix-setup.yaml +430 -0
- konduktor/manifests/apoxy-setup.yaml +184 -0
- konduktor/manifests/apoxy-setup2.yaml +98 -0
- konduktor/manifests/controller_deployment.yaml +69 -0
- konduktor/manifests/dashboard_deployment.yaml +131 -0
- konduktor/manifests/dmesg_daemonset.yaml +57 -0
- konduktor/manifests/pod_cleanup_controller.yaml +129 -0
- konduktor/resource.py +546 -0
- konduktor/serving.py +153 -0
- konduktor/task.py +949 -0
- konduktor/templates/deployment.yaml.j2 +191 -0
- konduktor/templates/jobset.yaml.j2 +43 -0
- konduktor/templates/pod.yaml.j2 +563 -0
- konduktor/usage/__init__.py +0 -0
- konduktor/usage/constants.py +21 -0
- konduktor/utils/__init__.py +0 -0
- konduktor/utils/accelerator_registry.py +17 -0
- konduktor/utils/annotations.py +62 -0
- konduktor/utils/base64_utils.py +95 -0
- konduktor/utils/common_utils.py +426 -0
- konduktor/utils/constants.py +5 -0
- konduktor/utils/env_options.py +55 -0
- konduktor/utils/exceptions.py +234 -0
- konduktor/utils/kubernetes_enums.py +8 -0
- konduktor/utils/kubernetes_utils.py +763 -0
- konduktor/utils/log_utils.py +467 -0
- konduktor/utils/loki_utils.py +102 -0
- konduktor/utils/rich_utils.py +123 -0
- konduktor/utils/schemas.py +625 -0
- konduktor/utils/subprocess_utils.py +273 -0
- konduktor/utils/ux_utils.py +247 -0
- konduktor/utils/validator.py +461 -0
- konduktor_nightly-0.1.0.dev20251128104812.dist-info/LICENSE +91 -0
- konduktor_nightly-0.1.0.dev20251128104812.dist-info/METADATA +98 -0
- konduktor_nightly-0.1.0.dev20251128104812.dist-info/RECORD +107 -0
- konduktor_nightly-0.1.0.dev20251128104812.dist-info/WHEEL +4 -0
- konduktor_nightly-0.1.0.dev20251128104812.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { useState, useRef } from 'react';
|
|
3
|
+
import BarLoader from "react-spinners/BarLoader";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function Grafana() {
|
|
7
|
+
|
|
8
|
+
const [isIframeLoaded, setIsIframeLoaded] = useState(false);
|
|
9
|
+
const [isError, setIsError] = useState(false);
|
|
10
|
+
const iframeRef = useRef(null);
|
|
11
|
+
|
|
12
|
+
const handleLoad = () => {
|
|
13
|
+
setIsIframeLoaded(true);
|
|
14
|
+
setIsError(false);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const handleError = () => {
|
|
18
|
+
setIsError(true);
|
|
19
|
+
setIsIframeLoaded(false);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
{!isIframeLoaded ?
|
|
25
|
+
<div style={{ display: 'flex', justifyContent: 'center', flexDirection: 'column', alignItems: 'center', marginTop: '48px' }}>
|
|
26
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '22px', marginBottom: '24px' }}>Loading Grafana Konduktor Dashboard</p>
|
|
27
|
+
<BarLoader
|
|
28
|
+
height={8}
|
|
29
|
+
width={400}
|
|
30
|
+
aria-label="Loading Spinner"
|
|
31
|
+
/>
|
|
32
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '18px', marginTop: '24px' }}>If stuck loading, check port forwarding for errors</p>
|
|
33
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '12px' }}>kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n prometheus</p>
|
|
34
|
+
</div>
|
|
35
|
+
:
|
|
36
|
+
null
|
|
37
|
+
}
|
|
38
|
+
{isError ?
|
|
39
|
+
<div style={{ display: 'flex', justifyContent: 'center', flexDirection: 'column', alignItems: 'center', marginTop: '48px' }}>
|
|
40
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '22px' }}>Error Loading Grafana Konduktor Dashboard</p>
|
|
41
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '22px', marginTop: '32px' }}>Check port forwarding for errors</p>
|
|
42
|
+
<p style={{ fontFamily: 'Poppins', fontSize: '12px' }}>kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n prometheus</p>
|
|
43
|
+
</div>
|
|
44
|
+
:
|
|
45
|
+
null
|
|
46
|
+
}
|
|
47
|
+
<iframe
|
|
48
|
+
src='http://localhost:3000/dashboards'
|
|
49
|
+
style={{
|
|
50
|
+
width: '100%',
|
|
51
|
+
height: '800px',
|
|
52
|
+
border: 'none',
|
|
53
|
+
visibility: isIframeLoaded ? 'visible' : 'hidden', // Control visibility
|
|
54
|
+
transition: 'visibility 0s, opacity 0.5s linear', // Smooth transition
|
|
55
|
+
opacity: isIframeLoaded ? 1 : 0, // Fade in effect
|
|
56
|
+
}}
|
|
57
|
+
title="Grafana Dashboard"
|
|
58
|
+
onLoad={handleLoad}
|
|
59
|
+
onError={handleError}
|
|
60
|
+
ref={iframeRef}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default Grafana
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react'
|
|
4
|
+
import { DataGrid, GridActionsCellItem } from '@mui/x-data-grid';
|
|
5
|
+
import DeleteIcon from '@mui/icons-material/DeleteOutlined';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function JobsData() {
|
|
9
|
+
|
|
10
|
+
const [data, setData] = useState([])
|
|
11
|
+
|
|
12
|
+
const [paginationModel, setPaginationModel] = useState({
|
|
13
|
+
pageSize: 10,
|
|
14
|
+
page: 0,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const fetchData = async () => {
|
|
18
|
+
try {
|
|
19
|
+
const response = await fetch(`/api/jobs`, {
|
|
20
|
+
method: 'GET',
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json'
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
const data = await response.json();
|
|
26
|
+
setData(data)
|
|
27
|
+
return data
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Error fetching from backend:', error);
|
|
30
|
+
return []
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handleDelete = async (row) => {
|
|
35
|
+
const { name, namespace } = row
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(`/api/jobs`, {
|
|
38
|
+
method: 'DELETE',
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json'
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({ name, namespace })
|
|
43
|
+
})
|
|
44
|
+
const data2 = await response.json()
|
|
45
|
+
|
|
46
|
+
// Optimistically remove the row from the state
|
|
47
|
+
const newData = data.filter((job) => job.name !== name || job.namespace !== namespace);
|
|
48
|
+
setData(newData);
|
|
49
|
+
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error("Delete error:", error)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const updatePriority = async (name, namespace, priority, priority_class_name) => {
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch(`/api/jobs`, {
|
|
58
|
+
method: 'PUT',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': 'application/json'
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({ name, namespace, priority, priority_class_name })
|
|
63
|
+
})
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
return data
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error("Put error:", error);
|
|
68
|
+
return error
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const columns = [
|
|
73
|
+
{
|
|
74
|
+
field: 'name',
|
|
75
|
+
headerName: 'NAME',
|
|
76
|
+
width: 200
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
field: 'namespace',
|
|
80
|
+
headerName: 'NAMESPACE',
|
|
81
|
+
width: 120
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
field: 'priority',
|
|
85
|
+
headerName: 'PRIORITY',
|
|
86
|
+
width: 100,
|
|
87
|
+
type: 'number',
|
|
88
|
+
editable: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
field: 'status',
|
|
92
|
+
headerName: 'STATUS',
|
|
93
|
+
width: 120,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
field: 'active',
|
|
97
|
+
headerName: 'ACTIVE',
|
|
98
|
+
width: 100,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
field: 'created_at',
|
|
102
|
+
headerName: 'CREATED AT',
|
|
103
|
+
width: 160
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
field: 'localQueueName',
|
|
107
|
+
headerName: 'CREATED BY',
|
|
108
|
+
width: 160
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
field: 'order',
|
|
112
|
+
headerName: 'order',
|
|
113
|
+
width: 10,
|
|
114
|
+
type: 'number',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
field: 'actions',
|
|
118
|
+
type: 'actions',
|
|
119
|
+
headerName: 'DELETE',
|
|
120
|
+
width: 70,
|
|
121
|
+
cellClassName: 'actions',
|
|
122
|
+
getActions: (params) => {
|
|
123
|
+
|
|
124
|
+
return [
|
|
125
|
+
<GridActionsCellItem
|
|
126
|
+
icon={<DeleteIcon />}
|
|
127
|
+
key={`delete-${params.row.id}`}
|
|
128
|
+
label="Delete"
|
|
129
|
+
onClick={() => handleDelete(params.row)}
|
|
130
|
+
color="inherit"
|
|
131
|
+
/>,
|
|
132
|
+
];
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const processRowUpdate = async (newRow, oldRow) => {
|
|
138
|
+
const updatedRow = { ...newRow };
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const res = await updatePriority(updatedRow.name, updatedRow.namespace, updatedRow.priority, "")
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error("Fetch error:", error);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
await fetchData()
|
|
147
|
+
|
|
148
|
+
return oldRow
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
fetchData()
|
|
153
|
+
}, [])
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div className='flex w-full h-full flex-col p-8'>
|
|
158
|
+
<DataGrid
|
|
159
|
+
sx={{
|
|
160
|
+
color: 'black',
|
|
161
|
+
fontFamily: 'Poppins',
|
|
162
|
+
bgcolor: 'white',
|
|
163
|
+
border: '2px solid hsl(var(--border))',
|
|
164
|
+
'& .MuiDataGrid-filler': {
|
|
165
|
+
backgroundColor: 'rgb(248 250 252)',
|
|
166
|
+
},
|
|
167
|
+
'& .MuiDataGrid-scrollbar--horizontal': {
|
|
168
|
+
left: 0
|
|
169
|
+
},
|
|
170
|
+
'--DataGrid-containerBackground': 'rgb(248 250 252)',
|
|
171
|
+
}}
|
|
172
|
+
rows={data}
|
|
173
|
+
getRowId={(row) => row.id}
|
|
174
|
+
columns={columns}
|
|
175
|
+
paginationModel={paginationModel}
|
|
176
|
+
onPaginationModelChange={setPaginationModel}
|
|
177
|
+
processRowUpdate={processRowUpdate}
|
|
178
|
+
editMode='row'
|
|
179
|
+
sortModel={[
|
|
180
|
+
{ field: 'order', sort: 'desc' },
|
|
181
|
+
]}
|
|
182
|
+
initialState={{
|
|
183
|
+
columns: {
|
|
184
|
+
columnVisibilityModel: {
|
|
185
|
+
order: false,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
}}
|
|
189
|
+
checkboxSelection
|
|
190
|
+
disableRowSelectionOnClick
|
|
191
|
+
pageSizeOptions={[5, 10, 20, 50]}
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export default JobsData
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState, useRef } from 'react';
|
|
4
|
+
import { io } from 'socket.io-client';
|
|
5
|
+
import { Input } from "./ui/input";
|
|
6
|
+
import ChipSelect from "./ui/chip-select";
|
|
7
|
+
import { FaSearch } from 'react-icons/fa';
|
|
8
|
+
|
|
9
|
+
function LogsData() {
|
|
10
|
+
|
|
11
|
+
const [logsData, setLogsData] = useState([]);
|
|
12
|
+
const [namespaces, setNamespaces] = useState([]);
|
|
13
|
+
const [selectedNamespaces, setSelectedNamespaces] = useState(['default']);
|
|
14
|
+
const [isAtBottom, setIsAtBottom] = useState(true); // Track if user is at the bottom
|
|
15
|
+
const logContainerRef = useRef(null);
|
|
16
|
+
const [searchQuery, setSearchQuery] = useState('')
|
|
17
|
+
|
|
18
|
+
const socketRef = useRef(null);
|
|
19
|
+
|
|
20
|
+
const fetchData = async () => {
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`/api/namespaces`, {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json'
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
setNamespaces(data)
|
|
30
|
+
return
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Error fetching from backend:', error);
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check if user is at the bottom of the log container
|
|
38
|
+
const handleScroll = () => {
|
|
39
|
+
if (logContainerRef.current) {
|
|
40
|
+
const { scrollTop, scrollHeight, clientHeight } = logContainerRef.current
|
|
41
|
+
const isUserAtBottom = scrollTop + clientHeight >= scrollHeight
|
|
42
|
+
setIsAtBottom(isUserAtBottom)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleSearchChange = (event) => {
|
|
47
|
+
setSearchQuery(event.target.value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const filteredLogs = logsData.filter(log =>
|
|
51
|
+
log.log.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
52
|
+
log.timestamp.toLowerCase().includes(searchQuery.toLowerCase())
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
fetchData()
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
// Create and store the socket instance only once
|
|
61
|
+
if (!socketRef.current) {
|
|
62
|
+
socketRef.current = io('http://localhost:5173'); // Connect to Next.js server
|
|
63
|
+
|
|
64
|
+
socketRef.current.on('connect', () => {
|
|
65
|
+
console.log('Connected to Next.js Socket.IO server');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
socketRef.current.on('log_data', (data) => {
|
|
69
|
+
setLogsData((prevLogs) => [...prevLogs, ...data]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
socketRef.current.on('disconnect', () => {
|
|
73
|
+
console.log('Disconnected from Next.js Socket.IO server');
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Clean up and disconnect the socket when the component unmounts
|
|
78
|
+
return () => {
|
|
79
|
+
if (socketRef.current) {
|
|
80
|
+
socketRef.current.disconnect();
|
|
81
|
+
socketRef.current = null;
|
|
82
|
+
console.log('Socket disconnected on component unmount');
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
// Emit selected namespaces whenever they change
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (socketRef.current) {
|
|
90
|
+
socketRef.current.emit('update_namespaces', selectedNamespaces);
|
|
91
|
+
}
|
|
92
|
+
}, [selectedNamespaces]);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (isAtBottom && logContainerRef.current) {
|
|
96
|
+
logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
|
|
97
|
+
}
|
|
98
|
+
}, [logsData, isAtBottom]);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className='flex w-full h-full flex-col px-8'>
|
|
102
|
+
<div className='flex w-full my-4 py-4 justify-center gap-2'>
|
|
103
|
+
<div className="relative w-full md:w-1/4 min-w-[250px] mx-8 md:mx-0 flex justify-center items-center">
|
|
104
|
+
<span className="absolute left-3 text-gray-500">
|
|
105
|
+
<FaSearch />
|
|
106
|
+
</span>
|
|
107
|
+
<Input
|
|
108
|
+
className="pl-10 w-full"
|
|
109
|
+
placeholder="Search"
|
|
110
|
+
value={searchQuery}
|
|
111
|
+
onChange={handleSearchChange}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
<ChipSelect namespaces={namespaces} selectedNamespaces={selectedNamespaces} setSelectedNamespaces={setSelectedNamespaces} />
|
|
115
|
+
</div>
|
|
116
|
+
<div className='flex w-full bg-white h-full py-2 justify-center bg-slate-50 rounded-md border-2 max-h-[450px] box-border'>
|
|
117
|
+
<div ref={logContainerRef} onScroll={handleScroll} className='w-full bg-white flex flex-col overflow-y-scroll box-border'>
|
|
118
|
+
{filteredLogs.map((data, index) => (
|
|
119
|
+
<div key={index} className='py-1 px-2 flex flex-row box-border'>
|
|
120
|
+
<div className='w-36 min-w-36 max-w-36'>
|
|
121
|
+
<p className='text-gray-500 text-[12px]'>{data.timestamp}</p>
|
|
122
|
+
</div>
|
|
123
|
+
<div className='flex justify-center mr-4'>
|
|
124
|
+
<div className='bg-[rgb(0,0,0,0.08)] rounded-[4px] px-2 h-[18px]'>
|
|
125
|
+
<p className='text-gray-900 text-[12px]'>{data.namespace}</p>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div>
|
|
129
|
+
<p className="text-gray-900 text-[12px] leading-4">{data.log}</p>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
))}
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default LogsData
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {
|
|
3
|
+
NavigationMenu,
|
|
4
|
+
NavigationMenuContent,
|
|
5
|
+
NavigationMenuIndicator,
|
|
6
|
+
NavigationMenuItem,
|
|
7
|
+
NavigationMenuLink,
|
|
8
|
+
NavigationMenuList,
|
|
9
|
+
NavigationMenuTrigger,
|
|
10
|
+
NavigationMenuViewport,
|
|
11
|
+
} from "./ui/navigation-menu"
|
|
12
|
+
import Box from '@mui/material/Box';
|
|
13
|
+
|
|
14
|
+
function NavMenu() {
|
|
15
|
+
return (
|
|
16
|
+
<NavigationMenu>
|
|
17
|
+
<NavigationMenuList>
|
|
18
|
+
<NavigationMenuItem>
|
|
19
|
+
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
|
|
20
|
+
<NavigationMenuContent>
|
|
21
|
+
<Box sx={{ width: '600px', height: '300px', display: 'flex', justifyContent: 'center', p: '16px' }}>
|
|
22
|
+
<NavigationMenuLink>Link</NavigationMenuLink>
|
|
23
|
+
</Box>
|
|
24
|
+
</NavigationMenuContent>
|
|
25
|
+
</NavigationMenuItem>
|
|
26
|
+
<NavigationMenuItem>
|
|
27
|
+
<NavigationMenuTrigger>Item Two</NavigationMenuTrigger>
|
|
28
|
+
<NavigationMenuContent>
|
|
29
|
+
<Box sx={{ width: '300px', height: '300px', display: 'flex', justifyContent: 'center' }}>
|
|
30
|
+
<NavigationMenuLink>Link</NavigationMenuLink>
|
|
31
|
+
</Box>
|
|
32
|
+
</NavigationMenuContent>
|
|
33
|
+
</NavigationMenuItem>
|
|
34
|
+
</NavigationMenuList>
|
|
35
|
+
</NavigationMenu>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default NavMenu
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
5
|
+
import Link from 'next/link'; // Import Link from Next.js for client-side navigation
|
|
6
|
+
import Box from '@mui/material/Box';
|
|
7
|
+
import Tabs from '@mui/material/Tabs';
|
|
8
|
+
import Tab from '@mui/material/Tab';
|
|
9
|
+
|
|
10
|
+
function NavTabs() {
|
|
11
|
+
const pathname = usePathname();
|
|
12
|
+
const [tabValue, setTabValue] = useState(undefined);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!pathname) return;
|
|
16
|
+
|
|
17
|
+
if (pathname === '/') {
|
|
18
|
+
setTabValue(0);
|
|
19
|
+
} else if (pathname === '/logs') {
|
|
20
|
+
setTabValue(1);
|
|
21
|
+
} else if (pathname === '/jobs') {
|
|
22
|
+
setTabValue(2);
|
|
23
|
+
}
|
|
24
|
+
}, [pathname]);
|
|
25
|
+
|
|
26
|
+
const handleTabChange = (event, newValue) => {
|
|
27
|
+
setTabValue(newValue);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Box sx={{ width: '100%' }}>
|
|
32
|
+
{tabValue !== undefined ? (
|
|
33
|
+
<Tabs
|
|
34
|
+
value={tabValue}
|
|
35
|
+
onChange={handleTabChange}
|
|
36
|
+
sx={{
|
|
37
|
+
borderBottom: '2px solid rgb(229 231 235) !important',
|
|
38
|
+
'& .MuiTabs-indicator': {
|
|
39
|
+
backgroundColor: 'rgb(75 85 99) !important',
|
|
40
|
+
},
|
|
41
|
+
'& .MuiTab-root': {
|
|
42
|
+
color: 'rgb(107 114 128) !important',
|
|
43
|
+
},
|
|
44
|
+
'& .Mui-selected': {
|
|
45
|
+
color: 'black !important',
|
|
46
|
+
},
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<Tab
|
|
50
|
+
component={Link}
|
|
51
|
+
href="/"
|
|
52
|
+
label="Metrics"
|
|
53
|
+
sx={{ fontWeight: 'bold', fontFamily: 'Poppins' }}
|
|
54
|
+
/>
|
|
55
|
+
<Tab
|
|
56
|
+
component={Link}
|
|
57
|
+
href="/logs"
|
|
58
|
+
label="Logs"
|
|
59
|
+
sx={{ fontWeight: 'bold', fontFamily: 'Poppins' }}
|
|
60
|
+
/>
|
|
61
|
+
<Tab
|
|
62
|
+
component={Link}
|
|
63
|
+
href="/jobs"
|
|
64
|
+
label="Jobs"
|
|
65
|
+
sx={{ fontWeight: 'bold', fontFamily: 'Poppins' }}
|
|
66
|
+
/>
|
|
67
|
+
</Tabs>
|
|
68
|
+
) : null}
|
|
69
|
+
</Box>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default NavTabs;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import Tabs from '@mui/material/Tabs';
|
|
4
|
+
import Tab from '@mui/material/Tab';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function NavTabs2(props) {
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<Box sx={{ width: '100%' }}>
|
|
11
|
+
<Tabs value={props.tab} onChange={props.handleTabChange} sx={{
|
|
12
|
+
borderBottom: '2px solid rgb(229 231 235) !important',
|
|
13
|
+
'& .MuiTabs-indicator': {
|
|
14
|
+
backgroundColor: 'rgb(75 85 99) !important', // Change the indicator color
|
|
15
|
+
},
|
|
16
|
+
'& .MuiTab-root': {
|
|
17
|
+
color: 'rgb(107 114 128) !important', // Change the default text color
|
|
18
|
+
},
|
|
19
|
+
'& .Mui-selected': {
|
|
20
|
+
color: 'black !important',
|
|
21
|
+
},
|
|
22
|
+
}} >
|
|
23
|
+
<Tab sx={{ fontFamily: 'Poppins', }} label="Application Logs" />
|
|
24
|
+
{/*<Tab sx={{ fontFamily: 'Poppins', }} label="Workspace Events" />*/}
|
|
25
|
+
</Tabs>
|
|
26
|
+
</Box>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default NavTabs2
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Select,
|
|
5
|
+
SelectContent,
|
|
6
|
+
SelectItem,
|
|
7
|
+
SelectTrigger,
|
|
8
|
+
SelectValue,
|
|
9
|
+
} from "./ui/select"
|
|
10
|
+
|
|
11
|
+
function SelectBtn() {
|
|
12
|
+
return (
|
|
13
|
+
<div className="flex flex-col space-y-1.5">
|
|
14
|
+
<Select>
|
|
15
|
+
<SelectTrigger id="framework" className='tracking-wide mr-2'>
|
|
16
|
+
<SelectValue placeholder="View In Grafana" />
|
|
17
|
+
</SelectTrigger>
|
|
18
|
+
<SelectContent position="popper">
|
|
19
|
+
<SelectItem value="1">Core Dashboard</SelectItem>
|
|
20
|
+
<SelectItem value="2">Ray Data Dashboard</SelectItem>
|
|
21
|
+
</SelectContent>
|
|
22
|
+
</Select>
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default SelectBtn
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import OutlinedInput from '@mui/material/OutlinedInput';
|
|
4
|
+
import InputLabel from '@mui/material/InputLabel';
|
|
5
|
+
import MenuItem from '@mui/material/MenuItem';
|
|
6
|
+
import FormControl from '@mui/material/FormControl';
|
|
7
|
+
import Select from '@mui/material/Select';
|
|
8
|
+
import Chip from '@mui/material/Chip';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export default function ChipSelect(props) {
|
|
12
|
+
|
|
13
|
+
const handleChange = (event) => {
|
|
14
|
+
const {
|
|
15
|
+
target: { value },
|
|
16
|
+
} = event;
|
|
17
|
+
props.setSelectedNamespaces(
|
|
18
|
+
// On autofill we get a stringified value.
|
|
19
|
+
typeof value === 'string' ? value.split(',') : value,
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<FormControl className='flex w-3/4' >
|
|
25
|
+
<InputLabel id="demo-multiple-chip-label" sx={{
|
|
26
|
+
lineHeight: 1.2,
|
|
27
|
+
fontSize: '14px',
|
|
28
|
+
color: 'gray',
|
|
29
|
+
"&.Mui-focused": {
|
|
30
|
+
color: 'gray'
|
|
31
|
+
}
|
|
32
|
+
}} >
|
|
33
|
+
Namespace(s)
|
|
34
|
+
</InputLabel>
|
|
35
|
+
<Select
|
|
36
|
+
labelId="demo-multiple-chip-label"
|
|
37
|
+
id="demo-multiple-chip"
|
|
38
|
+
multiple
|
|
39
|
+
value={props.selectedNamespaces}
|
|
40
|
+
onChange={handleChange}
|
|
41
|
+
input={<OutlinedInput id="select-multiple-chip" label="Namespace(s)" />}
|
|
42
|
+
sx={{
|
|
43
|
+
minHeight: '48px',
|
|
44
|
+
borderRadius: '0.375rem',
|
|
45
|
+
'.MuiSelect-select': {
|
|
46
|
+
height: 'auto',
|
|
47
|
+
p: '8px',
|
|
48
|
+
},
|
|
49
|
+
'.MuiOutlinedInput-notchedOutline': {
|
|
50
|
+
borderColor: '#e5e7eb',
|
|
51
|
+
},
|
|
52
|
+
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
|
53
|
+
borderColor: '#e5e7eb',
|
|
54
|
+
},
|
|
55
|
+
'&:hover .MuiOutlinedInput-notchedOutline': {
|
|
56
|
+
borderColor: '#e5e7eb',
|
|
57
|
+
},
|
|
58
|
+
}}
|
|
59
|
+
renderValue={(selected) => (
|
|
60
|
+
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.3 }}>
|
|
61
|
+
{selected.map((value) => (
|
|
62
|
+
<Chip sx={{ fontSize: '12px', maxHeight: '24px', borderRadius: '4px' }} key={value} label={value} />
|
|
63
|
+
))}
|
|
64
|
+
</Box>
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
{props.namespaces.map((choice) => (
|
|
68
|
+
<MenuItem
|
|
69
|
+
key={choice}
|
|
70
|
+
value={choice}
|
|
71
|
+
>
|
|
72
|
+
{choice}
|
|
73
|
+
</MenuItem>
|
|
74
|
+
))}
|
|
75
|
+
</Select>
|
|
76
|
+
</FormControl>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils"
|
|
4
|
+
|
|
5
|
+
const Input = React.forwardRef(({ className, type, ...props }, ref) => {
|
|
6
|
+
return (
|
|
7
|
+
(<input
|
|
8
|
+
type={type}
|
|
9
|
+
className={cn(
|
|
10
|
+
"flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
11
|
+
className
|
|
12
|
+
)}
|
|
13
|
+
ref={ref}
|
|
14
|
+
{...props} />)
|
|
15
|
+
);
|
|
16
|
+
})
|
|
17
|
+
Input.displayName = "Input"
|
|
18
|
+
|
|
19
|
+
export { Input }
|