Add ROOTLESS_CONTAINER and request UI updates

Introduce ROOTLESS_CONTAINER env to opt out of gosu (replace /proc uid_map detection) and update entrypoint messaging; adjust app-start.sh and redis-start.sh to skip gosu when ROOTLESS_CONTAINER=true and warn on UID/GID mismatch only when applicable. Backend: include audiobook audibleAsin in admin requests response (mapped to asin) and pass baseUrl through test-flaresolverr endpoint to the FlareSolverr tester. Frontend: RecentRequestsTable and RequestActionsDropdown now surface asin, accept/passthrough annasArchiveBaseUrl, and add a "View Details" flow using AudiobookDetailsModal; admin page passes ebook baseUrl from settings. InteractiveTorrentSearchModal refactor: improved UX/UI, keyboard handling, portal/modal mounting, skeleton/loading states, formatting helpers, and richer result display. Tests updated to match changes.
This commit is contained in:
kikootwo
2026-02-06 17:13:39 -05:00
parent 03371be81d
commit 95e63dfc36
18 changed files with 1027 additions and 427 deletions
+23 -5
View File
@@ -63,12 +63,30 @@ describe('E-book sidecar', () => {
},
});
const result = await testFlareSolverrConnection('http://flare');
const result = await testFlareSolverrConnection('http://flare', 'https://annas-archive.li');
expect(result.success).toBe(true);
expect(result.responseTime).toBeTypeOf('number');
});
it('uses configured base URL for FlareSolverr test', async () => {
const longHtml = `<html>${'Anna'.padEnd(1200, 'A')}</html>`;
axiosMock.post.mockResolvedValue({
data: {
status: 'ok',
solution: { status: 200, response: longHtml },
},
});
await testFlareSolverrConnection('http://flare', 'https://custom-mirror.org');
expect(axiosMock.post).toHaveBeenCalledWith(
'http://flare/v1',
expect.objectContaining({ url: 'https://custom-mirror.org/' }),
expect.any(Object)
);
});
it('returns false when FlareSolverr response is invalid', async () => {
axiosMock.post.mockResolvedValue({
data: {
@@ -77,7 +95,7 @@ describe('E-book sidecar', () => {
},
});
const result = await testFlareSolverrConnection('http://flare');
const result = await testFlareSolverrConnection('http://flare', 'https://annas-archive.li');
expect(result.success).toBe(false);
});
@@ -85,7 +103,7 @@ describe('E-book sidecar', () => {
it('returns error details when FlareSolverr request fails', async () => {
axiosMock.post.mockRejectedValue(new Error('flare down'));
const result = await testFlareSolverrConnection('http://flare');
const result = await testFlareSolverrConnection('http://flare', 'https://annas-archive.li');
expect(result.success).toBe(false);
expect(result.message).toContain('flare down');
@@ -99,7 +117,7 @@ describe('E-book sidecar', () => {
},
});
const result = await testFlareSolverrConnection('http://flare');
const result = await testFlareSolverrConnection('http://flare', 'https://annas-archive.li');
expect(result.success).toBe(false);
expect(result.message).toContain('FlareSolverr error');
@@ -114,7 +132,7 @@ describe('E-book sidecar', () => {
},
});
const result = await testFlareSolverrConnection('http://flare');
const result = await testFlareSolverrConnection('http://flare', 'https://annas-archive.li');
expect(result.success).toBe(false);
expect(result.message).toContain('FlareSolverr returned HTTP 403');