flowyml 1.7.2__py3-none-any.whl → 1.8.0__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.
- flowyml/assets/base.py +15 -0
- flowyml/assets/metrics.py +5 -0
- flowyml/cli/main.py +709 -0
- flowyml/cli/stack_cli.py +138 -25
- flowyml/core/__init__.py +17 -0
- flowyml/core/executor.py +161 -26
- flowyml/core/image_builder.py +129 -0
- flowyml/core/log_streamer.py +227 -0
- flowyml/core/orchestrator.py +22 -2
- flowyml/core/pipeline.py +34 -10
- flowyml/core/routing.py +558 -0
- flowyml/core/step.py +9 -1
- flowyml/core/step_grouping.py +49 -35
- flowyml/core/types.py +407 -0
- flowyml/monitoring/alerts.py +10 -0
- flowyml/monitoring/notifications.py +104 -25
- flowyml/monitoring/slack_blocks.py +323 -0
- flowyml/plugins/__init__.py +251 -0
- flowyml/plugins/alerters/__init__.py +1 -0
- flowyml/plugins/alerters/slack.py +168 -0
- flowyml/plugins/base.py +752 -0
- flowyml/plugins/config.py +478 -0
- flowyml/plugins/deployers/__init__.py +22 -0
- flowyml/plugins/deployers/gcp_cloud_run.py +200 -0
- flowyml/plugins/deployers/sagemaker.py +306 -0
- flowyml/plugins/deployers/vertex.py +290 -0
- flowyml/plugins/integration.py +369 -0
- flowyml/plugins/manager.py +510 -0
- flowyml/plugins/model_registries/__init__.py +22 -0
- flowyml/plugins/model_registries/mlflow.py +159 -0
- flowyml/plugins/model_registries/sagemaker.py +489 -0
- flowyml/plugins/model_registries/vertex.py +386 -0
- flowyml/plugins/orchestrators/__init__.py +13 -0
- flowyml/plugins/orchestrators/sagemaker.py +443 -0
- flowyml/plugins/orchestrators/vertex_ai.py +461 -0
- flowyml/plugins/registries/__init__.py +13 -0
- flowyml/plugins/registries/ecr.py +321 -0
- flowyml/plugins/registries/gcr.py +313 -0
- flowyml/plugins/registry.py +454 -0
- flowyml/plugins/stack.py +494 -0
- flowyml/plugins/stack_config.py +537 -0
- flowyml/plugins/stores/__init__.py +13 -0
- flowyml/plugins/stores/gcs.py +460 -0
- flowyml/plugins/stores/s3.py +453 -0
- flowyml/plugins/trackers/__init__.py +11 -0
- flowyml/plugins/trackers/mlflow.py +316 -0
- flowyml/plugins/validators/__init__.py +3 -0
- flowyml/plugins/validators/deepchecks.py +119 -0
- flowyml/registry/__init__.py +2 -1
- flowyml/registry/model_environment.py +109 -0
- flowyml/registry/model_registry.py +241 -96
- flowyml/serving/__init__.py +17 -0
- flowyml/serving/model_server.py +628 -0
- flowyml/stacks/__init__.py +60 -0
- flowyml/stacks/aws.py +93 -0
- flowyml/stacks/base.py +62 -0
- flowyml/stacks/components.py +12 -0
- flowyml/stacks/gcp.py +44 -9
- flowyml/stacks/plugins.py +115 -0
- flowyml/stacks/registry.py +2 -1
- flowyml/storage/sql.py +401 -12
- flowyml/tracking/experiment.py +8 -5
- flowyml/ui/backend/Dockerfile +87 -16
- flowyml/ui/backend/auth.py +12 -2
- flowyml/ui/backend/main.py +149 -5
- flowyml/ui/backend/routers/ai_context.py +226 -0
- flowyml/ui/backend/routers/assets.py +23 -4
- flowyml/ui/backend/routers/auth.py +96 -0
- flowyml/ui/backend/routers/deployments.py +660 -0
- flowyml/ui/backend/routers/model_explorer.py +597 -0
- flowyml/ui/backend/routers/plugins.py +103 -51
- flowyml/ui/backend/routers/projects.py +91 -8
- flowyml/ui/backend/routers/runs.py +20 -1
- flowyml/ui/backend/routers/schedules.py +22 -17
- flowyml/ui/backend/routers/templates.py +319 -0
- flowyml/ui/backend/routers/websocket.py +2 -2
- flowyml/ui/frontend/Dockerfile +55 -6
- flowyml/ui/frontend/dist/assets/index-B5AsPTSz.css +1 -0
- flowyml/ui/frontend/dist/assets/index-dFbZ8wD8.js +753 -0
- flowyml/ui/frontend/dist/index.html +2 -2
- flowyml/ui/frontend/dist/logo.png +0 -0
- flowyml/ui/frontend/nginx.conf +65 -4
- flowyml/ui/frontend/package-lock.json +1404 -74
- flowyml/ui/frontend/package.json +3 -0
- flowyml/ui/frontend/public/logo.png +0 -0
- flowyml/ui/frontend/src/App.jsx +10 -7
- flowyml/ui/frontend/src/app/auth/Login.jsx +90 -0
- flowyml/ui/frontend/src/app/dashboard/page.jsx +8 -8
- flowyml/ui/frontend/src/app/deployments/page.jsx +786 -0
- flowyml/ui/frontend/src/app/model-explorer/page.jsx +1031 -0
- flowyml/ui/frontend/src/app/pipelines/page.jsx +12 -2
- flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectExperimentsList.jsx +19 -6
- flowyml/ui/frontend/src/app/runs/[runId]/page.jsx +36 -24
- flowyml/ui/frontend/src/app/runs/page.jsx +8 -2
- flowyml/ui/frontend/src/app/settings/page.jsx +267 -253
- flowyml/ui/frontend/src/components/AssetDetailsPanel.jsx +29 -7
- flowyml/ui/frontend/src/components/Layout.jsx +6 -0
- flowyml/ui/frontend/src/components/PipelineGraph.jsx +79 -29
- flowyml/ui/frontend/src/components/RunDetailsPanel.jsx +36 -6
- flowyml/ui/frontend/src/components/RunMetaPanel.jsx +113 -0
- flowyml/ui/frontend/src/components/ai/AIAssistantButton.jsx +71 -0
- flowyml/ui/frontend/src/components/ai/AIAssistantPanel.jsx +420 -0
- flowyml/ui/frontend/src/components/header/Header.jsx +22 -0
- flowyml/ui/frontend/src/components/plugins/PluginManager.jsx +4 -4
- flowyml/ui/frontend/src/components/plugins/{ZenMLIntegration.jsx → StackImport.jsx} +38 -12
- flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx +36 -13
- flowyml/ui/frontend/src/contexts/AIAssistantContext.jsx +245 -0
- flowyml/ui/frontend/src/contexts/AuthContext.jsx +108 -0
- flowyml/ui/frontend/src/hooks/useAIContext.js +156 -0
- flowyml/ui/frontend/src/hooks/useWebGPU.js +54 -0
- flowyml/ui/frontend/src/layouts/MainLayout.jsx +6 -0
- flowyml/ui/frontend/src/router/index.jsx +47 -20
- flowyml/ui/frontend/src/services/pluginService.js +3 -1
- flowyml/ui/server_manager.py +5 -5
- flowyml/ui/utils.py +157 -39
- flowyml/utils/config.py +37 -15
- flowyml/utils/model_introspection.py +123 -0
- flowyml/utils/observability.py +30 -0
- flowyml-1.8.0.dist-info/METADATA +174 -0
- {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/RECORD +123 -65
- {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/WHEEL +1 -1
- flowyml/ui/frontend/dist/assets/index-B40RsQDq.css +0 -1
- flowyml/ui/frontend/dist/assets/index-CjI0zKCn.js +0 -685
- flowyml-1.7.2.dist-info/METADATA +0 -477
- {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/entry_points.txt +0 -0
- {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,315 +1,329 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Settings as SettingsIcon,
|
|
4
|
+
Palette,
|
|
5
|
+
Bell,
|
|
6
|
+
Database,
|
|
7
|
+
Shield,
|
|
8
|
+
Globe,
|
|
9
|
+
Zap,
|
|
10
|
+
Clock,
|
|
11
|
+
Save,
|
|
12
|
+
RefreshCw,
|
|
13
|
+
CheckCircle2,
|
|
14
|
+
Moon,
|
|
15
|
+
Sun,
|
|
16
|
+
Monitor
|
|
17
|
+
} from 'lucide-react';
|
|
3
18
|
import { Card } from '../../components/ui/Card';
|
|
4
19
|
import { Button } from '../../components/ui/Button';
|
|
5
20
|
import { Badge } from '../../components/ui/Badge';
|
|
6
|
-
import { format } from 'date-fns';
|
|
7
21
|
|
|
8
22
|
export function Settings() {
|
|
9
|
-
const [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
23
|
+
const [settings, setSettings] = useState({
|
|
24
|
+
theme: 'system',
|
|
25
|
+
notificationsEnabled: true,
|
|
26
|
+
emailAlerts: false,
|
|
27
|
+
autoRefresh: true,
|
|
28
|
+
refreshInterval: 30,
|
|
29
|
+
timezone: 'auto',
|
|
30
|
+
dataRetention: 30,
|
|
31
|
+
artifactUpload: false,
|
|
32
|
+
debugMode: false
|
|
33
|
+
});
|
|
34
|
+
const [saved, setSaved] = useState(false);
|
|
35
|
+
const [serverInfo, setServerInfo] = useState(null);
|
|
15
36
|
|
|
16
37
|
useEffect(() => {
|
|
17
|
-
|
|
38
|
+
fetchServerInfo();
|
|
18
39
|
}, []);
|
|
19
40
|
|
|
20
|
-
const
|
|
41
|
+
const fetchServerInfo = async () => {
|
|
21
42
|
try {
|
|
22
|
-
const response = await fetch('/api/execution/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} finally {
|
|
28
|
-
setLoading(false);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const createToken = async (e) => {
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
try {
|
|
35
|
-
const response = await fetch('/api/execution/tokens', {
|
|
36
|
-
method: 'POST',
|
|
37
|
-
headers: { 'Content-Type': 'application/json' },
|
|
38
|
-
body: JSON.stringify({ name: newTokenName })
|
|
39
|
-
});
|
|
40
|
-
const data = await response.json();
|
|
41
|
-
setCreatedToken(data.token);
|
|
42
|
-
setNewTokenName('');
|
|
43
|
-
fetchTokens();
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error('Failed to create token:', error);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const deleteToken = async (tokenId) => {
|
|
50
|
-
if (!confirm('Are you sure you want to delete this token? This action cannot be undone.')) return;
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
await fetch(`/api/execution/tokens/${tokenId}`, {
|
|
54
|
-
method: 'DELETE'
|
|
55
|
-
});
|
|
56
|
-
fetchTokens();
|
|
43
|
+
const response = await fetch('/api/execution/info');
|
|
44
|
+
if (response.ok) {
|
|
45
|
+
const data = await response.json();
|
|
46
|
+
setServerInfo(data);
|
|
47
|
+
}
|
|
57
48
|
} catch (error) {
|
|
58
|
-
console.error('Failed to
|
|
49
|
+
console.error('Failed to fetch server info:', error);
|
|
59
50
|
}
|
|
60
51
|
};
|
|
61
52
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
const handleSettingChange = (key, value) => {
|
|
54
|
+
setSettings(prev => ({ ...prev, [key]: value }));
|
|
55
|
+
setSaved(false);
|
|
65
56
|
};
|
|
66
57
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
} else {
|
|
73
|
-
newSet.add(tokenId);
|
|
74
|
-
}
|
|
75
|
-
return newSet;
|
|
76
|
-
});
|
|
58
|
+
const saveSettings = () => {
|
|
59
|
+
// In a real app, this would save to the backend
|
|
60
|
+
localStorage.setItem('flowyml_settings', JSON.stringify(settings));
|
|
61
|
+
setSaved(true);
|
|
62
|
+
setTimeout(() => setSaved(false), 3000);
|
|
77
63
|
};
|
|
78
64
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
65
|
+
const ThemeButton = ({ theme, icon: Icon, label }) => (
|
|
66
|
+
<button
|
|
67
|
+
onClick={() => handleSettingChange('theme', theme)}
|
|
68
|
+
className={`flex flex-col items-center justify-center p-4 rounded-xl border-2 transition-all ${settings.theme === theme
|
|
69
|
+
? 'border-primary-500 bg-primary-50 dark:bg-primary-900/20'
|
|
70
|
+
: 'border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-600'
|
|
71
|
+
}`}
|
|
72
|
+
>
|
|
73
|
+
<Icon size={24} className={settings.theme === theme ? 'text-primary-600' : 'text-slate-500'} />
|
|
74
|
+
<span className={`mt-2 text-sm font-medium ${settings.theme === theme ? 'text-primary-600' : 'text-slate-600 dark:text-slate-400'
|
|
75
|
+
}`}>
|
|
76
|
+
{label}
|
|
77
|
+
</span>
|
|
78
|
+
</button>
|
|
79
|
+
);
|
|
91
80
|
|
|
92
81
|
return (
|
|
93
|
-
<div className="p-6 max-w-
|
|
82
|
+
<div className="p-6 max-w-4xl mx-auto space-y-6">
|
|
94
83
|
{/* Header */}
|
|
95
84
|
<div className="flex items-center justify-between">
|
|
96
85
|
<div>
|
|
97
86
|
<h1 className="text-3xl font-bold text-slate-900 dark:text-white flex items-center gap-3">
|
|
98
|
-
<div className="p-3 bg-gradient-to-br from-
|
|
99
|
-
<
|
|
87
|
+
<div className="p-3 bg-gradient-to-br from-slate-600 to-slate-800 rounded-xl text-white">
|
|
88
|
+
<SettingsIcon size={28} />
|
|
100
89
|
</div>
|
|
101
|
-
|
|
90
|
+
Settings
|
|
102
91
|
</h1>
|
|
103
92
|
<p className="text-slate-500 dark:text-slate-400 mt-2">
|
|
104
|
-
|
|
93
|
+
Configure your FlowyML dashboard preferences
|
|
105
94
|
</p>
|
|
106
95
|
</div>
|
|
107
96
|
<Button
|
|
108
|
-
onClick={
|
|
97
|
+
onClick={saveSettings}
|
|
109
98
|
className="flex items-center gap-2 bg-gradient-to-r from-primary-600 to-purple-600 hover:from-primary-700 hover:to-purple-700"
|
|
110
99
|
>
|
|
111
|
-
<
|
|
112
|
-
|
|
100
|
+
{saved ? <CheckCircle2 size={16} /> : <Save size={16} />}
|
|
101
|
+
{saved ? 'Saved!' : 'Save Settings'}
|
|
113
102
|
</Button>
|
|
114
103
|
</div>
|
|
115
104
|
|
|
116
|
-
{/*
|
|
117
|
-
<Card
|
|
118
|
-
<div className="flex items-
|
|
119
|
-
<
|
|
105
|
+
{/* Appearance */}
|
|
106
|
+
<Card>
|
|
107
|
+
<div className="flex items-center gap-3 mb-6">
|
|
108
|
+
<div className="p-2 bg-purple-100 dark:bg-purple-900/20 rounded-lg">
|
|
109
|
+
<Palette className="text-purple-600 dark:text-purple-400" size={20} />
|
|
110
|
+
</div>
|
|
120
111
|
<div>
|
|
121
|
-
<
|
|
122
|
-
<p className="text-sm text-
|
|
123
|
-
Treat your API tokens like passwords. Never share them publicly or commit them to version control.
|
|
124
|
-
</p>
|
|
112
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Appearance</h2>
|
|
113
|
+
<p className="text-sm text-slate-500 dark:text-slate-400">Customize the look and feel</p>
|
|
125
114
|
</div>
|
|
126
115
|
</div>
|
|
127
|
-
</Card>
|
|
128
116
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
</div>
|
|
136
|
-
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-2">No API tokens yet</h3>
|
|
137
|
-
<p className="text-slate-500 max-w-md mx-auto mb-6">
|
|
138
|
-
Create your first API token to start making programmatic requests to flowyml
|
|
139
|
-
</p>
|
|
140
|
-
<Button
|
|
141
|
-
onClick={() => setShowCreateModal(true)}
|
|
142
|
-
className="bg-primary-600 hover:bg-primary-700"
|
|
143
|
-
>
|
|
144
|
-
<Plus size={16} className="mr-2" />
|
|
145
|
-
Create Your First Token
|
|
146
|
-
</Button>
|
|
147
|
-
</Card>
|
|
148
|
-
) : (
|
|
149
|
-
Array.isArray(tokens) && tokens.map((token) => (
|
|
150
|
-
<Card key={token.id} className="hover:shadow-lg transition-all duration-200">
|
|
151
|
-
<div className="flex items-center justify-between gap-4">
|
|
152
|
-
<div className="flex-1 min-w-0">
|
|
153
|
-
<div className="flex items-center gap-3 mb-3">
|
|
154
|
-
<div className="p-2 bg-primary-50 dark:bg-primary-900/20 rounded-lg">
|
|
155
|
-
<Key className="text-primary-600 dark:text-primary-400" size={20} />
|
|
156
|
-
</div>
|
|
157
|
-
<div className="flex-1 min-w-0">
|
|
158
|
-
<h3 className="text-lg font-semibold text-slate-900 dark:text-white truncate">
|
|
159
|
-
{token.name}
|
|
160
|
-
</h3>
|
|
161
|
-
<div className="flex items-center gap-2 flex-wrap">
|
|
162
|
-
<span className="text-xs text-slate-500 dark:text-slate-400 flex items-center gap-1">
|
|
163
|
-
<Calendar size={12} />
|
|
164
|
-
Created {format(new Date(token.created_at), 'MMM d, yyyy')}
|
|
165
|
-
</span>
|
|
166
|
-
<Badge variant="secondary" className="text-xs">
|
|
167
|
-
{token.id}
|
|
168
|
-
</Badge>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
117
|
+
<div className="grid grid-cols-3 gap-4">
|
|
118
|
+
<ThemeButton theme="light" icon={Sun} label="Light" />
|
|
119
|
+
<ThemeButton theme="dark" icon={Moon} label="Dark" />
|
|
120
|
+
<ThemeButton theme="system" icon={Monitor} label="System" />
|
|
121
|
+
</div>
|
|
122
|
+
</Card>
|
|
172
123
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
>
|
|
185
|
-
{visibleTokens.has(token.id) ? (
|
|
186
|
-
<EyeOff size={16} className="text-slate-500" />
|
|
187
|
-
) : (
|
|
188
|
-
<Eye size={16} className="text-slate-500" />
|
|
189
|
-
)}
|
|
190
|
-
</button>
|
|
191
|
-
<button
|
|
192
|
-
onClick={() => copyToClipboard(token.token)}
|
|
193
|
-
className="p-1.5 hover:bg-slate-200 dark:hover:bg-slate-700 rounded transition-colors"
|
|
194
|
-
title="Copy to clipboard"
|
|
195
|
-
>
|
|
196
|
-
<Copy size={16} className="text-slate-500" />
|
|
197
|
-
</button>
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
124
|
+
{/* Notifications */}
|
|
125
|
+
<Card>
|
|
126
|
+
<div className="flex items-center gap-3 mb-6">
|
|
127
|
+
<div className="p-2 bg-blue-100 dark:bg-blue-900/20 rounded-lg">
|
|
128
|
+
<Bell className="text-blue-600 dark:text-blue-400" size={20} />
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Notifications</h2>
|
|
132
|
+
<p className="text-sm text-slate-500 dark:text-slate-400">Manage alert preferences</p>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
202
135
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
</Button>
|
|
136
|
+
<div className="space-y-4">
|
|
137
|
+
<label className="flex items-center justify-between cursor-not-allowed opacity-60">
|
|
138
|
+
<div>
|
|
139
|
+
<div className="font-medium text-slate-900 dark:text-white flex items-center gap-2">
|
|
140
|
+
Push Notifications
|
|
141
|
+
<Badge variant="secondary" className="text-xs">Coming Soon</Badge>
|
|
210
142
|
</div>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<h2 className="text-2xl font-bold text-slate-900 dark:text-white mb-4 flex items-center gap-2">
|
|
221
|
-
<Plus className="text-primary-600" size={24} />
|
|
222
|
-
Create New Token
|
|
223
|
-
</h2>
|
|
143
|
+
<div className="text-sm text-slate-500">Get notified about pipeline completions</div>
|
|
144
|
+
</div>
|
|
145
|
+
<input
|
|
146
|
+
type="checkbox"
|
|
147
|
+
checked={settings.notificationsEnabled}
|
|
148
|
+
disabled
|
|
149
|
+
className="w-5 h-5 rounded text-slate-400 cursor-not-allowed"
|
|
150
|
+
/>
|
|
151
|
+
</label>
|
|
224
152
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
</
|
|
230
|
-
<input
|
|
231
|
-
type="text"
|
|
232
|
-
value={newTokenName}
|
|
233
|
-
onChange={(e) => setNewTokenName(e.target.value)}
|
|
234
|
-
placeholder="e.g., Production API, CI/CD Pipeline"
|
|
235
|
-
className="w-full px-4 py-2 border border-slate-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-slate-800 text-slate-900 dark:text-white"
|
|
236
|
-
required
|
|
237
|
-
/>
|
|
238
|
-
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1">
|
|
239
|
-
Choose a descriptive name to identify this token's purpose
|
|
240
|
-
</p>
|
|
153
|
+
<label className="flex items-center justify-between cursor-not-allowed opacity-60">
|
|
154
|
+
<div>
|
|
155
|
+
<div className="font-medium text-slate-900 dark:text-white flex items-center gap-2">
|
|
156
|
+
Email Alerts
|
|
157
|
+
<Badge variant="secondary" className="text-xs">Coming Soon</Badge>
|
|
241
158
|
</div>
|
|
159
|
+
<div className="text-sm text-slate-500">Receive email for failed pipelines</div>
|
|
160
|
+
</div>
|
|
161
|
+
<input
|
|
162
|
+
type="checkbox"
|
|
163
|
+
checked={settings.emailAlerts}
|
|
164
|
+
disabled
|
|
165
|
+
className="w-5 h-5 rounded text-slate-400 cursor-not-allowed"
|
|
166
|
+
/>
|
|
167
|
+
</label>
|
|
168
|
+
</div>
|
|
169
|
+
</Card>
|
|
242
170
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
className="bg-primary-600 hover:bg-primary-700"
|
|
254
|
-
>
|
|
255
|
-
Create Token
|
|
256
|
-
</Button>
|
|
257
|
-
</div>
|
|
258
|
-
</form>
|
|
259
|
-
</Card>
|
|
171
|
+
{/* Data & Storage */}
|
|
172
|
+
<Card>
|
|
173
|
+
<div className="flex items-center gap-3 mb-6">
|
|
174
|
+
<div className="p-2 bg-green-100 dark:bg-green-900/20 rounded-lg">
|
|
175
|
+
<Database className="text-green-600 dark:text-green-400" size={20} />
|
|
176
|
+
</div>
|
|
177
|
+
<div>
|
|
178
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Data & Storage</h2>
|
|
179
|
+
<p className="text-sm text-slate-500 dark:text-slate-400">Configure data handling</p>
|
|
180
|
+
</div>
|
|
260
181
|
</div>
|
|
261
|
-
)}
|
|
262
182
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
<CheckCircle2 className="text-green-600 dark:text-green-400" size={32} />
|
|
183
|
+
<div className="space-y-4">
|
|
184
|
+
<label className="flex items-center justify-between cursor-not-allowed opacity-60">
|
|
185
|
+
<div>
|
|
186
|
+
<div className="font-medium text-slate-900 dark:text-white flex items-center gap-2">
|
|
187
|
+
Auto-upload Artifacts
|
|
188
|
+
<Badge variant="secondary" className="text-xs">Coming Soon</Badge>
|
|
270
189
|
</div>
|
|
271
|
-
<
|
|
272
|
-
<p className="text-slate-500 dark:text-slate-400 mt-2">
|
|
273
|
-
Copy this token now. You won't be able to see it again.
|
|
274
|
-
</p>
|
|
190
|
+
<div className="text-sm text-slate-500">Automatically upload artifacts to remote storage</div>
|
|
275
191
|
</div>
|
|
192
|
+
<input
|
|
193
|
+
type="checkbox"
|
|
194
|
+
checked={settings.artifactUpload}
|
|
195
|
+
disabled
|
|
196
|
+
className="w-5 h-5 rounded text-slate-400 cursor-not-allowed"
|
|
197
|
+
/>
|
|
198
|
+
</label>
|
|
276
199
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
title="Copy to clipboard"
|
|
286
|
-
>
|
|
287
|
-
<Copy size={18} />
|
|
288
|
-
</button>
|
|
200
|
+
<div className="opacity-60">
|
|
201
|
+
<div className="flex items-center justify-between mb-2">
|
|
202
|
+
<div>
|
|
203
|
+
<div className="font-medium text-slate-900 dark:text-white flex items-center gap-2">
|
|
204
|
+
Data Retention
|
|
205
|
+
<Badge variant="secondary" className="text-xs">Coming Soon</Badge>
|
|
206
|
+
</div>
|
|
207
|
+
<div className="text-sm text-slate-500">Days to keep run history</div>
|
|
289
208
|
</div>
|
|
209
|
+
<Badge variant="secondary">{settings.dataRetention} days</Badge>
|
|
210
|
+
</div>
|
|
211
|
+
<input
|
|
212
|
+
type="range"
|
|
213
|
+
min="7"
|
|
214
|
+
max="365"
|
|
215
|
+
value={settings.dataRetention}
|
|
216
|
+
disabled
|
|
217
|
+
className="w-full h-2 bg-slate-200 dark:bg-slate-700 rounded-lg appearance-none cursor-not-allowed"
|
|
218
|
+
/>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
</Card>
|
|
222
|
+
|
|
223
|
+
{/* Performance */}
|
|
224
|
+
<Card>
|
|
225
|
+
<div className="flex items-center gap-3 mb-6">
|
|
226
|
+
<div className="p-2 bg-amber-100 dark:bg-amber-900/20 rounded-lg">
|
|
227
|
+
<Zap className="text-amber-600 dark:text-amber-400" size={20} />
|
|
228
|
+
</div>
|
|
229
|
+
<div>
|
|
230
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Performance</h2>
|
|
231
|
+
<p className="text-sm text-slate-500 dark:text-slate-400">Dashboard behavior settings</p>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div className="space-y-4">
|
|
236
|
+
<label className="flex items-center justify-between cursor-pointer">
|
|
237
|
+
<div>
|
|
238
|
+
<div className="font-medium text-slate-900 dark:text-white">Auto-refresh Data</div>
|
|
239
|
+
<div className="text-sm text-slate-500">Automatically refresh dashboard data</div>
|
|
290
240
|
</div>
|
|
241
|
+
<input
|
|
242
|
+
type="checkbox"
|
|
243
|
+
checked={settings.autoRefresh}
|
|
244
|
+
onChange={(e) => handleSettingChange('autoRefresh', e.target.checked)}
|
|
245
|
+
className="w-5 h-5 rounded text-primary-600 focus:ring-primary-500"
|
|
246
|
+
/>
|
|
247
|
+
</label>
|
|
291
248
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
<div
|
|
296
|
-
<
|
|
249
|
+
{settings.autoRefresh && (
|
|
250
|
+
<div>
|
|
251
|
+
<div className="flex items-center justify-between mb-2">
|
|
252
|
+
<div>
|
|
253
|
+
<div className="font-medium text-slate-900 dark:text-white">Refresh Interval</div>
|
|
254
|
+
<div className="text-sm text-slate-500">Seconds between refreshes</div>
|
|
297
255
|
</div>
|
|
256
|
+
<Badge variant="secondary">{settings.refreshInterval}s</Badge>
|
|
298
257
|
</div>
|
|
258
|
+
<input
|
|
259
|
+
type="range"
|
|
260
|
+
min="10"
|
|
261
|
+
max="120"
|
|
262
|
+
step="10"
|
|
263
|
+
value={settings.refreshInterval}
|
|
264
|
+
onChange={(e) => handleSettingChange('refreshInterval', parseInt(e.target.value))}
|
|
265
|
+
className="w-full h-2 bg-slate-200 dark:bg-slate-700 rounded-lg appearance-none cursor-pointer"
|
|
266
|
+
/>
|
|
299
267
|
</div>
|
|
268
|
+
)}
|
|
300
269
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
270
|
+
<label className="flex items-center justify-between cursor-pointer">
|
|
271
|
+
<div>
|
|
272
|
+
<div className="font-medium text-slate-900 dark:text-white">Debug Mode</div>
|
|
273
|
+
<div className="text-sm text-slate-500">Show verbose logging in console</div>
|
|
274
|
+
</div>
|
|
275
|
+
<input
|
|
276
|
+
type="checkbox"
|
|
277
|
+
checked={settings.debugMode}
|
|
278
|
+
onChange={(e) => handleSettingChange('debugMode', e.target.checked)}
|
|
279
|
+
className="w-5 h-5 rounded text-primary-600 focus:ring-primary-500"
|
|
280
|
+
/>
|
|
281
|
+
</label>
|
|
311
282
|
</div>
|
|
312
|
-
|
|
283
|
+
</Card>
|
|
284
|
+
|
|
285
|
+
{/* Server Info */}
|
|
286
|
+
<Card className="bg-slate-50 dark:bg-slate-800/50">
|
|
287
|
+
<div className="flex items-center gap-3 mb-6">
|
|
288
|
+
<div className="p-2 bg-slate-200 dark:bg-slate-700 rounded-lg">
|
|
289
|
+
<Globe className="text-slate-600 dark:text-slate-400" size={20} />
|
|
290
|
+
</div>
|
|
291
|
+
<div>
|
|
292
|
+
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">Server Information</h2>
|
|
293
|
+
<p className="text-sm text-slate-500 dark:text-slate-400">FlowyML backend details</p>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<div className="grid grid-cols-2 gap-4 text-sm">
|
|
298
|
+
<div>
|
|
299
|
+
<div className="text-slate-500 dark:text-slate-400">Version</div>
|
|
300
|
+
<div className="font-medium text-slate-900 dark:text-white">{serverInfo?.version || '0.1.0'}</div>
|
|
301
|
+
</div>
|
|
302
|
+
<div>
|
|
303
|
+
<div className="text-slate-500 dark:text-slate-400">Environment</div>
|
|
304
|
+
<div className="font-medium text-slate-900 dark:text-white">{serverInfo?.environment || 'Development'}</div>
|
|
305
|
+
</div>
|
|
306
|
+
<div>
|
|
307
|
+
<div className="text-slate-500 dark:text-slate-400">Database</div>
|
|
308
|
+
<div className="font-medium text-slate-900 dark:text-white">{serverInfo?.database || 'PostgreSQL'}</div>
|
|
309
|
+
</div>
|
|
310
|
+
<div>
|
|
311
|
+
<div className="text-slate-500 dark:text-slate-400">Uptime</div>
|
|
312
|
+
<div className="font-medium text-slate-900 dark:text-white">{serverInfo?.uptime || 'N/A'}</div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
</Card>
|
|
316
|
+
|
|
317
|
+
{/* Footer Branding */}
|
|
318
|
+
<div className="text-center pt-8 pb-4 border-t border-slate-200 dark:border-slate-700">
|
|
319
|
+
<div className="flex items-center justify-center gap-2 text-slate-500 dark:text-slate-400">
|
|
320
|
+
<span className="text-sm">Made with ❤️ by</span>
|
|
321
|
+
<span className="font-semibold text-primary-600 dark:text-primary-400">UnicoLab</span>
|
|
322
|
+
</div>
|
|
323
|
+
<p className="text-xs text-slate-400 dark:text-slate-500 mt-1">
|
|
324
|
+
FlowyML - Next-generation MLOps Platform
|
|
325
|
+
</p>
|
|
326
|
+
</div>
|
|
313
327
|
</div>
|
|
314
328
|
);
|
|
315
329
|
}
|