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,914 +0,0 @@
1
- import { Show, For, createSignal, createEffect, createMemo, onMount } from "solid-js";
2
- import { createConfigResource, createConfigMutation, createValidationMutation, apiClient } from "../utils/api";
3
- import { SettingsIcon, FlaskIcon, RocketIcon, SaveIcon, PlayIcon, TrashIcon, CheckIcon, AlertCircleIcon, AlertTriangleIcon, InfoIcon, UploadIcon, CheckCircleIcon, RefreshIcon } from "../components/icons";
4
-
5
- export default function PluginView() {
6
- // State
7
- const [activeTab, setActiveTab] = createSignal("config");
8
- const [localConfig, setLocalConfig] = createSignal({});
9
- const [isDirty, setIsDirty] = createSignal(false);
10
- const [validationResult, setValidationResult] = createSignal(null);
11
- const [showValidationDetails, setShowValidationDetails] = createSignal(false);
12
- const [saveMessage, setSaveMessage] = createSignal("");
13
- const [saveMessageType, setSaveMessageType] = createSignal("success");
14
-
15
- // Testing state
16
- const [httpConfig, setHttpConfig] = createSignal({});
17
- const [selectedAction, setSelectedAction] = createSignal("");
18
- const [httpParams, setHttpParams] = createSignal("");
19
- const [httpResults, setHttpResults] = createSignal([]);
20
- const [isExecuting, setIsExecuting] = createSignal(false);
21
- const [isLoadingHttpConfig, setIsLoadingHttpConfig] = createSignal(false);
22
-
23
- // Publishing state
24
- const [publishConfig, setPublishConfig] = createSignal({});
25
- const [isPublishing, setIsPublishing] = createSignal(false);
26
- const [publishResult, setPublishResult] = createSignal(null);
27
-
28
- // API resources
29
- const { data: config, loading: isLoading, error, refresh: refreshConfig } = createConfigResource();
30
- const configMutation = createConfigMutation();
31
- const validationMutation = createValidationMutation();
32
-
33
- // Computed properties
34
- const pluginActions = createMemo(() => {
35
- const config = localConfig();
36
- if (!config.actions) return [];
37
- return Object.entries(config.actions).map(([name, action]) => ({
38
- name,
39
- type: action.method || 'job',
40
- }));
41
- });
42
-
43
- const canPublish = createMemo(() => {
44
- const pubConfig = publishConfig();
45
- return pubConfig.host && pubConfig.accessToken;
46
- });
47
-
48
- // Methods
49
- const markDirty = () => {
50
- setIsDirty(true);
51
- };
52
-
53
- const updateLocalConfig = (field, value) => {
54
- setLocalConfig(prev => ({ ...prev, [field]: value }));
55
- markDirty();
56
- };
57
-
58
- const updateTasksConfig = (value) => {
59
- // Convert comma-separated string to array for config
60
- const tasksArray = value.split(',').map(task => task.trim()).filter(task => task.length > 0);
61
- updateLocalConfig('tasks', tasksArray);
62
- };
63
-
64
- const saveConfiguration = async () => {
65
- try {
66
- // Validate first
67
- const validation = await validationMutation.mutate(localConfig());
68
- setValidationResult(validation);
69
-
70
- if (!validation.valid) {
71
- setSaveMessage("Configuration has validation errors");
72
- setSaveMessageType("error");
73
- setTimeout(() => setSaveMessage(""), 5000);
74
- return;
75
- }
76
-
77
- await configMutation.mutate(localConfig());
78
- setIsDirty(false);
79
- setSaveMessage("Configuration saved successfully");
80
- setSaveMessageType("success");
81
- setTimeout(() => setSaveMessage(""), 3000);
82
- } catch (err) {
83
- setSaveMessage(err.message || "Failed to save configuration");
84
- setSaveMessageType("error");
85
- setTimeout(() => setSaveMessage(""), 5000);
86
- }
87
- };
88
-
89
- const loadHttpConfig = async () => {
90
- setIsLoadingHttpConfig(true);
91
- try {
92
- const authResponse = await apiClient.get('/auth/token');
93
- if (authResponse.data) {
94
- setHttpConfig({
95
- baseUrl: authResponse.data.host || 'Not configured',
96
- accessToken: authResponse.data.token || '',
97
- pluginCode: ''
98
- });
99
- }
100
- } catch (err) {
101
- console.error('Failed to load http config:', err);
102
- } finally {
103
- setIsLoadingHttpConfig(false);
104
- }
105
- };
106
-
107
- const loadActionParams = async (action) => {
108
- if (!action) return;
109
-
110
- try {
111
- const response = await apiClient.get(`/plugin/http/params/${action}`);
112
- if (response.data && response.data.has_example) {
113
- setHttpParams(JSON.stringify(response.data.example_params, null, 2));
114
- }
115
- } catch (err) {
116
- console.error('Failed to load action params:', err);
117
- }
118
- };
119
-
120
- const executeHttpRequest = async () => {
121
- if (!selectedAction() || isExecuting()) return;
122
-
123
- setIsExecuting(true);
124
- try {
125
- const response = await apiClient.post('/plugin/http', {
126
- action: selectedAction(),
127
- params: httpParams() ? JSON.parse(httpParams()) : {},
128
- debug: true,
129
- access_token: httpConfig().accessToken,
130
- });
131
-
132
- // Check if the response indicates a validation error
133
- if (response.data && !response.data.success && response.data.validation_errors) {
134
- const result = {
135
- timestamp: new Date().toISOString(),
136
- success: false,
137
- status_code: 400,
138
- error: response.data.error,
139
- validation_errors: response.data.validation_errors,
140
- execution_time: 0
141
- };
142
- setHttpResults(prev => [...prev, result]);
143
- } else {
144
- const result = {
145
- timestamp: new Date().toISOString(),
146
- success: response.data?.success !== false,
147
- status_code: response.data?.status_code || 200,
148
- response_data: response.data,
149
- execution_time: response.data?.execution_time || 0,
150
- error: response.error
151
- };
152
- setHttpResults(prev => [...prev, result]);
153
- }
154
- } catch (err) {
155
- const result = {
156
- timestamp: new Date().toISOString(),
157
- success: false,
158
- status_code: 500,
159
- error: err.message,
160
- execution_time: 0
161
- };
162
- setHttpResults(prev => [...prev, result]);
163
- } finally {
164
- setIsExecuting(false);
165
- }
166
- };
167
-
168
- const clearResults = () => {
169
- setHttpResults([]);
170
- };
171
-
172
- const publishPlugin = async () => {
173
- setIsPublishing(true);
174
- try {
175
- const response = await apiClient.post('/plugin/publish', {
176
- host: publishConfig().host,
177
- access_token: publishConfig().accessToken,
178
- debug: publishConfig().debug,
179
- });
180
-
181
- // Handle validation errors from the new API
182
- if (response.data && !response.data.success && response.data.validation_errors) {
183
- setPublishResult({
184
- success: false,
185
- error: response.data.error,
186
- validation_errors: response.data.validation_errors,
187
- message: response.data.message
188
- });
189
- } else {
190
- setPublishResult(response.data);
191
- }
192
- } catch (err) {
193
- setPublishResult({
194
- success: false,
195
- error: err.message || 'Failed to publish plugin'
196
- });
197
- } finally {
198
- setIsPublishing(false);
199
- }
200
- };
201
-
202
- const formatTimestamp = (timestamp) => {
203
- return new Date(timestamp).toLocaleTimeString();
204
- };
205
-
206
- // Auto-validation with debouncing
207
- let validationTimeout;
208
- createEffect(() => {
209
- const config = localConfig();
210
- if (Object.keys(config).length > 0) {
211
- if (validationTimeout) clearTimeout(validationTimeout);
212
-
213
- validationTimeout = setTimeout(async () => {
214
- try {
215
- const validation = await validationMutation.mutate(config);
216
- setValidationResult(validation);
217
- } catch (error) {
218
- console.debug('Auto-validation failed:', error);
219
- }
220
- }, 500);
221
- }
222
- });
223
-
224
- // Sync with config
225
- createEffect(() => {
226
- if (config()) {
227
- const configData = config().config || config(); // Handle both direct config and wrapped response
228
- setLocalConfig({ ...configData });
229
- setIsDirty(false);
230
-
231
- // Pre-fill plugin code in testing from config
232
- if (configData.code && !httpConfig().pluginCode) {
233
- setHttpConfig(prev => ({ ...prev, pluginCode: configData.code }));
234
- }
235
- }
236
- });
237
-
238
- // Load data on mount
239
- onMount(async () => {
240
- await loadHttpConfig();
241
-
242
- // Load publish config
243
- try {
244
- const authResponse = await apiClient.get('/auth/token');
245
- if (authResponse.data?.token && authResponse.data?.host) {
246
- setPublishConfig({
247
- host: authResponse.data.host,
248
- accessToken: authResponse.data.token,
249
- debug: true
250
- });
251
- }
252
- } catch (err) {
253
- console.error('Failed to load publish config:', err);
254
- }
255
- });
256
-
257
- return (
258
- <div class="min-h-screen bg-slate-50">
259
- {/* Header */}
260
- <header class="sticky top-0 z-50 w-full border-b border-slate-200 glass-effect">
261
- <div class="container mx-auto flex h-14 max-w-6xl items-center justify-between px-4">
262
- <div class="flex-1">
263
- <h1 class="text-lg font-semibold">Plugin Development</h1>
264
- <p class="text-sm text-slate-500">Configure and deploy your Synapse plugin</p>
265
- </div>
266
- <Show when={isDirty()}>
267
- <button
268
- class="btn btn-sm btn-primary"
269
- onClick={saveConfiguration}
270
- disabled={configMutation.loading()}
271
- >
272
- <SaveIcon class="w-4 h-4 mr-2" />
273
- {configMutation.loading() ? 'Saving...' : 'Save'}
274
- </button>
275
- </Show>
276
- </div>
277
- </header>
278
-
279
- {/* Loading State */}
280
- <Show when={isLoading()}>
281
- <div class="flex min-h-[400px] items-center justify-center">
282
- <div class="text-center">
283
- <div class="loading loading-spinner loading-lg mb-4"></div>
284
- <p class="text-sm text-slate-600">Loading configuration...</p>
285
- </div>
286
- </div>
287
- </Show>
288
-
289
- {/* Error State */}
290
- <Show when={error()}>
291
- <div class="container mx-auto max-w-6xl px-4 py-8">
292
- <div class="alert alert-error">
293
- <AlertCircleIcon class="w-4 h-4" />
294
- <div>
295
- <h3 class="font-semibold">Failed to load configuration</h3>
296
- <p class="text-sm">{error()}</p>
297
- </div>
298
- </div>
299
- <button class="btn btn-sm btn-outline mt-4" onClick={refreshConfig}>
300
- <RefreshIcon class="w-4 h-4 mr-2" />
301
- Retry
302
- </button>
303
- </div>
304
- </Show>
305
-
306
- {/* Main Content */}
307
- <Show when={!isLoading() && !error()}>
308
- <main class="px-6 py-6">
309
- {/* Tabs */}
310
- <div class="tabs tabs-bordered w-full">
311
- <button
312
- class={`tab tab-lg ${activeTab() === 'config' ? 'tab-active' : ''}`}
313
- onClick={() => setActiveTab('config')}
314
- >
315
- <SettingsIcon class="w-4 h-4 mr-2" />
316
- Configuration
317
- </button>
318
- <button
319
- class={`tab tab-lg ${activeTab() === 'httprequest' ? 'tab-active' : ''}`}
320
- onClick={() => setActiveTab('httprequest')}
321
- >
322
- <FlaskIcon class="w-4 h-4 mr-2" />
323
- HTTP Request
324
- </button>
325
- <button
326
- class={`tab tab-lg ${activeTab() === 'deployment' ? 'tab-active' : ''}`}
327
- onClick={() => setActiveTab('deployment')}
328
- >
329
- <RocketIcon class="w-4 h-4 mr-2" />
330
- Deployment
331
- </button>
332
- </div>
333
-
334
- {/* Configuration Tab */}
335
- <Show when={activeTab() === 'config'}>
336
- <div class="mt-6 space-y-4">
337
- <div class="card bg-white shadow-professional">
338
- <div class="card-body p-6">
339
- <div class="flex items-center justify-between mb-4">
340
- <h2 class="text-lg font-semibold text-slate-900">Basic Information</h2>
341
- <Show when={config() && config().file_path}>
342
- <div class="flex items-center gap-2 text-sm text-slate-600">
343
- <InfoIcon class="w-4 h-4" />
344
- <span>Loaded from {config().file_path}</span>
345
- </div>
346
- </Show>
347
- </div>
348
-
349
- {/* Validation Status */}
350
- <Show when={validationResult() || (config() && config().validation)}>
351
- {(() => {
352
- const validation = validationResult() || (config() && config().validation);
353
- return (
354
- <div class={`alert mb-6 ${validation.valid ? 'alert-success' : 'alert-error'}`}>
355
- <Show when={validation.valid}>
356
- <CheckIcon class="w-4 h-4" />
357
- </Show>
358
- <Show when={!validation.valid}>
359
- <AlertCircleIcon class="w-4 h-4" />
360
- </Show>
361
- <div class="flex-1">
362
- <div class="flex items-center justify-between">
363
- <Show when={validation.valid}>
364
- <span>Configuration valid ({validation.validated_fields} fields)</span>
365
- </Show>
366
- <Show when={!validation.valid}>
367
- <span>{validation.errors?.length || 0} validation error{(validation.errors?.length || 0) > 1 ? 's' : ''}</span>
368
- </Show>
369
- <Show when={!validation.valid && validation.errors?.length > 0}>
370
- <button
371
- class="btn btn-xs btn-ghost"
372
- onClick={() => setShowValidationDetails(!showValidationDetails())}
373
- >
374
- {showValidationDetails() ? 'Hide' : 'Show'} Details
375
- </button>
376
- </Show>
377
- </div>
378
- </div>
379
- </div>
380
- );
381
- })()}
382
- </Show>
383
-
384
- {/* Validation Errors */}
385
- <Show when={showValidationDetails()}>
386
- {(() => {
387
- const validation = validationResult() || (config() && config().validation);
388
- const errors = validation?.errors || [];
389
-
390
- return errors.length > 0 && !validation?.valid ? (
391
- <div class="mb-6 space-y-2">
392
- <For each={errors}>
393
- {(error) => (
394
- <div class="flex items-start gap-2 text-sm text-red-600">
395
- <AlertTriangleIcon class="mt-0.5 h-3 w-3 flex-shrink-0" />
396
- <span>{error}</span>
397
- </div>
398
- )}
399
- </For>
400
- </div>
401
- ) : null;
402
- })()}
403
- </Show>
404
-
405
- {/* Form */}
406
- <div class="grid gap-4 md:grid-cols-2">
407
- <div class="form-control">
408
- <label class="label">
409
- <span class="label-text">Plugin Name</span>
410
- </label>
411
- <input
412
- type="text"
413
- class="input input-bordered"
414
- placeholder="Enter plugin name"
415
- value={localConfig().name || ''}
416
- onInput={(e) => updateLocalConfig('name', e.target.value)}
417
- />
418
- </div>
419
-
420
- <div class="form-control">
421
- <label class="label">
422
- <span class="label-text">Code</span>
423
- </label>
424
- <input
425
- type="text"
426
- class="input input-bordered"
427
- placeholder="plugin-code"
428
- value={localConfig().code || ''}
429
- onInput={(e) => updateLocalConfig('code', e.target.value)}
430
- />
431
- </div>
432
-
433
- <div class="form-control">
434
- <label class="label">
435
- <span class="label-text">Version</span>
436
- </label>
437
- <input
438
- type="text"
439
- class="input input-bordered"
440
- placeholder="1.0.0"
441
- value={localConfig().version || ''}
442
- onInput={(e) => updateLocalConfig('version', e.target.value)}
443
- />
444
- </div>
445
-
446
- <div class="form-control">
447
- <label class="label">
448
- <span class="label-text">Category</span>
449
- </label>
450
- <select
451
- class="select select-bordered"
452
- value={localConfig().category || ''}
453
- onChange={(e) => updateLocalConfig('category', e.target.value)}
454
- >
455
- <option value="">Select category</option>
456
- <option value="neural_net">Neural Network</option>
457
- <option value="export">Export</option>
458
- <option value="upload">Upload</option>
459
- <option value="smart_tool">Smart Tool</option>
460
- <option value="post_annotation">Post Annotation</option>
461
- <option value="pre_annotation">Pre Annotation</option>
462
- <option value="data_validation">Data Validation</option>
463
- </select>
464
- </div>
465
-
466
- <div class="form-control">
467
- <label class="label">
468
- <span class="label-text">Data Type</span>
469
- </label>
470
- <select
471
- class="select select-bordered"
472
- value={localConfig().data_type || ''}
473
- onChange={(e) => updateLocalConfig('data_type', e.target.value)}
474
- >
475
- <option value="">Select data type</option>
476
- <option value="image">Image</option>
477
- <option value="text">Text</option>
478
- <option value="video">Video</option>
479
- <option value="pcd">Point Cloud</option>
480
- <option value="audio">Audio</option>
481
- </select>
482
- </div>
483
-
484
- <div class="form-control">
485
- <label class="label">
486
- <span class="label-text">Package Manager</span>
487
- </label>
488
- <select
489
- class="select select-bordered"
490
- value={localConfig().package_manager || ''}
491
- onChange={(e) => updateLocalConfig('package_manager', e.target.value)}
492
- >
493
- <option value="">Select package manager</option>
494
- <option value="pip">pip</option>
495
- <option value="uv">uv</option>
496
- </select>
497
- </div>
498
-
499
- <div class="form-control md:col-span-2">
500
- <label class="label">
501
- <span class="label-text">Description</span>
502
- </label>
503
- <textarea
504
- class="textarea textarea-bordered"
505
- rows="3"
506
- placeholder="Describe what your plugin does"
507
- value={localConfig().description || ''}
508
- onInput={(e) => updateLocalConfig('description', e.target.value)}
509
- />
510
- </div>
511
-
512
- <div class="form-control md:col-span-2">
513
- <label class="label">
514
- <span class="label-text">Task Types</span>
515
- </label>
516
- <input
517
- type="text"
518
- class="input input-bordered"
519
- placeholder="e.g., image.object_detection, text.classification"
520
- value={Array.isArray(localConfig().tasks) ? localConfig().tasks.join(', ') : (localConfig().tasks || '')}
521
- onInput={(e) => updateTasksConfig(e.target.value)}
522
- />
523
- <label class="label">
524
- <span class="label-text-alt">Comma-separated task types (format: data_type.task_name)</span>
525
- </label>
526
- </div>
527
- </div>
528
- </div>
529
- </div>
530
- </div>
531
- </Show>
532
-
533
- {/* Http Tab */}
534
- <Show when={activeTab() === 'httprequest'}>
535
- <div class="mt-6 space-y-4">
536
- {/* HTTP Configuration */}
537
- <div class="card bg-white shadow-professional">
538
- <div class="card-body p-6">
539
- <h3 class="text-lg font-semibold text-slate-900 mb-4">HTTP Configuration</h3>
540
-
541
- <Show when={isLoadingHttpConfig()}>
542
- <div class="flex items-center gap-3 text-sm text-slate-600">
543
- <div class="loading loading-spinner loading-sm"></div>
544
- <span>Loading configuration...</span>
545
- </div>
546
- </Show>
547
-
548
- <Show when={!isLoadingHttpConfig()}>
549
- <div class="grid gap-4 md:grid-cols-2">
550
- <div class="form-control">
551
- <label class="label">
552
- <span class="label-text">Backend URL</span>
553
- </label>
554
- <input
555
- type="text"
556
- class="input input-bordered bg-slate-50"
557
- value={httpConfig().baseUrl || 'Not configured'}
558
- readonly
559
- />
560
- </div>
561
- <div class="form-control">
562
- <label class="label">
563
- <span class="label-text">Access Token</span>
564
- </label>
565
- <input
566
- type="password"
567
- class="input input-bordered bg-slate-50"
568
- value={httpConfig().accessToken ? '••••••••' : 'Not configured'}
569
- readonly
570
- />
571
- </div>
572
- <div class="form-control">
573
- <label class="label">
574
- <span class="label-text">Plugin Code</span>
575
- <Show when={httpConfig().pluginCode === localConfig().code}>
576
- </Show>
577
- </label>
578
- <input
579
- type="text"
580
- class="input input-bordered"
581
- placeholder="Enter plugin code"
582
- readonly
583
- value={httpConfig().pluginCode || ''}
584
- onInput={(e) => setHttpConfig(prev => ({ ...prev, pluginCode: e.target.value }))}
585
- />
586
- </div>
587
- </div>
588
- </Show>
589
- </div>
590
- </div>
591
-
592
- {/* Action Selection */}
593
- <div class="card bg-white shadow-professional">
594
- <div class="card-body p-6">
595
- <h3 class="text-lg font-semibold text-slate-900 mb-4">Select Action</h3>
596
-
597
- <Show when={pluginActions().length > 0}>
598
- <div class="flex flex-wrap gap-2">
599
- <For each={pluginActions()}>
600
- {(action) => (
601
- <button
602
- class={`btn btn-sm ${selectedAction() === action.name ? 'btn-primary' : 'btn-outline'}`}
603
- onClick={() => {
604
- setSelectedAction(action.name);
605
- loadActionParams(action.name);
606
- }}
607
- >
608
- {action.name}
609
- <span class="badge badge-outline badge-secondary badge-sm ml-2">{action.type}</span>
610
- </button>
611
- )}
612
- </For>
613
- </div>
614
- </Show>
615
-
616
- <Show when={pluginActions().length === 0}>
617
- <div class="flex flex-col items-center py-8 text-center">
618
- <InfoIcon class="w-8 h-8 text-slate-400 mb-2" />
619
- <p class="text-sm text-slate-600">No actions configured</p>
620
- </div>
621
- </Show>
622
- </div>
623
- </div>
624
-
625
- {/* HTTP Endpoint Reference */}
626
- <Show when={selectedAction()}>
627
- <div class="card bg-white shadow-professional">
628
- <div class="card-body p-6">
629
- <h3 class="text-lg font-semibold text-slate-900 mb-4">Endpoint Reference</h3>
630
-
631
- <div class="bg-slate-50 p-4 rounded-lg font-mono text-sm mb-4">
632
- <div class="flex items-center gap-2 mb-2">
633
- <span class="badge badge-primary badge-sm">POST</span>
634
- <span class="text-slate-700">
635
- {httpConfig().baseUrl || 'http://localhost:8000'}/plugins/{httpConfig().pluginCode || 'plugin_code'}/run/
636
- </span>
637
- </div>
638
-
639
- <div class="text-xs text-slate-600 space-y-1">
640
- <div><strong>Headers:</strong></div>
641
- <div class="ml-4">Content-Type: application/json</div>
642
- <div class="ml-4">Accept: application/json; indent=4</div>
643
- <Show when={httpConfig().accessToken}>
644
- <div class="ml-4">SYNAPSE-Access-Token: Token ••••••••</div>
645
- </Show>
646
-
647
- <div class="mt-2"><strong>Body Structure:</strong></div>
648
- <div class="ml-4">{"{"}</div>
649
- <div class="ml-6">"agent": 2,</div>
650
- <div class="ml-6">"action": "{selectedAction()}",</div>
651
- <div class="ml-6">"params": {"{"} ... {"}"}, </div>
652
- <div class="ml-6">"debug": true</div>
653
- <div class="ml-4">{"}"}</div>
654
- </div>
655
- </div>
656
- </div>
657
- </div>
658
- </Show>
659
-
660
- {/* HTTP Parameters */}
661
- <Show when={selectedAction()}>
662
- <div class="card bg-white shadow-professional">
663
- <div class="card-body p-6">
664
- <h3 class="text-lg font-semibold text-slate-900 mb-4">HTTP Parameters</h3>
665
-
666
- <div class="mb-3">
667
- <label class="label">
668
- <span class="label-text">Parameters (JSON)</span>
669
- <span class="label-text-alt">Will be sent as "params" in the request body</span>
670
- </label>
671
- </div>
672
-
673
- <textarea
674
- class="textarea textarea-bordered font-mono text-xs w-full"
675
- rows="8"
676
- placeholder="Enter JSON parameters..."
677
- value={httpParams()}
678
- onInput={(e) => setHttpParams(e.target.value)}
679
- />
680
-
681
- <div class="flex gap-2 mt-4">
682
- <button
683
- class="btn btn-sm btn-primary"
684
- onClick={executeHttpRequest}
685
- disabled={isExecuting() || !selectedAction()}
686
- >
687
- <Show when={!isExecuting()}>
688
- <PlayIcon class="w-4 h-4 mr-2" />
689
- </Show>
690
- <Show when={isExecuting()}>
691
- <div class="loading loading-spinner loading-sm mr-2"></div>
692
- </Show>
693
- {isExecuting() ? 'Executing...' : 'Execute HTTP Request'}
694
- </button>
695
- <button
696
- class="btn btn-sm btn-outline"
697
- onClick={() => loadActionParams(selectedAction())}
698
- disabled={!selectedAction()}
699
- >
700
- <RefreshIcon class="w-4 h-4 mr-2" />
701
- Load Example
702
- </button>
703
- <button class="btn btn-sm btn-outline" onClick={clearResults}>
704
- <TrashIcon class="w-4 h-4 mr-2" />
705
- Clear
706
- </button>
707
- </div>
708
- </div>
709
- </div>
710
- </Show>
711
-
712
- {/* Results */}
713
- <Show when={httpResults().length > 0}>
714
- <div class="space-y-4">
715
- <div class="flex items-center justify-between">
716
- <h3 class="text-lg font-semibold text-slate-900">Results</h3>
717
- <span class="badge badge-outline badge-secondary">{httpResults().length} result{httpResults().length > 1 ? 's' : ''}</span>
718
- </div>
719
-
720
- <For each={httpResults()}>
721
- {(result) => (
722
- <div class="card bg-white shadow-professional">
723
- <div class="border-b border-slate-200 bg-slate-50 px-6 py-3">
724
- <div class="flex items-center justify-between">
725
- <div class="flex items-center gap-2">
726
- <Show when={result.success}>
727
- <CheckIcon class="w-4 h-4 text-emerald-600" />
728
- </Show>
729
- <Show when={!result.success}>
730
- <AlertCircleIcon class="w-4 h-4 text-red-600" />
731
- </Show>
732
- <span class={`text-sm font-medium ${result.success ? 'text-emerald-700' : 'text-red-700'}`}>
733
- {result.success ? 'Success' : 'Failed'}
734
- </span>
735
- <span class="badge badge-outline badge-sm">{result.status_code}</span>
736
- </div>
737
- <div class="flex items-center gap-3 text-xs text-slate-600">
738
- <span>{result.execution_time}ms</span>
739
- <span>{formatTimestamp(result.timestamp)}</span>
740
- </div>
741
- </div>
742
- </div>
743
- <div class="p-6">
744
- <Show when={result.validation_errors}>
745
- <div class="mb-4">
746
- <h4 class="text-sm font-medium text-red-700 mb-2">Configuration Validation Errors:</h4>
747
- <div class="space-y-1">
748
- <For each={result.validation_errors}>
749
- {(error) => (
750
- <div class="flex items-start gap-2 text-sm text-red-600">
751
- <AlertTriangleIcon class="mt-0.5 h-3 w-3 flex-shrink-0" />
752
- <span>{error}</span>
753
- </div>
754
- )}
755
- </For>
756
- </div>
757
- </div>
758
- </Show>
759
- <pre class="overflow-auto rounded-md bg-slate-100 p-3 text-xs">
760
- {JSON.stringify(result.response_data || result.error, null, 2)}
761
- </pre>
762
- </div>
763
- </div>
764
- )}
765
- </For>
766
- </div>
767
- </Show>
768
- </div>
769
- </Show>
770
-
771
- {/* Deployment Tab */}
772
- <Show when={activeTab() === 'deployment'}>
773
- <div class="mt-6 space-y-4">
774
- <div class="card bg-white shadow-professional">
775
- <div class="card-body p-6">
776
- <h3 class="text-lg font-semibold text-slate-900 mb-4">Deployment Settings</h3>
777
-
778
- <div class="grid gap-4 md:grid-cols-2">
779
- <div class="form-control">
780
- <label class="label">
781
- <span class="label-text">Backend URL</span>
782
- </label>
783
- <input
784
- type="text"
785
- class="input input-bordered bg-slate-50"
786
- value={publishConfig().host || 'Not configured'}
787
- readonly
788
- />
789
- </div>
790
- <div class="form-control">
791
- <label class="label">
792
- <span class="label-text">Access Token</span>
793
- </label>
794
- <input
795
- type="password"
796
- class="input input-bordered bg-slate-50"
797
- value={publishConfig().accessToken ? '••••••••' : 'Not configured'}
798
- readonly
799
- />
800
- </div>
801
- <div class="form-control">
802
- <label class="label cursor-pointer">
803
- <span class="label-text">Enable Debug Mode</span>
804
- <input
805
- type="checkbox"
806
- class="toggle toggle-primary ml-2"
807
- checked={publishConfig().debug || false}
808
- onChange={(e) => setPublishConfig(prev => ({ ...prev, debug: e.target.checked }))}
809
- />
810
- </label>
811
- </div>
812
- <div class="form-control">
813
- <label class="label">
814
- <span class="label-text">Debug Modules</span>
815
- </label>
816
- <input
817
- type="text"
818
- class="input input-bordered"
819
- placeholder="module1,module2"
820
- value={publishConfig().debugModules || ''}
821
- onInput={(e) => setPublishConfig(prev => ({ ...prev, debugModules: e.target.value }))}
822
- />
823
- <label class="label">
824
- <span class="label-text-alt">Comma-separated list of debug modules (optional)</span>
825
- </label>
826
- </div>
827
- </div>
828
-
829
- <div class="mt-6 border-t border-slate-200 pt-6">
830
- <button
831
- class="btn btn-primary"
832
- onClick={publishPlugin}
833
- disabled={isPublishing() || !canPublish()}
834
- >
835
- <Show when={!isPublishing()}>
836
- <UploadIcon class="w-4 h-4 mr-2" />
837
- </Show>
838
- <Show when={isPublishing()}>
839
- <div class="loading loading-spinner loading-sm mr-2"></div>
840
- </Show>
841
- {isPublishing() ? 'Publishing...' : 'Publish Plugin'}
842
- </button>
843
- </div>
844
-
845
- {/* Publish Results */}
846
- <Show when={publishResult()}>
847
- <div class={`alert mt-6 ${publishResult().success ? 'alert-success' : 'alert-error'}`}>
848
- <Show when={publishResult().success}>
849
- <CheckCircleIcon class="w-4 h-4" />
850
- </Show>
851
- <Show when={!publishResult().success}>
852
- <AlertCircleIcon class="w-4 h-4" />
853
- </Show>
854
- <div class="flex-1">
855
- <h4 class="font-semibold">
856
- {publishResult().success ? 'Published Successfully' : 'Publication Failed'}
857
- </h4>
858
- <p class="text-sm">
859
- {publishResult().success ? publishResult().message : (publishResult().message || publishResult().error)}
860
- </p>
861
-
862
- {/* Show validation errors if they exist */}
863
- <Show when={!publishResult().success && publishResult().validation_errors}>
864
- <div class="mt-3">
865
- <h5 class="text-sm font-medium mb-2">Configuration Issues:</h5>
866
- <div class="space-y-1">
867
- <For each={publishResult().validation_errors}>
868
- {(error) => (
869
- <div class="flex items-start gap-2 text-xs">
870
- <AlertTriangleIcon class="mt-0.5 h-3 w-3 flex-shrink-0" />
871
- <span>{error}</span>
872
- </div>
873
- )}
874
- </For>
875
- </div>
876
- </div>
877
- </Show>
878
-
879
- <Show when={publishResult().success}>
880
- <div class="flex gap-4 mt-2 text-xs">
881
- <span>Plugin: {publishResult().plugin_code}</span>
882
- <span>Version: {publishResult().version}</span>
883
- <Show when={publishResult().name}>
884
- <span>Name: {publishResult().name}</span>
885
- </Show>
886
- </div>
887
- </Show>
888
- </div>
889
- </div>
890
- </Show>
891
- </div>
892
- </div>
893
- </div>
894
- </Show>
895
- </main>
896
- </Show>
897
-
898
- {/* Status Toast */}
899
- <Show when={saveMessage()}>
900
- <div class="toast toast-top toast-end">
901
- <div class={`alert ${saveMessageType() === 'success' ? 'alert-success' : 'alert-error'}`}>
902
- <Show when={saveMessageType() === 'success'}>
903
- <CheckIcon class="w-4 h-4" />
904
- </Show>
905
- <Show when={saveMessageType() === 'error'}>
906
- <AlertCircleIcon class="w-4 h-4" />
907
- </Show>
908
- <span>{saveMessage()}</span>
909
- </div>
910
- </div>
911
- </Show>
912
- </div>
913
- );
914
- }