@auxiora/dashboard 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/router.d.ts.map +1 -1
  2. package/dist/router.js +195 -49
  3. package/dist/router.js.map +1 -1
  4. package/dist/types.d.ts +66 -0
  5. package/dist/types.d.ts.map +1 -1
  6. package/dist/types.js.map +1 -1
  7. package/package.json +10 -4
  8. package/dist-ui/assets/index-BfY0i5jw.css +0 -1
  9. package/dist-ui/assets/index-CXpk9mvw.js +0 -60
  10. package/dist-ui/icon.svg +0 -59
  11. package/dist-ui/index.html +0 -20
  12. package/src/auth.ts +0 -83
  13. package/src/cloud-types.ts +0 -63
  14. package/src/index.ts +0 -5
  15. package/src/router.ts +0 -2494
  16. package/src/types.ts +0 -269
  17. package/tests/auth.test.ts +0 -51
  18. package/tests/cloud-router.test.ts +0 -249
  19. package/tests/desktop-router.test.ts +0 -151
  20. package/tests/router.test.ts +0 -388
  21. package/tests/trust-router.test.ts +0 -170
  22. package/tsconfig.json +0 -12
  23. package/tsconfig.tsbuildinfo +0 -1
  24. package/ui/index.html +0 -19
  25. package/ui/node_modules/.bin/browserslist +0 -17
  26. package/ui/node_modules/.bin/tsc +0 -17
  27. package/ui/node_modules/.bin/tsserver +0 -17
  28. package/ui/node_modules/.bin/vite +0 -17
  29. package/ui/package.json +0 -23
  30. package/ui/public/icon.svg +0 -59
  31. package/ui/src/App.tsx +0 -63
  32. package/ui/src/api.ts +0 -238
  33. package/ui/src/components/ActivityFeed.tsx +0 -123
  34. package/ui/src/components/BehaviorHealth.tsx +0 -105
  35. package/ui/src/components/DataTable.tsx +0 -39
  36. package/ui/src/components/Layout.tsx +0 -160
  37. package/ui/src/components/PasswordStrength.tsx +0 -31
  38. package/ui/src/components/SetupProgress.tsx +0 -26
  39. package/ui/src/components/StatusBadge.tsx +0 -12
  40. package/ui/src/components/ThemeSelector.tsx +0 -39
  41. package/ui/src/contexts/ThemeContext.tsx +0 -58
  42. package/ui/src/hooks/useApi.ts +0 -19
  43. package/ui/src/hooks/usePolling.ts +0 -8
  44. package/ui/src/main.tsx +0 -16
  45. package/ui/src/pages/AuditLog.tsx +0 -36
  46. package/ui/src/pages/Behaviors.tsx +0 -426
  47. package/ui/src/pages/Chat.tsx +0 -688
  48. package/ui/src/pages/Login.tsx +0 -64
  49. package/ui/src/pages/Overview.tsx +0 -56
  50. package/ui/src/pages/Sessions.tsx +0 -26
  51. package/ui/src/pages/SettingsAmbient.tsx +0 -185
  52. package/ui/src/pages/SettingsConnections.tsx +0 -201
  53. package/ui/src/pages/SettingsNotifications.tsx +0 -241
  54. package/ui/src/pages/SetupAppearance.tsx +0 -45
  55. package/ui/src/pages/SetupChannels.tsx +0 -143
  56. package/ui/src/pages/SetupComplete.tsx +0 -31
  57. package/ui/src/pages/SetupConnections.tsx +0 -80
  58. package/ui/src/pages/SetupDashboardPassword.tsx +0 -50
  59. package/ui/src/pages/SetupIdentity.tsx +0 -68
  60. package/ui/src/pages/SetupPersonality.tsx +0 -78
  61. package/ui/src/pages/SetupProvider.tsx +0 -65
  62. package/ui/src/pages/SetupVault.tsx +0 -50
  63. package/ui/src/pages/SetupWelcome.tsx +0 -19
  64. package/ui/src/pages/UnlockVault.tsx +0 -56
  65. package/ui/src/pages/Webhooks.tsx +0 -158
  66. package/ui/src/pages/settings/Appearance.tsx +0 -63
  67. package/ui/src/pages/settings/Channels.tsx +0 -138
  68. package/ui/src/pages/settings/Identity.tsx +0 -61
  69. package/ui/src/pages/settings/Personality.tsx +0 -54
  70. package/ui/src/pages/settings/PersonalityEditor.tsx +0 -577
  71. package/ui/src/pages/settings/Provider.tsx +0 -537
  72. package/ui/src/pages/settings/Security.tsx +0 -111
  73. package/ui/src/styles/global.css +0 -2308
  74. package/ui/src/styles/themes/index.css +0 -7
  75. package/ui/src/styles/themes/monolith.css +0 -125
  76. package/ui/src/styles/themes/nebula.css +0 -90
  77. package/ui/src/styles/themes/neon.css +0 -149
  78. package/ui/src/styles/themes/polar.css +0 -151
  79. package/ui/src/styles/themes/signal.css +0 -163
  80. package/ui/src/styles/themes/terra.css +0 -146
  81. package/ui/tsconfig.json +0 -14
  82. package/ui/vite.config.ts +0 -20
@@ -1,241 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { useApi } from '../hooks/useApi.js';
3
- import { api } from '../api.js';
4
-
5
- interface NotificationPreferences {
6
- dnd: {
7
- enabled: boolean;
8
- schedule: { start: string; end: string };
9
- };
10
- urgencyKeywords: string[];
11
- sources: {
12
- email: boolean;
13
- calendar: boolean;
14
- github: boolean;
15
- };
16
- soundEnabled: boolean;
17
- }
18
-
19
- interface Notification {
20
- id: string;
21
- title: string;
22
- body: string;
23
- source: string;
24
- timestamp: number;
25
- }
26
-
27
- const DEFAULT_PREFS: NotificationPreferences = {
28
- dnd: {
29
- enabled: false,
30
- schedule: { start: '22:00', end: '08:00' },
31
- },
32
- urgencyKeywords: [],
33
- sources: {
34
- email: true,
35
- calendar: true,
36
- github: true,
37
- },
38
- soundEnabled: true,
39
- };
40
-
41
- export function SettingsNotifications() {
42
- const { data: prefsData, loading: fetchingPrefs } = useApi(() => api.getNotificationPreferences(), []);
43
- const { data: notifsData, loading: fetchingNotifs } = useApi(() => api.getNotifications(), []);
44
- const [prefs, setPrefs] = useState<NotificationPreferences>(DEFAULT_PREFS);
45
- const [notifications, setNotifications] = useState<Notification[]>([]);
46
- const [saving, setSaving] = useState(false);
47
- const [success, setSuccess] = useState('');
48
- const [error, setError] = useState('');
49
- const [keywordsText, setKeywordsText] = useState('');
50
-
51
- useEffect(() => {
52
- if (prefsData?.data && Object.keys(prefsData.data).length > 0) {
53
- const d = prefsData.data;
54
- const merged: NotificationPreferences = {
55
- dnd: {
56
- enabled: d.dnd?.enabled ?? DEFAULT_PREFS.dnd.enabled,
57
- schedule: {
58
- start: d.dnd?.schedule?.start ?? DEFAULT_PREFS.dnd.schedule.start,
59
- end: d.dnd?.schedule?.end ?? DEFAULT_PREFS.dnd.schedule.end,
60
- },
61
- },
62
- urgencyKeywords: d.urgencyKeywords ?? DEFAULT_PREFS.urgencyKeywords,
63
- sources: {
64
- email: d.sources?.email ?? DEFAULT_PREFS.sources.email,
65
- calendar: d.sources?.calendar ?? DEFAULT_PREFS.sources.calendar,
66
- github: d.sources?.github ?? DEFAULT_PREFS.sources.github,
67
- },
68
- soundEnabled: d.soundEnabled ?? DEFAULT_PREFS.soundEnabled,
69
- };
70
- setPrefs(merged);
71
- setKeywordsText((merged.urgencyKeywords || []).join(', '));
72
- }
73
- }, [prefsData]);
74
-
75
- useEffect(() => {
76
- if (notifsData?.data) {
77
- setNotifications(notifsData.data);
78
- }
79
- }, [notifsData]);
80
-
81
- const handleSave = async () => {
82
- setSaving(true);
83
- setError('');
84
- setSuccess('');
85
- try {
86
- const keywords = keywordsText
87
- .split(',')
88
- .map(k => k.trim())
89
- .filter(Boolean);
90
- await api.updateNotificationPreferences({ ...prefs, urgencyKeywords: keywords });
91
- setSuccess('Notification settings saved successfully');
92
- } catch (err: unknown) {
93
- setError(err instanceof Error ? err.message : 'Failed to save settings');
94
- } finally {
95
- setSaving(false);
96
- }
97
- };
98
-
99
- const handleDismiss = async (id: string) => {
100
- try {
101
- await api.dismissNotification(id);
102
- setNotifications(prev => prev.filter(n => n.id !== id));
103
- } catch {
104
- // ignore
105
- }
106
- };
107
-
108
- if (fetchingPrefs || fetchingNotifs) return null;
109
-
110
- return (
111
- <div className="page">
112
- <h2>Notification Settings</h2>
113
- <div className="settings-form">
114
- <div className="settings-section">
115
- <h3>Do Not Disturb</h3>
116
- <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '1rem' }}>
117
- <div
118
- className={`toggle${prefs.dnd.enabled ? ' active' : ''}`}
119
- onClick={() => setPrefs(prev => ({
120
- ...prev,
121
- dnd: { ...prev.dnd, enabled: !prev.dnd.enabled },
122
- }))}
123
- />
124
- <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>
125
- {prefs.dnd.enabled ? 'Enabled' : 'Disabled'}
126
- </span>
127
- </div>
128
- {prefs.dnd.enabled && (
129
- <div style={{ display: 'flex', gap: '1rem', alignItems: 'center', marginBottom: '1rem' }}>
130
- <div>
131
- <label>Start</label>
132
- <input
133
- type="time"
134
- value={prefs.dnd.schedule.start}
135
- onChange={(e) => setPrefs(prev => ({
136
- ...prev,
137
- dnd: { ...prev.dnd, schedule: { ...prev.dnd.schedule, start: e.target.value } },
138
- }))}
139
- />
140
- </div>
141
- <div>
142
- <label>End</label>
143
- <input
144
- type="time"
145
- value={prefs.dnd.schedule.end}
146
- onChange={(e) => setPrefs(prev => ({
147
- ...prev,
148
- dnd: { ...prev.dnd, schedule: { ...prev.dnd.schedule, end: e.target.value } },
149
- }))}
150
- />
151
- </div>
152
- </div>
153
- )}
154
- </div>
155
-
156
- <div className="settings-section">
157
- <h3>Urgency Keywords</h3>
158
- <label>Comma-separated keywords that mark a notification as urgent</label>
159
- <textarea
160
- rows={3}
161
- value={keywordsText}
162
- onChange={(e) => setKeywordsText(e.target.value)}
163
- placeholder="urgent, critical, deadline, asap"
164
- style={{ width: '100%', resize: 'vertical' }}
165
- />
166
- </div>
167
-
168
- <div className="settings-section">
169
- <h3>Sources</h3>
170
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', marginBottom: '1rem' }}>
171
- {(['email', 'calendar', 'github'] as const).map(source => (
172
- <label key={source} style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', cursor: 'pointer', fontSize: '0.85rem' }}>
173
- <input
174
- type="checkbox"
175
- checked={prefs.sources[source]}
176
- onChange={() => setPrefs(prev => ({
177
- ...prev,
178
- sources: { ...prev.sources, [source]: !prev.sources[source] },
179
- }))}
180
- style={{ width: 'auto', marginBottom: 0 }}
181
- />
182
- {source.charAt(0).toUpperCase() + source.slice(1)}
183
- </label>
184
- ))}
185
- </div>
186
- </div>
187
-
188
- <div className="settings-section">
189
- <h3>Sound</h3>
190
- <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '1rem' }}>
191
- <div
192
- className={`toggle${prefs.soundEnabled ? ' active' : ''}`}
193
- onClick={() => setPrefs(prev => ({ ...prev, soundEnabled: !prev.soundEnabled }))}
194
- />
195
- <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>
196
- {prefs.soundEnabled ? 'Enabled' : 'Disabled'}
197
- </span>
198
- </div>
199
- </div>
200
-
201
- <button className="settings-btn" onClick={handleSave} disabled={saving}>
202
- {saving ? 'Saving...' : 'Save Settings'}
203
- </button>
204
- {success && <div className="settings-success">{success}</div>}
205
- {error && <div className="error">{error}</div>}
206
-
207
- {notifications.length > 0 && (
208
- <div className="settings-section" style={{ marginTop: '2rem' }}>
209
- <h3>Recent Notifications</h3>
210
- <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
211
- {notifications.map(n => (
212
- <div key={n.id} style={{
213
- display: 'flex',
214
- justifyContent: 'space-between',
215
- alignItems: 'center',
216
- padding: '0.75rem',
217
- background: 'var(--bg-secondary, #1a1a2e)',
218
- borderRadius: '6px',
219
- }}>
220
- <div>
221
- <div style={{ fontWeight: 500 }}>{n.title}</div>
222
- <div style={{ fontSize: '0.8rem', color: 'var(--text-secondary)' }}>
223
- {n.source} &middot; {new Date(n.timestamp).toLocaleString()}
224
- </div>
225
- </div>
226
- <button
227
- className="settings-btn"
228
- style={{ padding: '0.25rem 0.75rem', fontSize: '0.8rem' }}
229
- onClick={() => handleDismiss(n.id)}
230
- >
231
- Dismiss
232
- </button>
233
- </div>
234
- ))}
235
- </div>
236
- </div>
237
- )}
238
- </div>
239
- </div>
240
- );
241
- }
@@ -1,45 +0,0 @@
1
- import { useState } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { SetupProgress } from '../components/SetupProgress';
4
- import { ThemeSelector } from '../components/ThemeSelector';
5
- import { useTheme } from '../contexts/ThemeContext';
6
- import { api } from '../api';
7
-
8
- export function SetupAppearance() {
9
- const { theme } = useTheme();
10
- const [error, setError] = useState('');
11
- const [loading, setLoading] = useState(false);
12
- const navigate = useNavigate();
13
-
14
- const handleContinue = async () => {
15
- setLoading(true);
16
- setError('');
17
- try {
18
- await api.updateAppearance(theme);
19
- navigate('/setup/provider');
20
- } catch (err: unknown) {
21
- setError(err instanceof Error ? err.message : 'Failed to save appearance');
22
- setLoading(false);
23
- }
24
- };
25
-
26
- return (
27
- <div className="setup-page">
28
- <SetupProgress currentStep={5} />
29
- <div className="setup-card" style={{ maxWidth: 720 }}>
30
- <h1>Appearance</h1>
31
- <p className="subtitle">Choose a visual theme for Mission Control. You can change this later in settings.</p>
32
- <ThemeSelector />
33
- {error && <p className="error">{error}</p>}
34
- <button
35
- className="btn-primary"
36
- onClick={handleContinue}
37
- disabled={loading}
38
- style={{ marginTop: '1.5rem', width: '100%' }}
39
- >
40
- {loading ? 'Saving...' : 'Continue'}
41
- </button>
42
- </div>
43
- </div>
44
- );
45
- }
@@ -1,143 +0,0 @@
1
- import { useState } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { api } from '../api';
4
- import { SetupProgress } from '../components/SetupProgress';
5
-
6
- interface ChannelDef {
7
- type: string;
8
- name: string;
9
- description: string;
10
- fields: Array<{ key: string; label: string; type: string }>;
11
- }
12
-
13
- const CHANNELS: ChannelDef[] = [
14
- { type: 'webchat', name: 'Webchat', description: 'Built-in, no setup needed', fields: [] },
15
- { type: 'discord', name: 'Discord', description: 'Connect a Discord bot', fields: [
16
- { key: 'botToken', label: 'Bot Token', type: 'password' },
17
- ]},
18
- { type: 'telegram', name: 'Telegram', description: 'Connect a Telegram bot', fields: [
19
- { key: 'botToken', label: 'Bot Token', type: 'password' },
20
- ]},
21
- { type: 'slack', name: 'Slack', description: 'Connect to a Slack workspace', fields: [
22
- { key: 'botToken', label: 'Bot Token', type: 'password' },
23
- { key: 'appToken', label: 'App Token', type: 'password' },
24
- ]},
25
- { type: 'matrix', name: 'Matrix', description: 'Connect to a Matrix homeserver', fields: [
26
- { key: 'homeserverUrl', label: 'Homeserver URL', type: 'text' },
27
- { key: 'userId', label: 'User ID', type: 'text' },
28
- { key: 'accessToken', label: 'Access Token', type: 'password' },
29
- ]},
30
- { type: 'signal', name: 'Signal', description: 'Connect via Signal CLI', fields: [
31
- { key: 'cliEndpoint', label: 'CLI Endpoint', type: 'text' },
32
- { key: 'phoneNumber', label: 'Phone Number', type: 'text' },
33
- ]},
34
- { type: 'teams', name: 'Teams', description: 'Connect to Microsoft Teams', fields: [
35
- { key: 'appId', label: 'App ID', type: 'text' },
36
- { key: 'appPassword', label: 'App Password', type: 'password' },
37
- ]},
38
- { type: 'whatsapp', name: 'WhatsApp', description: 'Connect via WhatsApp Business API', fields: [
39
- { key: 'phoneNumberId', label: 'Phone Number ID', type: 'text' },
40
- { key: 'accessToken', label: 'Access Token', type: 'password' },
41
- { key: 'verifyToken', label: 'Verify Token', type: 'text' },
42
- ]},
43
- { type: 'twilio', name: 'Twilio', description: 'Connect via Twilio SMS', fields: [
44
- { key: 'accountSid', label: 'Account SID', type: 'text' },
45
- { key: 'authToken', label: 'Auth Token', type: 'password' },
46
- { key: 'phoneNumber', label: 'Phone Number', type: 'text' },
47
- ]},
48
- { type: 'email', name: 'Email', description: 'Connect via IMAP/SMTP', fields: [
49
- { key: 'imapHost', label: 'IMAP Host', type: 'text' },
50
- { key: 'imapPort', label: 'IMAP Port', type: 'text' },
51
- { key: 'smtpHost', label: 'SMTP Host', type: 'text' },
52
- { key: 'smtpPort', label: 'SMTP Port', type: 'text' },
53
- { key: 'email', label: 'Email', type: 'text' },
54
- { key: 'password', label: 'Password', type: 'password' },
55
- ]},
56
- ];
57
-
58
- export function SetupChannels() {
59
- const [enabled, setEnabled] = useState<Record<string, boolean>>({ webchat: true });
60
- const [credentials, setCredentials] = useState<Record<string, Record<string, string>>>({});
61
- const [error, setError] = useState('');
62
- const [loading, setLoading] = useState(false);
63
- const navigate = useNavigate();
64
-
65
- const toggleChannel = (type: string) => {
66
- if (type === 'webchat') return;
67
- setEnabled((prev) => ({ ...prev, [type]: !prev[type] }));
68
- };
69
-
70
- const setField = (type: string, key: string, value: string) => {
71
- setCredentials((prev) => ({
72
- ...prev,
73
- [type]: { ...prev[type], [key]: value },
74
- }));
75
- };
76
-
77
- const handleSubmit = async () => {
78
- setLoading(true);
79
- setError('');
80
- try {
81
- const channels = CHANNELS
82
- .filter((ch) => enabled[ch.type])
83
- .map((ch) => ({
84
- type: ch.type,
85
- enabled: true,
86
- credentials: credentials[ch.type],
87
- }));
88
- await api.setupChannels(channels);
89
- navigate('/setup/connections');
90
- } catch (err: unknown) {
91
- setError(err instanceof Error ? err.message : 'Failed to save channels');
92
- } finally {
93
- setLoading(false);
94
- }
95
- };
96
-
97
- return (
98
- <div className="setup-page">
99
- <SetupProgress currentStep={7} />
100
- <div className="setup-card" style={{ maxWidth: 720 }}>
101
- <h1>Channels</h1>
102
- <p className="subtitle">Enable the messaging channels you want to connect.</p>
103
- <div className="channel-grid">
104
- {CHANNELS.map((ch) => (
105
- <div key={ch.type} className="channel-card">
106
- <div className="channel-card-header">
107
- <h3>{ch.name}</h3>
108
- {ch.type === 'webchat' ? (
109
- <span style={{ fontSize: '0.75rem', color: 'var(--success)' }}>Always on</span>
110
- ) : (
111
- <div
112
- className={`toggle${enabled[ch.type] ? ' active' : ''}`}
113
- onClick={() => toggleChannel(ch.type)}
114
- />
115
- )}
116
- </div>
117
- <p style={{ fontSize: '0.8rem', color: 'var(--text-secondary)', marginBottom: '0.5rem' }}>{ch.description}</p>
118
- {enabled[ch.type] && ch.fields.length > 0 && (
119
- <div className="channel-card-fields">
120
- {ch.fields.map((f) => (
121
- <div key={f.key}>
122
- <label>{f.label}</label>
123
- <input
124
- type={f.type}
125
- value={credentials[ch.type]?.[f.key] || ''}
126
- onChange={(e) => setField(ch.type, f.key, e.target.value)}
127
- />
128
- </div>
129
- ))}
130
- </div>
131
- )}
132
- </div>
133
- ))}
134
- </div>
135
- <button className="setup-btn-primary" onClick={handleSubmit} disabled={loading}>
136
- {loading ? 'Saving...' : 'Save & Continue'}
137
- </button>
138
- {error && <p className="error">{error}</p>}
139
- <span className="skip-link" onClick={() => navigate('/setup/connections')}>Skip for now</span>
140
- </div>
141
- </div>
142
- );
143
- }
@@ -1,31 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { api } from '../api';
3
-
4
- export function SetupComplete() {
5
- const [error, setError] = useState('');
6
-
7
- useEffect(() => {
8
- api.completeSetup().catch((err: unknown) => {
9
- setError(err instanceof Error ? err.message : 'Failed to finalize setup');
10
- });
11
- }, []);
12
-
13
- return (
14
- <div className="setup-page">
15
- <div className="setup-card" style={{ textAlign: 'center' }}>
16
- <div className="setup-complete-check">{'\u2713'}</div>
17
- <h1>Setup Complete!</h1>
18
- <p className="subtitle">Your assistant is ready to go.</p>
19
- {error && <p className="error">{error}</p>}
20
- <div className="setup-complete-buttons">
21
- <button className="setup-btn-primary" onClick={() => { window.location.href = '/'; }}>
22
- Open Chat
23
- </button>
24
- <button className="setup-btn-secondary" onClick={() => { window.location.href = '/dashboard'; }}>
25
- Go to Mission Control
26
- </button>
27
- </div>
28
- </div>
29
- </div>
30
- );
31
- }
@@ -1,80 +0,0 @@
1
- import { useState } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { api } from '../api';
4
- import { SetupProgress } from '../components/SetupProgress';
5
-
6
- export function SetupConnections() {
7
- const [clientId, setClientId] = useState('');
8
- const [clientSecret, setClientSecret] = useState('');
9
- const [error, setError] = useState('');
10
- const [loading, setLoading] = useState(false);
11
- const navigate = useNavigate();
12
-
13
- const handleConnect = async () => {
14
- if (!clientId || !clientSecret) {
15
- setError('Both Client ID and Client Secret are required');
16
- return;
17
- }
18
- setLoading(true);
19
- setError('');
20
- try {
21
- const result = await api.saveConnectorCredentials('google-workspace', clientId, clientSecret);
22
- if (result.oauthUrl) {
23
- window.location.href = result.oauthUrl;
24
- } else {
25
- navigate('/setup/complete');
26
- }
27
- } catch (err: unknown) {
28
- setError(err instanceof Error ? err.message : 'Failed to save credentials');
29
- } finally {
30
- setLoading(false);
31
- }
32
- };
33
-
34
- return (
35
- <div className="setup-page">
36
- <SetupProgress currentStep={8} />
37
- <div className="setup-card">
38
- <h1>Connections</h1>
39
- <p className="subtitle">Connect external services for calendar, email, and task intelligence.</p>
40
- <div className="settings-section">
41
- <h3>Google Workspace</h3>
42
- <p style={{ fontSize: '0.8rem', color: 'var(--text-secondary)', marginBottom: '1rem' }}>
43
- Connect your Google account to enable calendar awareness, email summaries, and task sync.
44
- </p>
45
- <label>Client ID</label>
46
- <input
47
- type="text"
48
- value={clientId}
49
- onChange={(e) => setClientId(e.target.value)}
50
- placeholder="your-client-id.apps.googleusercontent.com"
51
- />
52
- <label>Client Secret</label>
53
- <input
54
- type="password"
55
- value={clientSecret}
56
- onChange={(e) => setClientSecret(e.target.value)}
57
- placeholder="GOCSPX-..."
58
- />
59
- <button
60
- type="button"
61
- className="setup-btn-primary"
62
- onClick={handleConnect}
63
- disabled={loading}
64
- >
65
- {loading ? 'Connecting...' : 'Connect Google Account'}
66
- </button>
67
- {error && <p className="error">{error}</p>}
68
- </div>
69
- <button
70
- type="button"
71
- className="setup-btn-secondary"
72
- onClick={() => navigate('/setup/complete')}
73
- >
74
- Continue without connecting
75
- </button>
76
- <span className="skip-link" onClick={() => navigate('/setup/complete')}>Skip for now</span>
77
- </div>
78
- </div>
79
- );
80
- }
@@ -1,50 +0,0 @@
1
- import { useState } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { api } from '../api';
4
- import { SetupProgress } from '../components/SetupProgress';
5
- import { PasswordStrength } from '../components/PasswordStrength';
6
-
7
- export function SetupDashboardPassword() {
8
- const [password, setPassword] = useState('');
9
- const [confirm, setConfirm] = useState('');
10
- const [error, setError] = useState('');
11
- const [loading, setLoading] = useState(false);
12
- const navigate = useNavigate();
13
-
14
- const handleSubmit = async (e: React.FormEvent) => {
15
- e.preventDefault();
16
- if (password.length < 8) { setError('Password must be at least 8 characters'); return; }
17
- if (password !== confirm) { setError('Passwords do not match'); return; }
18
- setLoading(true);
19
- setError('');
20
- try {
21
- await api.setupDashboardPassword(password);
22
- navigate('/setup/identity');
23
- } catch (err: unknown) {
24
- setError(err instanceof Error ? err.message : 'Failed to set password');
25
- } finally {
26
- setLoading(false);
27
- }
28
- };
29
-
30
- return (
31
- <div className="setup-page">
32
- <SetupProgress currentStep={2} />
33
- <div className="setup-card">
34
- <h1>Mission Control Password</h1>
35
- <p className="subtitle">This password protects Mission Control. You'll use it to log in.</p>
36
- <form onSubmit={handleSubmit}>
37
- <label>Password</label>
38
- <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} autoFocus />
39
- <PasswordStrength password={password} />
40
- <label>Confirm password</label>
41
- <input type="password" value={confirm} onChange={(e) => setConfirm(e.target.value)} />
42
- <button type="submit" className="setup-btn-primary" disabled={loading}>
43
- {loading ? 'Saving...' : 'Set Password'}
44
- </button>
45
- {error && <p className="error">{error}</p>}
46
- </form>
47
- </div>
48
- </div>
49
- );
50
- }
@@ -1,68 +0,0 @@
1
- import { useState, useMemo } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { api } from '../api';
4
- import { SetupProgress } from '../components/SetupProgress';
5
-
6
- const AI_NAMES = [
7
- 'Nova', 'Atlas', 'Jasper', 'Echo', 'Sage', 'Onyx', 'Iris', 'Phoenix',
8
- 'Kai', 'Luna', 'Orion', 'Zephyr', 'Rune', 'Pixel', 'Nyx', 'Sol',
9
- 'Cleo', 'Juno', 'Vex', 'Aura',
10
- ];
11
-
12
- export function SetupIdentity() {
13
- const randomName = useMemo(() => AI_NAMES[Math.floor(Math.random() * AI_NAMES.length)], []);
14
- const [name, setName] = useState('');
15
- const [pronouns, setPronouns] = useState('she/her');
16
- const [vibe, setVibe] = useState('');
17
- const [error, setError] = useState('');
18
- const [loading, setLoading] = useState(false);
19
- const navigate = useNavigate();
20
-
21
- const handleSubmit = async (e: React.FormEvent) => {
22
- e.preventDefault();
23
- setLoading(true);
24
- setError('');
25
- try {
26
- await api.setupIdentity(name || randomName, pronouns, vibe || undefined);
27
- if (vibe) localStorage.setItem('auxiora_setup_vibe', vibe);
28
- navigate('/setup/personality');
29
- } catch (err: unknown) {
30
- setError(err instanceof Error ? err.message : 'Failed to save identity');
31
- } finally {
32
- setLoading(false);
33
- }
34
- };
35
-
36
- return (
37
- <div className="setup-page">
38
- <SetupProgress currentStep={3} />
39
- <div className="setup-card">
40
- <h1>Agent Identity</h1>
41
- <p className="subtitle">Give your AI assistant a name, pronouns, and vibe.</p>
42
- <form onSubmit={handleSubmit}>
43
- <label>Agent name</label>
44
- <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder={randomName} autoFocus />
45
- <label>Pronouns</label>
46
- <select value={pronouns} onChange={(e) => setPronouns(e.target.value)}>
47
- <option value="she/her">she/her</option>
48
- <option value="he/him">he/him</option>
49
- <option value="they/them">they/them</option>
50
- <option value="it/its">it/its</option>
51
- </select>
52
- <label>Describe the vibe</label>
53
- <textarea
54
- value={vibe}
55
- onChange={(e) => setVibe(e.target.value)}
56
- placeholder="e.g. chill and witty, professional and sharp, warm like a best friend"
57
- rows={3}
58
- style={{ width: '100%', resize: 'vertical' }}
59
- />
60
- <button type="submit" className="setup-btn-primary" disabled={loading}>
61
- {loading ? 'Saving...' : 'Continue'}
62
- </button>
63
- {error && <p className="error">{error}</p>}
64
- </form>
65
- </div>
66
- </div>
67
- );
68
- }