synapse-sdk 1.0.0a96__py3-none-any.whl → 1.0.0b1__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.

Potentially problematic release.


This version of synapse-sdk might be problematic. Click here for more details.

Files changed (66) hide show
  1. synapse_sdk/cli/__init__.py +139 -84
  2. synapse_sdk/cli/code_server.py +169 -0
  3. synapse_sdk/cli/config.py +105 -4
  4. synapse_sdk/cli/devtools.py +54 -34
  5. synapse_sdk/clients/base.py +3 -4
  6. synapse_sdk/devtools/server.py +24 -791
  7. synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
  8. synapse_sdk/devtools/streamlit_app/app.py +128 -0
  9. synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
  10. synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
  11. synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
  12. synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
  13. synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
  14. synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
  15. synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
  16. synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
  17. synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
  18. synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
  19. synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
  20. synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
  21. synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
  22. synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
  23. synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
  24. synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
  25. synapse_sdk/devtools/streamlit_app.py +10 -0
  26. synapse_sdk/plugins/categories/upload/actions/upload.py +2 -1
  27. synapse_sdk/utils/converters/dm/__init__.py +0 -1
  28. synapse_sdk/utils/converters/pascal/from_dm.py +32 -10
  29. synapse_sdk/utils/storage/providers/file_system.py +15 -13
  30. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/METADATA +4 -6
  31. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/RECORD +35 -46
  32. synapse_sdk/devtools/models.py +0 -55
  33. synapse_sdk/devtools/utils.py +0 -52
  34. synapse_sdk/devtools/web/.gitignore +0 -2
  35. synapse_sdk/devtools/web/README.md +0 -34
  36. synapse_sdk/devtools/web/dist/index.html +0 -17
  37. synapse_sdk/devtools/web/index.html +0 -16
  38. synapse_sdk/devtools/web/jsconfig.json +0 -15
  39. synapse_sdk/devtools/web/package-lock.json +0 -2609
  40. synapse_sdk/devtools/web/package.json +0 -27
  41. synapse_sdk/devtools/web/pnpm-lock.yaml +0 -1055
  42. synapse_sdk/devtools/web/src/App.jsx +0 -14
  43. synapse_sdk/devtools/web/src/App.module.css +0 -33
  44. synapse_sdk/devtools/web/src/assets/favicon.ico +0 -0
  45. synapse_sdk/devtools/web/src/components/Breadcrumbs.jsx +0 -42
  46. synapse_sdk/devtools/web/src/components/Layout.jsx +0 -12
  47. synapse_sdk/devtools/web/src/components/LogViewer.jsx +0 -280
  48. synapse_sdk/devtools/web/src/components/MessageViewer.jsx +0 -150
  49. synapse_sdk/devtools/web/src/components/NavigationSidebar.jsx +0 -128
  50. synapse_sdk/devtools/web/src/components/ServerStatusBar.jsx +0 -245
  51. synapse_sdk/devtools/web/src/components/icons.jsx +0 -325
  52. synapse_sdk/devtools/web/src/index.css +0 -470
  53. synapse_sdk/devtools/web/src/index.jsx +0 -15
  54. synapse_sdk/devtools/web/src/logo.svg +0 -1
  55. synapse_sdk/devtools/web/src/router.jsx +0 -34
  56. synapse_sdk/devtools/web/src/utils/api.js +0 -442
  57. synapse_sdk/devtools/web/src/views/ApplicationDetailView.jsx +0 -241
  58. synapse_sdk/devtools/web/src/views/ApplicationsView.jsx +0 -224
  59. synapse_sdk/devtools/web/src/views/HomeView.jsx +0 -197
  60. synapse_sdk/devtools/web/src/views/JobDetailView.jsx +0 -310
  61. synapse_sdk/devtools/web/src/views/PluginView.jsx +0 -914
  62. synapse_sdk/devtools/web/vite.config.js +0 -13
  63. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/WHEEL +0 -0
  64. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/entry_points.txt +0 -0
  65. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/licenses/LICENSE +0 -0
  66. {synapse_sdk-1.0.0a96.dist-info → synapse_sdk-1.0.0b1.dist-info}/top_level.txt +0 -0
@@ -1,14 +0,0 @@
1
- import { AppRouter } from "./router";
2
- import ServerStatusBar from "./components/ServerStatusBar";
3
- import "./index.css";
4
-
5
- function App() {
6
- return (
7
- <div class="min-h-screen bg-slate-50" data-theme="professional">
8
- <ServerStatusBar />
9
- <AppRouter />
10
- </div>
11
- );
12
- }
13
-
14
- export default App;
@@ -1,33 +0,0 @@
1
- .App {
2
- text-align: center;
3
- }
4
-
5
- .logo {
6
- animation: logo-spin infinite 20s linear;
7
- height: 40vmin;
8
- pointer-events: none;
9
- }
10
-
11
- .header {
12
- background-color: #282c34;
13
- min-height: 100vh;
14
- display: flex;
15
- flex-direction: column;
16
- align-items: center;
17
- justify-content: center;
18
- font-size: calc(10px + 2vmin);
19
- color: white;
20
- }
21
-
22
- .link {
23
- color: #b318f0;
24
- }
25
-
26
- @keyframes logo-spin {
27
- from {
28
- transform: rotate(0deg);
29
- }
30
- to {
31
- transform: rotate(360deg);
32
- }
33
- }
@@ -1,42 +0,0 @@
1
- import { For, Show } from "solid-js";
2
- import { useNavigate } from "@solidjs/router";
3
- import { HomeIcon, ArrowLeftIcon } from "./icons";
4
-
5
- export default function Breadcrumbs(props) {
6
- const navigate = useNavigate();
7
-
8
- const handleNavigation = (path) => {
9
- navigate(path);
10
- };
11
-
12
- return (
13
- <div class="flex items-center gap-2 text-sm text-slate-600 mb-4">
14
- <button
15
- class="flex items-center gap-1 hover:text-slate-900 transition-colors"
16
- onClick={() => handleNavigation("/")}
17
- >
18
- <HomeIcon class="w-4 h-4" />
19
- <span>Home</span>
20
- </button>
21
-
22
- <For each={props.items}>
23
- {(item, index) => (
24
- <>
25
- <ArrowLeftIcon class="w-3 h-3 rotate-180 text-slate-400" />
26
- <Show when={item.path && index() < props.items.length - 1}>
27
- <button
28
- class="hover:text-slate-900 transition-colors"
29
- onClick={() => handleNavigation(item.path)}
30
- >
31
- {item.label}
32
- </button>
33
- </Show>
34
- <Show when={!item.path || index() === props.items.length - 1}>
35
- <span class="text-slate-900 font-medium">{item.label}</span>
36
- </Show>
37
- </>
38
- )}
39
- </For>
40
- </div>
41
- );
42
- }
@@ -1,12 +0,0 @@
1
- import NavigationSidebar from "./NavigationSidebar";
2
-
3
- export default function Layout(props) {
4
- return (
5
- <div class="flex h-full">
6
- <NavigationSidebar />
7
- <main class="flex-1 overflow-auto lg:ml-0">
8
- {props.children}
9
- </main>
10
- </div>
11
- );
12
- }
@@ -1,280 +0,0 @@
1
- import { Show, For, createSignal, createEffect, onMount, onCleanup } from "solid-js";
2
- import { createJobLogsStream } from "../utils/api";
3
- import Prism from "prismjs";
4
- import "prismjs/themes/prism-tomorrow.css";
5
-
6
- export default function LogViewer(props) {
7
- const [autoScroll, setAutoScroll] = createSignal(true);
8
- const [highlightedLine, setHighlightedLine] = createSignal(null);
9
-
10
- let logContainerRef;
11
-
12
- const {
13
- logs,
14
- streaming,
15
- error,
16
- startStreaming,
17
- stopStreaming,
18
- clearLogs
19
- } = createJobLogsStream(props.submissionId);
20
-
21
- // Auto-scroll functionality
22
- createEffect(() => {
23
- if (autoScroll() && logContainerRef && logs().length > 0) {
24
- logContainerRef.scrollTop = logContainerRef.scrollHeight;
25
- }
26
- });
27
-
28
- // Check if user scrolled up manually
29
- const handleScroll = () => {
30
- if (!logContainerRef) return;
31
-
32
- const { scrollTop, scrollHeight, clientHeight } = logContainerRef;
33
- const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
34
-
35
- if (autoScroll() && !isAtBottom) {
36
- setAutoScroll(false);
37
- }
38
- };
39
-
40
- const toggleAutoScroll = () => {
41
- setAutoScroll(!autoScroll());
42
- if (autoScroll()) {
43
- scrollToBottom();
44
- }
45
- };
46
-
47
- const scrollToBottom = () => {
48
- if (logContainerRef) {
49
- logContainerRef.scrollTop = logContainerRef.scrollHeight;
50
- }
51
- };
52
-
53
- const copyLogs = () => {
54
- const logText = logs()
55
- .map(log => {
56
- const timestamp = log.timestamp ? `[${formatTimestamp(log.timestamp)}] ` : '';
57
- const level = log.level ? `[${log.level.toUpperCase()}] ` : '';
58
- return `${timestamp}${level}${log.message}`;
59
- })
60
- .join('\n');
61
-
62
- navigator.clipboard.writeText(logText).then(() => {
63
- // Could add a toast notification here
64
- });
65
- };
66
-
67
- const formatTimestamp = (timestamp) => {
68
- try {
69
- const date = new Date(timestamp);
70
- return date.toLocaleTimeString("en-US", {
71
- hour12: false,
72
- hour: "2-digit",
73
- minute: "2-digit",
74
- second: "2-digit",
75
- });
76
- } catch {
77
- return timestamp;
78
- }
79
- };
80
-
81
- const formatLogMessage = (message) => {
82
- // Escape HTML first
83
- let formatted = message
84
- .replace(/&/g, "&amp;")
85
- .replace(/</g, "&lt;")
86
- .replace(/>/g, "&gt;");
87
-
88
- // Handle ANSI escape codes and convert to HTML
89
- formatted = formatted
90
- // Reset
91
- .replace(/\x1b\[0m/g, "</span>")
92
- // Colors
93
- .replace(/\x1b\[31m/g, '<span class="ansi-red">')
94
- .replace(/\x1b\[32m/g, '<span class="ansi-green">')
95
- .replace(/\x1b\[33m/g, '<span class="ansi-yellow">')
96
- .replace(/\x1b\[34m/g, '<span class="ansi-blue">')
97
- .replace(/\x1b\[35m/g, '<span class="ansi-magenta">')
98
- .replace(/\x1b\[36m/g, '<span class="ansi-cyan">')
99
- .replace(/\x1b\[37m/g, '<span class="ansi-white">')
100
- .replace(/\x1b\[90m/g, '<span class="ansi-gray">')
101
- .replace(/\x1b\[91m/g, '<span class="ansi-bright-red">')
102
- .replace(/\x1b\[92m/g, '<span class="ansi-bright-green">')
103
- .replace(/\x1b\[93m/g, '<span class="ansi-bright-yellow">')
104
- .replace(/\x1b\[94m/g, '<span class="ansi-bright-blue">')
105
- .replace(/\x1b\[95m/g, '<span class="ansi-bright-magenta">')
106
- .replace(/\x1b\[96m/g, '<span class="ansi-bright-cyan">')
107
- .replace(/\x1b\[97m/g, '<span class="ansi-bright-white">')
108
- // Bold
109
- .replace(/\x1b\[1m/g, '<span class="ansi-bold">')
110
- // Remove any remaining ANSI codes
111
- .replace(/\x1b\[[0-9;]*m/g, "");
112
-
113
- // Try to detect and highlight JSON
114
- if (message.trim().match(/^\s*[{\[].*[}\]]\s*$/s)) {
115
- try {
116
- const trimmed = message.trim();
117
- const parsed = JSON.parse(trimmed);
118
- const jsonString = JSON.stringify(parsed, null, 2);
119
- formatted = Prism.highlight(jsonString, Prism.languages.json, "json");
120
- } catch {
121
- // Not valid JSON, continue with original formatting
122
- }
123
- }
124
-
125
- // Highlight URLs
126
- formatted = formatted.replace(
127
- /(https?:\/\/[^\s<>&"']+)/g,
128
- '<a href="$1" target="_blank" rel="noopener noreferrer" class="log-url">$1</a>'
129
- );
130
-
131
- // Highlight file paths
132
- formatted = formatted.replace(
133
- /([a-zA-Z0-9_\-./]+\.(py|js|ts|vue|json|yaml|yml|txt|log|sh|md))/g,
134
- '<span class="log-filepath">$1</span>'
135
- );
136
-
137
- // Highlight common patterns
138
- formatted = formatted
139
- // Error patterns
140
- .replace(
141
- /\b(ERROR|FATAL|EXCEPTION|TRACEBACK)\b/gi,
142
- '<span class="pattern-error">$1</span>'
143
- )
144
- // Warning patterns
145
- .replace(
146
- /\b(WARNING|WARN|DEPRECATED)\b/gi,
147
- '<span class="pattern-warning">$1</span>'
148
- )
149
- // Success patterns
150
- .replace(
151
- /\b(SUCCESS|PASSED|OK|COMPLETE)\b/gi,
152
- '<span class="pattern-success">$1</span>'
153
- )
154
- // Info patterns
155
- .replace(
156
- /\b(INFO|DEBUG|TRACE)\b/gi,
157
- '<span class="pattern-info">$1</span>'
158
- );
159
-
160
- return formatted;
161
- };
162
-
163
- const getLogLevelClass = (level) => {
164
- if (!level) return "";
165
-
166
- switch (level.toLowerCase()) {
167
- case "error":
168
- return "log-level-error";
169
- case "warn":
170
- case "warning":
171
- return "log-level-warn";
172
- case "info":
173
- return "log-level-info";
174
- case "debug":
175
- return "log-level-debug";
176
- default:
177
- return "";
178
- }
179
- };
180
-
181
- const highlightLine = (index) => {
182
- setHighlightedLine(highlightedLine() === index ? null : index);
183
- };
184
-
185
- onMount(() => {
186
- startStreaming();
187
- });
188
-
189
- onCleanup(() => {
190
- stopStreaming();
191
- });
192
-
193
- return (
194
- <div class="github-log-viewer">
195
- {/* Header */}
196
- <div class="log-header">
197
- <div class="log-title">
198
- <svg class="octicon" viewBox="0 0 16 16" width="16" height="16">
199
- <path d="M8 16a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2c.55 0 1.02.26 1.3.62.27.35.7.38 1.1.38.4 0 .83-.03 1.1-.38.28-.36.75-.62 1.3-.62a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H8z" />
200
- </svg>
201
- <span>Logs</span>
202
- </div>
203
- <div class="log-controls">
204
- <button
205
- onClick={toggleAutoScroll}
206
- class={`control-btn ${autoScroll() ? 'active' : ''}`}
207
- >
208
- Auto-scroll
209
- </button>
210
- <button onClick={clearLogs} class="control-btn">Clear</button>
211
- <button onClick={copyLogs} class="control-btn">Copy</button>
212
- </div>
213
- </div>
214
-
215
- {/* Error State */}
216
- <Show when={error()}>
217
- <div class="alert alert-error mb-2">
218
- <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
219
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
220
- </svg>
221
- <span>{error()}</span>
222
- </div>
223
- </Show>
224
-
225
- {/* Container */}
226
- <div class="log-container" ref={logContainerRef} onScroll={handleScroll}>
227
- <Show when={logs().length === 0 && !error()}>
228
- <div class="log-empty">
229
- <div class="empty-state">
230
- <svg class="empty-icon" viewBox="0 0 24 24" width="24" height="24">
231
- <path d="M3 3v18h18V3H3zm16 16H5V5h14v14zM7 7h10v2H7V7zm0 4h10v2H7v-2zm0 4h7v2H7v-2z" />
232
- </svg>
233
- <p>No logs available</p>
234
- <p class="empty-subtitle">Logs will appear here when available</p>
235
- </div>
236
- </div>
237
- </Show>
238
-
239
- <Show when={logs().length > 0}>
240
- <div class="log-content">
241
- <For each={logs()}>
242
- {(log, index) => (
243
- <div
244
- class={`log-line ${getLogLevelClass(log.level)} ${
245
- highlightedLine() === index() ? 'highlighted' : ''
246
- }`}
247
- onClick={() => highlightLine(index())}
248
- >
249
- <span class="line-number">{index() + 1}</span>
250
- <Show when={log.timestamp}>
251
- <span class="log-timestamp">
252
- {formatTimestamp(log.timestamp)}
253
- </span>
254
- </Show>
255
- <Show when={log.level}>
256
- <span class="log-level-badge">
257
- {log.level.toUpperCase().charAt(0)}
258
- </span>
259
- </Show>
260
- <span class="log-message" innerHTML={formatLogMessage(log.message)} />
261
- </div>
262
- )}
263
- </For>
264
- </div>
265
- </Show>
266
- </div>
267
-
268
- {/* Footer */}
269
- <div class="log-footer">
270
- <span class="log-count">{logs().length} lines</span>
271
- <Show when={streaming()}>
272
- <span class="streaming-status">
273
- <div class="streaming-dot"></div>
274
- Streaming...
275
- </span>
276
- </Show>
277
- </div>
278
- </div>
279
- );
280
- }
@@ -1,150 +0,0 @@
1
- import { Show, createSignal } from "solid-js";
2
- import Prism from "prismjs";
3
- import "prismjs/themes/prism.css";
4
- import "prismjs/components/prism-json";
5
- import "prismjs/components/prism-bash";
6
- import "prismjs/components/prism-python";
7
-
8
- export default function MessageViewer(props) {
9
- const [isExpanded, setIsExpanded] = createSignal(false);
10
-
11
- const message = () => props.message || '';
12
- const isLongMessage = () => message().length > 500;
13
-
14
- const displayMessage = () => {
15
- if (isExpanded() || !isLongMessage()) {
16
- return message();
17
- }
18
- return message().substring(0, 500) + '...';
19
- };
20
-
21
- const copyMessage = () => {
22
- navigator.clipboard.writeText(message()).then(() => {
23
- // Could add a toast notification here
24
- });
25
- };
26
-
27
- const formatMessage = (msg) => {
28
- if (!msg) return "";
29
-
30
- // Escape HTML first
31
- let formatted = msg
32
- .replace(/&/g, "&amp;")
33
- .replace(/</g, "&lt;")
34
- .replace(/>/g, "&gt;");
35
-
36
- // Handle ANSI escape codes and convert to HTML
37
- formatted = formatted
38
- // Reset
39
- .replace(/\x1b\[0m/g, "</span>")
40
- // Colors
41
- .replace(/\x1b\[31m/g, '<span class="ansi-red">')
42
- .replace(/\x1b\[32m/g, '<span class="ansi-green">')
43
- .replace(/\x1b\[33m/g, '<span class="ansi-yellow">')
44
- .replace(/\x1b\[34m/g, '<span class="ansi-blue">')
45
- .replace(/\x1b\[35m/g, '<span class="ansi-magenta">')
46
- .replace(/\x1b\[36m/g, '<span class="ansi-cyan">')
47
- .replace(/\x1b\[37m/g, '<span class="ansi-white">')
48
- .replace(/\x1b\[90m/g, '<span class="ansi-gray">')
49
- .replace(/\x1b\[91m/g, '<span class="ansi-bright-red">')
50
- .replace(/\x1b\[92m/g, '<span class="ansi-bright-green">')
51
- .replace(/\x1b\[93m/g, '<span class="ansi-bright-yellow">')
52
- .replace(/\x1b\[94m/g, '<span class="ansi-bright-blue">')
53
- .replace(/\x1b\[95m/g, '<span class="ansi-bright-magenta">')
54
- .replace(/\x1b\[96m/g, '<span class="ansi-bright-cyan">')
55
- .replace(/\x1b\[97m/g, '<span class="ansi-bright-white">')
56
- // Bold
57
- .replace(/\x1b\[1m/g, '<span class="ansi-bold">')
58
- // Remove any remaining ANSI codes
59
- .replace(/\x1b\[[0-9;]*m/g, "");
60
-
61
- // Try to detect and highlight JSON
62
- if (msg.trim().match(/^\s*[{\[].*[}\]]\s*$/s)) {
63
- try {
64
- const trimmed = msg.trim();
65
- const parsed = JSON.parse(trimmed);
66
- const jsonString = JSON.stringify(parsed, null, 2);
67
- formatted = Prism.highlight(jsonString, Prism.languages.json, "json");
68
- } catch {
69
- // Not valid JSON, continue with original formatting
70
- }
71
- }
72
-
73
- // Highlight URLs
74
- formatted = formatted.replace(
75
- /(https?:\/\/[^\s<>&"']+)/g,
76
- '<a href="$1" target="_blank" rel="noopener noreferrer" class="message-url">$1</a>'
77
- );
78
-
79
- // Highlight file paths
80
- formatted = formatted.replace(
81
- /([a-zA-Z0-9_\-./]+\.(py|js|ts|vue|json|yaml|yml|txt|log|sh|md))/g,
82
- '<span class="message-filepath">$1</span>'
83
- );
84
-
85
- // Highlight common patterns
86
- formatted = formatted
87
- // Error patterns
88
- .replace(
89
- /\b(ERROR|FATAL|EXCEPTION|TRACEBACK)\b/gi,
90
- '<span class="pattern-error">$1</span>'
91
- )
92
- // Warning patterns
93
- .replace(
94
- /\b(WARNING|WARN|DEPRECATED)\b/gi,
95
- '<span class="pattern-warning">$1</span>'
96
- )
97
- // Success patterns
98
- .replace(
99
- /\b(SUCCESS|PASSED|OK|COMPLETE)\b/gi,
100
- '<span class="pattern-success">$1</span>'
101
- )
102
- // Info patterns
103
- .replace(
104
- /\b(INFO|DEBUG|TRACE)\b/gi,
105
- '<span class="pattern-info">$1</span>'
106
- );
107
-
108
- return formatted;
109
- };
110
-
111
- // Check if message looks like JSON
112
- const isJsonMessage = () => {
113
- const trimmed = message().trim();
114
- return (trimmed.startsWith('{') && trimmed.endsWith('}')) ||
115
- (trimmed.startsWith('[') && trimmed.endsWith(']'));
116
- };
117
-
118
- // Check if message looks like a stack trace
119
- const isStackTrace = () => {
120
- return message().includes('Traceback') ||
121
- message().includes(' at ') ||
122
- message().includes('File "') ||
123
- /^\s*File ".*", line \d+/.test(message());
124
- };
125
-
126
- const getMessageClass = () => {
127
- if (isStackTrace()) {
128
- return 'bg-red-50 border-red-200';
129
- } else if (isJsonMessage()) {
130
- return 'bg-slate-50 border-slate-200';
131
- } else {
132
- return 'bg-slate-50 border-slate-200';
133
- }
134
- };
135
-
136
- return (
137
- <div class={`message-viewer rounded-lg border overflow-hidden ${getMessageClass()}`}>
138
- <div class="relative">
139
- <div
140
- class="message-content p-4 text-slate-900 whitespace-pre-wrap break-words max-h-96 overflow-y-auto scrollbar-thin scrollbar-thumb-slate-300 scrollbar-track-slate-100 font-mono text-sm leading-relaxed"
141
- innerHTML={formatMessage(displayMessage())}
142
- />
143
-
144
- <Show when={isLongMessage() && !isExpanded()}>
145
- <div class="absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-white to-transparent"></div>
146
- </Show>
147
- </div>
148
- </div>
149
- );
150
- }
@@ -1,128 +0,0 @@
1
- import { useLocation, useNavigate } from "@solidjs/router";
2
- import { createSignal, Show } from "solid-js";
3
- import { MenuIcon, CloseIcon, DocumentIcon } from "./icons";
4
- import { createStatusResource } from "../utils/api";
5
-
6
- export default function NavigationSidebar() {
7
- const location = useLocation();
8
- const navigate = useNavigate();
9
- const [isMobileMenuOpen, setIsMobileMenuOpen] = createSignal(false);
10
-
11
- // Get status for version info
12
- const { data: status } = createStatusResource();
13
-
14
- const navigationItems = [
15
- {
16
- id: "home",
17
- label: "Jobs",
18
- path: "/",
19
- },
20
- {
21
- id: "applications",
22
- label: "Serve Application",
23
- path: "/serve_applications",
24
- },
25
- {
26
- id: "plugin",
27
- label: "Plugin",
28
- path: "/plugin",
29
- }
30
- ];
31
-
32
- const isActive = (path) => {
33
- if (path === "/") {
34
- return location.pathname === "/";
35
- }
36
- return location.pathname.startsWith(path);
37
- };
38
-
39
- const handleNavigation = (path) => {
40
- navigate(path);
41
- setIsMobileMenuOpen(false); // Close mobile menu after navigation
42
- };
43
-
44
- return (
45
- <>
46
- {/* Mobile Menu Button */}
47
- <button
48
- class="lg:hidden fixed top-20 left-4 z-50 btn btn-sm btn-circle btn-ghost bg-white border border-slate-200 shadow-sm"
49
- onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen())}
50
- >
51
- <Show when={!isMobileMenuOpen()}>
52
- <MenuIcon class="w-4 h-4" />
53
- </Show>
54
- <Show when={isMobileMenuOpen()}>
55
- <CloseIcon class="w-4 h-4" />
56
- </Show>
57
- </button>
58
-
59
- {/* Mobile Overlay */}
60
- <Show when={isMobileMenuOpen()}>
61
- <div
62
- class="lg:hidden fixed inset-0 bg-black bg-opacity-30 z-40"
63
- onClick={() => setIsMobileMenuOpen(false)}
64
- />
65
- </Show>
66
-
67
- {/* Sidebar */}
68
- <div class={`
69
- w-64 bg-white border-r border-slate-200 min-h-screen flex flex-col
70
- lg:relative lg:translate-x-0 lg:z-auto
71
- ${isMobileMenuOpen()
72
- ? 'fixed inset-y-0 left-0 z-50 translate-x-0'
73
- : 'fixed inset-y-0 left-0 z-50 -translate-x-full lg:translate-x-0'}
74
- transition-transform duration-300 ease-in-out
75
- `}>
76
- {/* Header */}
77
- <div class="p-6 border-b border-slate-200">
78
- <h2 class="text-xl font-bold text-slate-900">Synapse Devtools</h2>
79
- <p class="text-sm text-slate-600 mt-1">Development Environment</p>
80
- </div>
81
-
82
- {/* Navigation */}
83
- <nav class="flex-1 p-6 py-8 overflow-y-auto">
84
- <ul class="space-y-2">
85
- {navigationItems.map((item) => {
86
- const active = isActive(item.path);
87
-
88
- return (
89
- <li key={item.id}>
90
- <button
91
- class={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-colors ${
92
- active
93
- ? "bg-slate-100 text-slate-900 font-medium"
94
- : "text-slate-600 hover:bg-slate-50 hover:text-slate-900"
95
- }`}
96
- onClick={() => handleNavigation(item.path)}
97
- >
98
- <div class="flex-1 min-w-0">
99
- <div class="text-sm font-medium">{item.label}</div>
100
- </div>
101
- </button>
102
- </li>
103
- );
104
- })}
105
- </ul>
106
- </nav>
107
-
108
- {/* Footer - Fixed at bottom */}
109
- <div class="flex-shrink-0 p-6 border-t border-slate-200 bg-white">
110
- <div class="text-xs text-slate-500">
111
- <div class="flex items-center justify-between">
112
- <span>SDK {status()?.devtools?.version || "Unknown"}</span>
113
- <a
114
- href="https://docs.synapse.sh"
115
- target="_blank"
116
- rel="noopener noreferrer"
117
- class="text-slate-600 hover:text-slate-900"
118
- title="Documentation"
119
- >
120
- <DocumentIcon class="w-4 h-4" />
121
- </a>
122
- </div>
123
- </div>
124
- </div>
125
- </div>
126
- </>
127
- );
128
- }