nextjs-chatbot-ui 1.1.0 → 1.1.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.
- package/components/AdminSetup.tsx +155 -71
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
13
13
|
const [currentStep, setCurrentStep] = useState<'connection' | 'columns'>('connection');
|
|
14
14
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
15
15
|
const [connectionError, setConnectionError] = useState<string | null>(null);
|
|
16
|
+
const [connectionSuccess, setConnectionSuccess] = useState(false);
|
|
16
17
|
const [availableColumns, setAvailableColumns] = useState<string[]>([]);
|
|
17
18
|
const [isLoadingColumns, setIsLoadingColumns] = useState(false);
|
|
18
19
|
|
|
@@ -52,52 +53,69 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
52
53
|
setConnectionError(null);
|
|
53
54
|
};
|
|
54
55
|
|
|
55
|
-
const handleTestConnection = async () => {
|
|
56
|
+
const handleTestConnection = async (): Promise<boolean> => {
|
|
56
57
|
if (!onTestConnection) {
|
|
57
58
|
// Default test - just validate fields
|
|
58
59
|
if (!connection.host || !connection.database) {
|
|
59
60
|
setConnectionError('Please fill in all required fields');
|
|
60
|
-
|
|
61
|
+
setConnectionSuccess(false);
|
|
62
|
+
return false;
|
|
61
63
|
}
|
|
62
64
|
setConnectionError(null);
|
|
63
|
-
|
|
65
|
+
setConnectionSuccess(true);
|
|
66
|
+
return true;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
setIsConnecting(true);
|
|
67
70
|
setConnectionError(null);
|
|
71
|
+
setConnectionSuccess(false);
|
|
68
72
|
|
|
69
73
|
try {
|
|
70
74
|
const isValid = await onTestConnection(connection);
|
|
71
75
|
if (isValid) {
|
|
72
76
|
setConnectionError(null);
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
setConnectionSuccess(true);
|
|
78
|
+
return true;
|
|
75
79
|
} else {
|
|
76
80
|
setConnectionError('Connection failed. Please check your credentials.');
|
|
81
|
+
setConnectionSuccess(false);
|
|
82
|
+
return false;
|
|
77
83
|
}
|
|
78
84
|
} catch (error: any) {
|
|
79
85
|
setConnectionError(error.message || 'Connection failed. Please try again.');
|
|
86
|
+
setConnectionSuccess(false);
|
|
87
|
+
return false;
|
|
80
88
|
} finally {
|
|
81
89
|
setIsConnecting(false);
|
|
82
90
|
}
|
|
83
91
|
};
|
|
84
92
|
|
|
85
|
-
const handleFetchColumns = async () => {
|
|
93
|
+
const handleFetchColumns = async (): Promise<string[]> => {
|
|
86
94
|
if (!onFetchColumns) {
|
|
87
95
|
// Mock columns for demo
|
|
88
|
-
|
|
96
|
+
const mockColumns = ['id', 'title', 'content', 'description', 'category', 'tags', 'created_at', 'updated_at'];
|
|
97
|
+
setAvailableColumns(mockColumns);
|
|
89
98
|
setIsLoadingColumns(false);
|
|
90
|
-
return;
|
|
99
|
+
return mockColumns;
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
setIsLoadingColumns(true);
|
|
103
|
+
setConnectionError(null);
|
|
94
104
|
try {
|
|
95
105
|
const columns = await onFetchColumns(connection);
|
|
96
|
-
|
|
106
|
+
if (columns && columns.length > 0) {
|
|
107
|
+
setAvailableColumns(columns);
|
|
108
|
+
setIsLoadingColumns(false);
|
|
109
|
+
return columns;
|
|
110
|
+
} else {
|
|
111
|
+
setConnectionError('No columns found in the database.');
|
|
112
|
+
setIsLoadingColumns(false);
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
97
115
|
} catch (error: any) {
|
|
98
116
|
setConnectionError(error.message || 'Failed to fetch columns');
|
|
99
|
-
} finally {
|
|
100
117
|
setIsLoadingColumns(false);
|
|
118
|
+
return [];
|
|
101
119
|
}
|
|
102
120
|
};
|
|
103
121
|
|
|
@@ -106,21 +124,39 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
106
124
|
if (dbType === 'mongodb') {
|
|
107
125
|
if (!connection.connectionString && (!connection.host || !connection.database)) {
|
|
108
126
|
setConnectionError('Please provide connection string or host and database');
|
|
127
|
+
setConnectionSuccess(false);
|
|
109
128
|
return;
|
|
110
129
|
}
|
|
111
130
|
} else {
|
|
112
131
|
if (!connection.host || !connection.database || !connection.username || !connection.password) {
|
|
113
132
|
setConnectionError('Please fill in all required fields');
|
|
133
|
+
setConnectionSuccess(false);
|
|
114
134
|
return;
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
|
|
118
|
-
//
|
|
119
|
-
|
|
138
|
+
// Clear previous errors
|
|
139
|
+
setConnectionError(null);
|
|
140
|
+
setConnectionSuccess(false);
|
|
141
|
+
|
|
142
|
+
// Test connection first
|
|
143
|
+
const connectionSuccess = await handleTestConnection();
|
|
120
144
|
|
|
121
|
-
|
|
122
|
-
|
|
145
|
+
if (!connectionSuccess) {
|
|
146
|
+
// Connection failed, don't proceed
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// If connection successful, fetch columns
|
|
151
|
+
const fetchedColumns = await handleFetchColumns();
|
|
152
|
+
|
|
153
|
+
if (fetchedColumns && fetchedColumns.length > 0) {
|
|
154
|
+
// Successfully fetched columns, move to next step
|
|
123
155
|
setCurrentStep('columns');
|
|
156
|
+
setConnectionError(null);
|
|
157
|
+
} else {
|
|
158
|
+
// Column fetching failed, show error but keep connection success
|
|
159
|
+
// Error is already set in handleFetchColumns
|
|
124
160
|
}
|
|
125
161
|
};
|
|
126
162
|
|
|
@@ -158,6 +194,8 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
158
194
|
setIsModalOpen(false);
|
|
159
195
|
setCurrentStep('connection');
|
|
160
196
|
setConnectionError(null);
|
|
197
|
+
setConnectionSuccess(false);
|
|
198
|
+
setAvailableColumns([]);
|
|
161
199
|
setColumnSelection({
|
|
162
200
|
embeddingColumns: [],
|
|
163
201
|
llmColumns: [],
|
|
@@ -435,88 +473,131 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
435
473
|
<p className="text-sm text-red-800">{connectionError}</p>
|
|
436
474
|
</div>
|
|
437
475
|
)}
|
|
476
|
+
{connectionSuccess && !connectionError && !isConnecting && (
|
|
477
|
+
<div className="bg-green-50 border border-green-200 rounded-lg p-4">
|
|
478
|
+
<p className="text-sm text-green-800">✓ Connection successful!</p>
|
|
479
|
+
</div>
|
|
480
|
+
)}
|
|
438
481
|
</div>
|
|
439
482
|
) : (
|
|
440
483
|
<div className="space-y-6">
|
|
441
484
|
{isLoadingColumns ? (
|
|
442
|
-
<div className="flex items-center justify-center py-8">
|
|
443
|
-
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
485
|
+
<div className="flex flex-col items-center justify-center py-8">
|
|
486
|
+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mb-3"></div>
|
|
487
|
+
<p className="text-sm text-gray-600">Loading columns...</p>
|
|
488
|
+
</div>
|
|
489
|
+
) : availableColumns.length === 0 ? (
|
|
490
|
+
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
|
491
|
+
<p className="text-sm text-yellow-800">No columns available. Please go back and check your connection.</p>
|
|
444
492
|
</div>
|
|
445
493
|
) : (
|
|
446
494
|
<>
|
|
447
495
|
<div>
|
|
448
|
-
<p className="text-sm text-gray-600 mb-
|
|
449
|
-
Select which columns to use for
|
|
496
|
+
<p className="text-sm text-gray-600 mb-2">
|
|
497
|
+
Select which columns to use for <strong>Embeddings</strong>, <strong>LLM processing</strong>, and <strong>ChromaDB storage</strong>.
|
|
498
|
+
</p>
|
|
499
|
+
<p className="text-xs text-gray-500 mb-4">
|
|
500
|
+
Found {availableColumns.length} column{availableColumns.length !== 1 ? 's' : ''} in your database.
|
|
450
501
|
</p>
|
|
451
502
|
</div>
|
|
452
503
|
|
|
453
504
|
{/* Embedding Columns */}
|
|
454
505
|
<div>
|
|
455
|
-
<label className="block text-sm font-medium text-gray-700 mb-
|
|
456
|
-
|
|
506
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
507
|
+
Works with Embeddings
|
|
457
508
|
</label>
|
|
458
|
-
<
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
<
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
509
|
+
<p className="text-xs text-gray-500 mb-3">Select columns that will be used for embedding generation</p>
|
|
510
|
+
<div className="grid grid-cols-2 gap-2 max-h-40 overflow-y-auto border border-gray-200 rounded-lg p-3 bg-gray-50">
|
|
511
|
+
{availableColumns.length === 0 ? (
|
|
512
|
+
<p className="text-sm text-gray-500 col-span-2 text-center py-2">No columns available</p>
|
|
513
|
+
) : (
|
|
514
|
+
availableColumns.map((column) => (
|
|
515
|
+
<label
|
|
516
|
+
key={`embedding-${column}`}
|
|
517
|
+
className="flex items-center gap-2 cursor-pointer hover:bg-white p-2 rounded transition-colors"
|
|
518
|
+
>
|
|
519
|
+
<input
|
|
520
|
+
type="checkbox"
|
|
521
|
+
checked={columnSelection.embeddingColumns.includes(column)}
|
|
522
|
+
onChange={() => handleColumnToggle(column, 'embeddingColumns')}
|
|
523
|
+
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
524
|
+
/>
|
|
525
|
+
<span className="text-sm text-gray-700">{column}</span>
|
|
526
|
+
</label>
|
|
527
|
+
))
|
|
528
|
+
)}
|
|
473
529
|
</div>
|
|
530
|
+
{columnSelection.embeddingColumns.length > 0 && (
|
|
531
|
+
<p className="text-xs text-green-600 mt-1">
|
|
532
|
+
{columnSelection.embeddingColumns.length} column{columnSelection.embeddingColumns.length !== 1 ? 's' : ''} selected
|
|
533
|
+
</p>
|
|
534
|
+
)}
|
|
474
535
|
</div>
|
|
475
536
|
|
|
476
537
|
{/* LLM Columns */}
|
|
477
538
|
<div>
|
|
478
|
-
<label className="block text-sm font-medium text-gray-700 mb-
|
|
479
|
-
LLM
|
|
539
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
540
|
+
Works with LLM
|
|
480
541
|
</label>
|
|
481
|
-
<
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
542
|
+
<p className="text-xs text-gray-500 mb-3">Select columns that will be processed by the LLM</p>
|
|
543
|
+
<div className="grid grid-cols-2 gap-2 max-h-40 overflow-y-auto border border-gray-200 rounded-lg p-3 bg-gray-50">
|
|
544
|
+
{availableColumns.length === 0 ? (
|
|
545
|
+
<p className="text-sm text-gray-500 col-span-2 text-center py-2">No columns available</p>
|
|
546
|
+
) : (
|
|
547
|
+
availableColumns.map((column) => (
|
|
548
|
+
<label
|
|
549
|
+
key={`llm-${column}`}
|
|
550
|
+
className="flex items-center gap-2 cursor-pointer hover:bg-white p-2 rounded transition-colors"
|
|
551
|
+
>
|
|
552
|
+
<input
|
|
553
|
+
type="checkbox"
|
|
554
|
+
checked={columnSelection.llmColumns.includes(column)}
|
|
555
|
+
onChange={() => handleColumnToggle(column, 'llmColumns')}
|
|
556
|
+
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
557
|
+
/>
|
|
558
|
+
<span className="text-sm text-gray-700">{column}</span>
|
|
559
|
+
</label>
|
|
560
|
+
))
|
|
561
|
+
)}
|
|
496
562
|
</div>
|
|
563
|
+
{columnSelection.llmColumns.length > 0 && (
|
|
564
|
+
<p className="text-xs text-green-600 mt-1">
|
|
565
|
+
{columnSelection.llmColumns.length} column{columnSelection.llmColumns.length !== 1 ? 's' : ''} selected
|
|
566
|
+
</p>
|
|
567
|
+
)}
|
|
497
568
|
</div>
|
|
498
569
|
|
|
499
570
|
{/* ChromaDB Columns */}
|
|
500
571
|
<div>
|
|
501
|
-
<label className="block text-sm font-medium text-gray-700 mb-
|
|
502
|
-
ChromaDB
|
|
572
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
573
|
+
Works with ChromaDB
|
|
503
574
|
</label>
|
|
504
|
-
<
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
<
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
575
|
+
<p className="text-xs text-gray-500 mb-3">Select columns that will be stored in ChromaDB</p>
|
|
576
|
+
<div className="grid grid-cols-2 gap-2 max-h-40 overflow-y-auto border border-gray-200 rounded-lg p-3 bg-gray-50">
|
|
577
|
+
{availableColumns.length === 0 ? (
|
|
578
|
+
<p className="text-sm text-gray-500 col-span-2 text-center py-2">No columns available</p>
|
|
579
|
+
) : (
|
|
580
|
+
availableColumns.map((column) => (
|
|
581
|
+
<label
|
|
582
|
+
key={`chroma-${column}`}
|
|
583
|
+
className="flex items-center gap-2 cursor-pointer hover:bg-white p-2 rounded transition-colors"
|
|
584
|
+
>
|
|
585
|
+
<input
|
|
586
|
+
type="checkbox"
|
|
587
|
+
checked={columnSelection.chromaColumns.includes(column)}
|
|
588
|
+
onChange={() => handleColumnToggle(column, 'chromaColumns')}
|
|
589
|
+
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
590
|
+
/>
|
|
591
|
+
<span className="text-sm text-gray-700">{column}</span>
|
|
592
|
+
</label>
|
|
593
|
+
))
|
|
594
|
+
)}
|
|
519
595
|
</div>
|
|
596
|
+
{columnSelection.chromaColumns.length > 0 && (
|
|
597
|
+
<p className="text-xs text-green-600 mt-1">
|
|
598
|
+
{columnSelection.chromaColumns.length} column{columnSelection.chromaColumns.length !== 1 ? 's' : ''} selected
|
|
599
|
+
</p>
|
|
600
|
+
)}
|
|
520
601
|
</div>
|
|
521
602
|
</>
|
|
522
603
|
)}
|
|
@@ -537,9 +618,12 @@ const AdminSetup: React.FC<AdminSetupProps> = ({
|
|
|
537
618
|
<button
|
|
538
619
|
onClick={handleConnectAndNext}
|
|
539
620
|
disabled={isConnecting || isLoadingColumns}
|
|
540
|
-
className="px-6 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
621
|
+
className="px-6 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
|
|
541
622
|
>
|
|
542
|
-
{isConnecting
|
|
623
|
+
{isConnecting && (
|
|
624
|
+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
|
625
|
+
)}
|
|
626
|
+
{isLoadingColumns ? 'Loading Columns...' : isConnecting ? 'Connecting...' : 'Connect & Next'}
|
|
543
627
|
</button>
|
|
544
628
|
) : (
|
|
545
629
|
<button
|