synapse-sdk 1.0.0a98__py3-none-any.whl → 1.0.0b2__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.
- synapse_sdk/cli/__init__.py +139 -84
- synapse_sdk/cli/code_server.py +169 -0
- synapse_sdk/cli/config.py +105 -4
- synapse_sdk/cli/devtools.py +54 -34
- synapse_sdk/clients/base.py +3 -4
- synapse_sdk/devtools/server.py +24 -791
- synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
- synapse_sdk/devtools/streamlit_app/app.py +128 -0
- synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
- synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
- synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
- synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
- synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
- synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
- synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
- synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
- synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
- synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
- synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
- synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
- synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
- synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
- synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
- synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
- synapse_sdk/devtools/streamlit_app.py +10 -0
- synapse_sdk/plugins/categories/upload/actions/upload.py +2 -1
- synapse_sdk/utils/converters/coco/from_dm.py +2 -2
- synapse_sdk/utils/converters/dm/__init__.py +0 -1
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.dist-info}/METADATA +4 -6
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.dist-info}/RECORD +34 -45
- synapse_sdk/devtools/models.py +0 -55
- synapse_sdk/devtools/utils.py +0 -52
- synapse_sdk/devtools/web/.gitignore +0 -2
- synapse_sdk/devtools/web/README.md +0 -34
- synapse_sdk/devtools/web/dist/index.html +0 -17
- synapse_sdk/devtools/web/index.html +0 -16
- synapse_sdk/devtools/web/jsconfig.json +0 -15
- synapse_sdk/devtools/web/package-lock.json +0 -2609
- synapse_sdk/devtools/web/package.json +0 -27
- synapse_sdk/devtools/web/pnpm-lock.yaml +0 -1055
- synapse_sdk/devtools/web/src/App.jsx +0 -14
- synapse_sdk/devtools/web/src/App.module.css +0 -33
- synapse_sdk/devtools/web/src/assets/favicon.ico +0 -0
- synapse_sdk/devtools/web/src/components/Breadcrumbs.jsx +0 -42
- synapse_sdk/devtools/web/src/components/Layout.jsx +0 -12
- synapse_sdk/devtools/web/src/components/LogViewer.jsx +0 -280
- synapse_sdk/devtools/web/src/components/MessageViewer.jsx +0 -150
- synapse_sdk/devtools/web/src/components/NavigationSidebar.jsx +0 -128
- synapse_sdk/devtools/web/src/components/ServerStatusBar.jsx +0 -245
- synapse_sdk/devtools/web/src/components/icons.jsx +0 -325
- synapse_sdk/devtools/web/src/index.css +0 -470
- synapse_sdk/devtools/web/src/index.jsx +0 -15
- synapse_sdk/devtools/web/src/logo.svg +0 -1
- synapse_sdk/devtools/web/src/router.jsx +0 -34
- synapse_sdk/devtools/web/src/utils/api.js +0 -442
- synapse_sdk/devtools/web/src/views/ApplicationDetailView.jsx +0 -241
- synapse_sdk/devtools/web/src/views/ApplicationsView.jsx +0 -224
- synapse_sdk/devtools/web/src/views/HomeView.jsx +0 -197
- synapse_sdk/devtools/web/src/views/JobDetailView.jsx +0 -310
- synapse_sdk/devtools/web/src/views/PluginView.jsx +0 -914
- synapse_sdk/devtools/web/vite.config.js +0 -13
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0a98.dist-info → synapse_sdk-1.0.0b2.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
|
-
}
|