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.
Files changed (107) hide show
  1. konduktor/__init__.py +49 -0
  2. konduktor/adaptors/__init__.py +0 -0
  3. konduktor/adaptors/aws.py +221 -0
  4. konduktor/adaptors/common.py +118 -0
  5. konduktor/adaptors/gcp.py +126 -0
  6. konduktor/authentication.py +124 -0
  7. konduktor/backends/__init__.py +6 -0
  8. konduktor/backends/backend.py +86 -0
  9. konduktor/backends/constants.py +21 -0
  10. konduktor/backends/deployment.py +204 -0
  11. konduktor/backends/deployment_utils.py +1351 -0
  12. konduktor/backends/jobset.py +225 -0
  13. konduktor/backends/jobset_utils.py +726 -0
  14. konduktor/backends/pod_utils.py +501 -0
  15. konduktor/check.py +184 -0
  16. konduktor/cli.py +1945 -0
  17. konduktor/config.py +420 -0
  18. konduktor/constants.py +36 -0
  19. konduktor/controller/__init__.py +0 -0
  20. konduktor/controller/constants.py +56 -0
  21. konduktor/controller/launch.py +44 -0
  22. konduktor/controller/node.py +116 -0
  23. konduktor/controller/parse.py +111 -0
  24. konduktor/dashboard/README.md +30 -0
  25. konduktor/dashboard/backend/main.py +169 -0
  26. konduktor/dashboard/backend/sockets.py +154 -0
  27. konduktor/dashboard/frontend/.eslintrc.json +3 -0
  28. konduktor/dashboard/frontend/.gitignore +36 -0
  29. konduktor/dashboard/frontend/app/api/jobs/route.js +71 -0
  30. konduktor/dashboard/frontend/app/api/namespaces/route.js +69 -0
  31. konduktor/dashboard/frontend/app/components/Grafana.jsx +66 -0
  32. konduktor/dashboard/frontend/app/components/JobsData.jsx +197 -0
  33. konduktor/dashboard/frontend/app/components/LogsData.jsx +139 -0
  34. konduktor/dashboard/frontend/app/components/NavMenu.jsx +39 -0
  35. konduktor/dashboard/frontend/app/components/NavTabs.jsx +73 -0
  36. konduktor/dashboard/frontend/app/components/NavTabs2.jsx +30 -0
  37. konduktor/dashboard/frontend/app/components/SelectBtn.jsx +27 -0
  38. konduktor/dashboard/frontend/app/components/lib/utils.js +6 -0
  39. konduktor/dashboard/frontend/app/components/ui/chip-select.jsx +78 -0
  40. konduktor/dashboard/frontend/app/components/ui/input.jsx +19 -0
  41. konduktor/dashboard/frontend/app/components/ui/navigation-menu.jsx +104 -0
  42. konduktor/dashboard/frontend/app/components/ui/select.jsx +120 -0
  43. konduktor/dashboard/frontend/app/favicon.ico +0 -0
  44. konduktor/dashboard/frontend/app/globals.css +120 -0
  45. konduktor/dashboard/frontend/app/jobs/page.js +10 -0
  46. konduktor/dashboard/frontend/app/layout.js +22 -0
  47. konduktor/dashboard/frontend/app/logs/page.js +11 -0
  48. konduktor/dashboard/frontend/app/page.js +12 -0
  49. konduktor/dashboard/frontend/jsconfig.json +7 -0
  50. konduktor/dashboard/frontend/next.config.mjs +4 -0
  51. konduktor/dashboard/frontend/package-lock.json +6687 -0
  52. konduktor/dashboard/frontend/package.json +37 -0
  53. konduktor/dashboard/frontend/postcss.config.mjs +8 -0
  54. konduktor/dashboard/frontend/server.js +64 -0
  55. konduktor/dashboard/frontend/tailwind.config.js +17 -0
  56. konduktor/data/__init__.py +9 -0
  57. konduktor/data/aws/__init__.py +15 -0
  58. konduktor/data/aws/s3.py +1138 -0
  59. konduktor/data/constants.py +7 -0
  60. konduktor/data/data_utils.py +268 -0
  61. konduktor/data/gcp/__init__.py +19 -0
  62. konduktor/data/gcp/constants.py +42 -0
  63. konduktor/data/gcp/gcs.py +994 -0
  64. konduktor/data/gcp/utils.py +9 -0
  65. konduktor/data/registry.py +19 -0
  66. konduktor/data/storage.py +812 -0
  67. konduktor/data/storage_utils.py +535 -0
  68. konduktor/execution.py +447 -0
  69. konduktor/kube_client.py +237 -0
  70. konduktor/logging.py +111 -0
  71. konduktor/manifests/aibrix-setup.yaml +430 -0
  72. konduktor/manifests/apoxy-setup.yaml +184 -0
  73. konduktor/manifests/apoxy-setup2.yaml +98 -0
  74. konduktor/manifests/controller_deployment.yaml +69 -0
  75. konduktor/manifests/dashboard_deployment.yaml +131 -0
  76. konduktor/manifests/dmesg_daemonset.yaml +57 -0
  77. konduktor/manifests/pod_cleanup_controller.yaml +129 -0
  78. konduktor/resource.py +546 -0
  79. konduktor/serving.py +153 -0
  80. konduktor/task.py +949 -0
  81. konduktor/templates/deployment.yaml.j2 +191 -0
  82. konduktor/templates/jobset.yaml.j2 +43 -0
  83. konduktor/templates/pod.yaml.j2 +563 -0
  84. konduktor/usage/__init__.py +0 -0
  85. konduktor/usage/constants.py +21 -0
  86. konduktor/utils/__init__.py +0 -0
  87. konduktor/utils/accelerator_registry.py +17 -0
  88. konduktor/utils/annotations.py +62 -0
  89. konduktor/utils/base64_utils.py +95 -0
  90. konduktor/utils/common_utils.py +426 -0
  91. konduktor/utils/constants.py +5 -0
  92. konduktor/utils/env_options.py +55 -0
  93. konduktor/utils/exceptions.py +234 -0
  94. konduktor/utils/kubernetes_enums.py +8 -0
  95. konduktor/utils/kubernetes_utils.py +763 -0
  96. konduktor/utils/log_utils.py +467 -0
  97. konduktor/utils/loki_utils.py +102 -0
  98. konduktor/utils/rich_utils.py +123 -0
  99. konduktor/utils/schemas.py +625 -0
  100. konduktor/utils/subprocess_utils.py +273 -0
  101. konduktor/utils/ux_utils.py +247 -0
  102. konduktor/utils/validator.py +461 -0
  103. konduktor_nightly-0.1.0.dev20251128104812.dist-info/LICENSE +91 -0
  104. konduktor_nightly-0.1.0.dev20251128104812.dist-info/METADATA +98 -0
  105. konduktor_nightly-0.1.0.dev20251128104812.dist-info/RECORD +107 -0
  106. konduktor_nightly-0.1.0.dev20251128104812.dist-info/WHEEL +4 -0
  107. 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,6 @@
1
+ import { clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -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 }