solr migration button

This commit is contained in:
Stefan Hardegger
2025-09-23 14:18:56 +02:00
parent 62f017c4ca
commit 9472210d8b
2 changed files with 103 additions and 3 deletions

View File

@@ -25,9 +25,11 @@ export default function SystemSettings({}: SystemSettingsProps) {
const [solrStatus, setSolrStatus] = useState<{ const [solrStatus, setSolrStatus] = useState<{
reindex: { loading: boolean; message: string; success?: boolean }; reindex: { loading: boolean; message: string; success?: boolean };
recreate: { loading: boolean; message: string; success?: boolean }; recreate: { loading: boolean; message: string; success?: boolean };
migrate: { loading: boolean; message: string; success?: boolean };
}>({ }>({
reindex: { loading: false, message: '' }, reindex: { loading: false, message: '' },
recreate: { loading: false, message: '' } recreate: { loading: false, message: '' },
migrate: { loading: false, message: '' }
}); });
const [databaseStatus, setDatabaseStatus] = useState<{ const [databaseStatus, setDatabaseStatus] = useState<{
@@ -407,6 +409,57 @@ export default function SystemSettings({}: SystemSettingsProps) {
} }
}; };
const handleLibraryMigration = async () => {
const confirmed = window.confirm(
'This will migrate Solr to support library separation. It will clear existing search data and reindex with library context. Continue?'
);
if (!confirmed) return;
setSolrStatus(prev => ({
...prev,
migrate: { loading: true, message: 'Migrating to library-aware schema...', success: undefined }
}));
try {
const result = await searchAdminApi.migrateLibrarySchema();
setSolrStatus(prev => ({
...prev,
migrate: {
loading: false,
message: result.success
? `${result.message}${result.note ? ` Note: ${result.note}` : ''}`
: (result.error || result.details || 'Migration failed'),
success: result.success
}
}));
setTimeout(() => {
setSolrStatus(prev => ({
...prev,
migrate: { loading: false, message: '', success: undefined }
}));
}, 10000); // Longer timeout for migration messages
} catch (error: any) {
setSolrStatus(prev => ({
...prev,
migrate: {
loading: false,
message: error.message || 'Network error occurred',
success: false
}
}));
setTimeout(() => {
setSolrStatus(prev => ({
...prev,
migrate: { loading: false, message: '', success: undefined }
}));
}, 10000);
}
};
// Load status on component mount // Load status on component mount
useEffect(() => { useEffect(() => {
loadSearchEngineStatus(); loadSearchEngineStatus();
@@ -445,7 +498,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
<div className="flex flex-col sm:flex-row gap-3 mb-4"> <div className="flex flex-col sm:flex-row gap-3 mb-4">
<Button <Button
onClick={handleSolrReindex} onClick={handleSolrReindex}
disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || !searchEngineStatus.solrAvailable} disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || solrStatus.migrate.loading || !searchEngineStatus.solrAvailable}
loading={solrStatus.reindex.loading} loading={solrStatus.reindex.loading}
variant="ghost" variant="ghost"
className="flex-1" className="flex-1"
@@ -454,7 +507,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
</Button> </Button>
<Button <Button
onClick={handleSolrRecreate} onClick={handleSolrRecreate}
disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || !searchEngineStatus.solrAvailable} disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || solrStatus.migrate.loading || !searchEngineStatus.solrAvailable}
loading={solrStatus.recreate.loading} loading={solrStatus.recreate.loading}
variant="secondary" variant="secondary"
className="flex-1" className="flex-1"
@@ -463,6 +516,23 @@ export default function SystemSettings({}: SystemSettingsProps) {
</Button> </Button>
</div> </div>
{/* Library Migration Section */}
<div className="border-t theme-border pt-4">
<h4 className="text-md font-medium theme-header mb-2">Library Separation Migration</h4>
<p className="text-sm theme-text mb-3">
Migrate Solr to support proper library separation. This ensures search results are isolated between different libraries (password-based access).
</p>
<Button
onClick={handleLibraryMigration}
disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || solrStatus.migrate.loading || !searchEngineStatus.solrAvailable}
loading={solrStatus.migrate.loading}
variant="primary"
className="w-full sm:w-auto"
>
{solrStatus.migrate.loading ? 'Migrating...' : '🔒 Migrate Library Schema'}
</Button>
</div>
{/* Status Messages */} {/* Status Messages */}
{solrStatus.reindex.message && ( {solrStatus.reindex.message && (
<div className={`text-sm p-3 rounded mb-3 ${ <div className={`text-sm p-3 rounded mb-3 ${
@@ -483,6 +553,16 @@ export default function SystemSettings({}: SystemSettingsProps) {
{solrStatus.recreate.message} {solrStatus.recreate.message}
</div> </div>
)} )}
{solrStatus.migrate.message && (
<div className={`text-sm p-3 rounded mb-3 ${
solrStatus.migrate.success
? 'bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200'
: 'bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200'
}`}>
{solrStatus.migrate.message}
</div>
)}
</div> </div>
<div className="text-sm theme-text bg-blue-50 dark:bg-blue-900/20 p-3 rounded-lg"> <div className="text-sm theme-text bg-blue-50 dark:bg-blue-900/20 p-3 rounded-lg">
@@ -490,7 +570,12 @@ export default function SystemSettings({}: SystemSettingsProps) {
<ul className="text-xs space-y-1 ml-4"> <ul className="text-xs space-y-1 ml-4">
<li> <strong>Reindex All:</strong> Refresh all search data while keeping existing schemas (fixes data sync issues)</li> <li> <strong>Reindex All:</strong> Refresh all search data while keeping existing schemas (fixes data sync issues)</li>
<li> <strong>Recreate Indices:</strong> Delete and rebuild all search indexes from scratch (fixes schema and structure issues)</li> <li> <strong>Recreate Indices:</strong> Delete and rebuild all search indexes from scratch (fixes schema and structure issues)</li>
<li> <strong>Migrate Library Schema:</strong> One-time migration to enable library separation (isolates search results by library)</li>
</ul> </ul>
<div className="mt-2 pt-2 border-t border-blue-200 dark:border-blue-700">
<p className="font-medium text-xs"> Library Migration:</p>
<p className="text-xs">Only run this once to enable library-aware search. Requires Solr schema to support libraryId field.</p>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -636,6 +636,21 @@ export const searchAdminApi = {
const response = await api.post('/admin/search/solr/recreate'); const response = await api.post('/admin/search/solr/recreate');
return response.data; return response.data;
}, },
// Migrate to library-aware schema
migrateLibrarySchema: async (): Promise<{
success: boolean;
message: string;
storiesCount?: number;
authorsCount?: number;
totalCount?: number;
error?: string;
details?: string;
note?: string;
}> => {
const response = await api.post('/admin/search/solr/migrate-library-schema');
return response.data;
},
}; };
// Collection endpoints // Collection endpoints