Skip to content

Commit 7a17f69

Browse files
committed
typesense-päivitysnappula admin-näkymään
1 parent e1e747b commit 7a17f69

File tree

2 files changed

+119
-5
lines changed

2 files changed

+119
-5
lines changed

backend/src/app.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getLatestStatusEntry, getAllStatusEntries, clearAllStatusEntries } from
1010
import { addStatusRow, createTables, dropTables } from './db/db.js';
1111
import { yearFrom, yearTo } from './util/config.js';
1212
import { getRecentLogs, pushLog } from './util/logBuffer.js';
13+
import { deleteCollection, syncStatutes, syncJudgments } from './search.js';
1314

1415
const app = express()
1516
const __filename = fileURLToPath(import.meta.url);
@@ -164,6 +165,54 @@ app.delete('/api/delete-database', async (req: express.Request, res: express.Res
164165
}
165166
});
166167

168+
app.post('/api/rebuild-typesense', async (req: express.Request, res: express.Response): Promise<void> => {
169+
try {
170+
res.status(200).json({ status: 'started', message: 'Typesense rebuild started in background' });
171+
setImmediate(async () => {
172+
try {
173+
console.info('Typesense rebuild started');
174+
await addStatusRow({ action: 'typesense_rebuild_start', startedAt: new Date().toISOString() }, true);
175+
176+
// Delete and recreate collections for both languages
177+
await deleteCollection('statutes', 'fin');
178+
await deleteCollection('statutes', 'swe');
179+
await deleteCollection('judgments', 'fin');
180+
await deleteCollection('judgments', 'swe');
181+
console.log('Old Typesense collections deleted');
182+
183+
// Rebuild indexes from database
184+
await syncStatutes('fin');
185+
await syncStatutes('swe');
186+
await syncJudgments('fin');
187+
await syncJudgments('swe');
188+
console.log('Typesense collections rebuilt');
189+
190+
await addStatusRow({ action: 'typesense_rebuild_complete', completedAt: new Date().toISOString() }, false);
191+
console.info('Typesense rebuild completed');
192+
} catch (error) {
193+
console.error('[REBUILD] Typesense rebuild failed with error:', error);
194+
const errorMessage = error instanceof Error ? error.message : String(error);
195+
try {
196+
await addStatusRow(
197+
{
198+
message: 'typesense_rebuild_failed',
199+
error: errorMessage,
200+
timestamp: new Date().toISOString()
201+
},
202+
false
203+
);
204+
console.log('[REBUILD] Wrote error status to database');
205+
} catch (dbError) {
206+
console.error('[REBUILD] Failed to write error status to database:', dbError);
207+
}
208+
}
209+
});
210+
} catch (error) {
211+
console.error('[REBUILD] Rebuild endpoint error:', error);
212+
res.status(500).json({ error: 'Failed to start typesense rebuild' });
213+
}
214+
});
215+
167216
app.get('/favicon.ico', (request: express.Request, response: express.Response): void => {
168217
response.status(204).end();
169218
})

frontend/src/components/AdminPage.tsx

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ interface StatusEntry {
1515
const AdminPage = ({ language }: AdminPageProps) => {
1616
const [isUpdating, setIsUpdating] = useState(false)
1717
const [isClearing, setIsClearing] = useState(false)
18+
const [isRebuilding, setIsRebuilding] = useState(false)
1819
const [message, setMessage] = useState('')
1920
const [error, setError] = useState('')
2021
const [latestStatus, setLatestStatus] = useState<StatusEntry | null>(null)
2122
const [hasStartedUpdate, setHasStartedUpdate] = useState(false)
2223
const [startYearInput, setStartYearInput] = useState<string>('')
24+
const [hasStartedRebuild, setHasStartedRebuild] = useState(false)
2325
const intervalRef = useRef<NodeJS.Timeout | null>(null)
2426
const [defaultStartYear, setDefaultStartYear] = useState<number | null>(null)
2527

@@ -129,11 +131,41 @@ const AdminPage = ({ language }: AdminPageProps) => {
129131
}
130132
}
131133

134+
const handleRebuildTypesense = async () => {
135+
setIsRebuilding(true)
136+
setMessage('')
137+
setError('')
138+
setLatestStatus(null)
139+
setHasStartedRebuild(true)
140+
141+
try {
142+
const response = await axios.post('/api/rebuild-typesense')
143+
setMessage(language === 'fin'
144+
? 'Typesense-indeksien uudelleenrakentaminen aloitettu!'
145+
: 'Typesense-indexombyggnad startad!'
146+
)
147+
console.log('Rebuild response:', response.data)
148+
149+
// Start polling for status updates
150+
startPolling()
151+
152+
} catch (err) {
153+
console.error('Rebuild failed:', err)
154+
setError(language === 'fin'
155+
? 'Indeksien uudelleenrakentaminen epäonnistui. Tarkista konsoli lisätiedoille.'
156+
: 'Ombyggnad av index misslyckades. Kontrollera konsolen för mer information.'
157+
)
158+
setIsRebuilding(false)
159+
}
160+
}
161+
132162
// Stop polling and updating state when updating becomes false (only if we started an update)
133163
useEffect(() => {
134-
if (latestStatus && hasStartedUpdate && !latestStatus.updating) {
164+
if (latestStatus && (hasStartedUpdate || hasStartedRebuild) && !latestStatus.updating) {
135165
setIsUpdating(false)
166+
setIsRebuilding(false)
136167
setHasStartedUpdate(false)
168+
setHasStartedRebuild(false)
137169
stopPolling()
138170

139171
// Check the action to determine success or failure
@@ -148,15 +180,25 @@ const AdminPage = ({ language }: AdminPageProps) => {
148180
? 'Päivitys epäonnistui.'
149181
: 'Uppdatering misslyckades.'
150182
)
183+
} else if (action === 'typesense_rebuild_complete') {
184+
setMessage(language === 'fin'
185+
? 'Indeksien uudelleenrakentaminen valmistui onnistuneesti!'
186+
: 'Ombyggnad av indexen slutfördes framgångsrikt!'
187+
)
188+
} else if (action === 'typesense_rebuild_failed') {
189+
setError(language === 'fin'
190+
? 'Indeksien uudelleenrakentaminen epäonnistui.'
191+
: 'Ombyggnad av indexen misslyckades.'
192+
)
151193
} else {
152194
// Generic completion message if no specific action
153195
setMessage(language === 'fin'
154-
? 'Päivitys valmistui!'
155-
: 'Uppdatering slutförd!'
196+
? 'Operaatio valmistui!'
197+
: 'Operationen slutfördes!'
156198
)
157199
}
158200
}
159-
}, [latestStatus, hasStartedUpdate, language])
201+
}, [latestStatus, hasStartedUpdate, hasStartedRebuild, language])
160202

161203
const containerStyle: React.CSSProperties = {
162204
display: 'flex',
@@ -191,6 +233,18 @@ const AdminPage = ({ language }: AdminPageProps) => {
191233
margin: '0 10px 20px 10px'
192234
}
193235

236+
const rebuildButtonStyle: React.CSSProperties = {
237+
backgroundColor: '#FFA500',
238+
color: 'white',
239+
border: 'none',
240+
padding: '12px 24px',
241+
fontSize: '16px',
242+
borderRadius: '4px',
243+
cursor: (isUpdating || isRebuilding) ? 'not-allowed' : 'pointer',
244+
opacity: (isUpdating || isRebuilding) ? 0.6 : 1,
245+
margin: '0 10px 20px 10px'
246+
}
247+
194248
const messageStyle: React.CSSProperties = {
195249
padding: '10px',
196250
borderRadius: '4px',
@@ -248,7 +302,7 @@ const AdminPage = ({ language }: AdminPageProps) => {
248302

249303
<div style={{ marginTop: '50px' }}>
250304
<div style={containerStyle}>
251-
<h2>{language === 'fin' ? 'Järjestelmän ylläpito' : 'Systemunderhåll'}</h2>
305+
<h2>{language === 'fin' ? 'Järjestelmän jee ylläpito' : 'Systemunderhåll'}</h2>
252306

253307
<p style={{ textAlign: 'center', marginBottom: '30px', color: '#666' }}>
254308
{language === 'fin'
@@ -290,6 +344,17 @@ const AdminPage = ({ language }: AdminPageProps) => {
290344
: (language === 'fin' ? 'Tyhjennä tilat' : 'Rensa status')
291345
}
292346
</button>
347+
348+
<button
349+
style={rebuildButtonStyle}
350+
onClick={handleRebuildTypesense}
351+
disabled={isUpdating || isRebuilding}
352+
>
353+
{isRebuilding
354+
? (language === 'fin' ? 'Rakennetaan uudelleen...' : 'Bygger om...')
355+
: (language === 'fin' ? 'Uudelleen rakenna Typesense' : 'Bygga om Typesense')
356+
}
357+
</button>
293358
</div>
294359

295360
{message && (

0 commit comments

Comments
 (0)