mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: list admin plugins when the browser can't cache their code #1327
This commit is contained in:
@@ -189,6 +189,24 @@ describe('usePluginStore', () => {
|
||||
expect(p).toMatchObject({ managed: true, enabled: true, bundleHash: 'hash-v1' });
|
||||
});
|
||||
|
||||
it('lists every server plugin when IndexedDB cannot be written (#1327)', async () => {
|
||||
mocks.apiFetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ plugins: [serverPlugin, { ...serverPlugin, id: 'optional-plugin', forceEnabled: false }], themes: [] }),
|
||||
});
|
||||
vi.mocked(pluginStorage.getCode).mockRejectedValue(new Error('IndexedDB unavailable'));
|
||||
vi.mocked(pluginStorage.saveCode).mockRejectedValueOnce(new Error('IndexedDB unavailable'));
|
||||
vi.mocked(pluginStorage.saveCode).mockRejectedValueOnce(new Error('IndexedDB unavailable'));
|
||||
vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
|
||||
await usePluginStore.getState().initializePlugins();
|
||||
|
||||
const plugins = usePluginStore.getState().plugins;
|
||||
expect(plugins.map(p => p.id)).toEqual(['managed-plugin', 'optional-plugin']);
|
||||
expect(plugins[0]).toMatchObject({ managed: true, enabled: true });
|
||||
expect(plugins[1]).toMatchObject({ managed: true, enabled: false });
|
||||
});
|
||||
|
||||
it('re-downloads the bundle when the record is current but IndexedDB has no copy (#636)', async () => {
|
||||
usePluginStore.setState({ plugins: [syncedRecord()] });
|
||||
vi.mocked(pluginStorage.getCode).mockResolvedValue(null);
|
||||
|
||||
+15
-2
@@ -524,7 +524,7 @@ async function syncServerPlugins(
|
||||
// New server plugin - download bundle and install.
|
||||
const code = await downloadPluginBundle(sp.id, sp.bundleHash, sp.tier);
|
||||
if (!code) continue;
|
||||
await pluginStorage.saveCode(sp.id, code);
|
||||
await cacheManagedBundle(sp.id, code);
|
||||
|
||||
const plugin: InstalledPlugin = {
|
||||
id: sp.id,
|
||||
@@ -569,7 +569,7 @@ async function syncServerPlugins(
|
||||
if (needsBundle) {
|
||||
const code = await downloadPluginBundle(sp.id, sp.bundleHash, sp.tier);
|
||||
if (!code) continue;
|
||||
await pluginStorage.saveCode(sp.id, code);
|
||||
await cacheManagedBundle(sp.id, code);
|
||||
}
|
||||
|
||||
// Force-enable in the same pass when the server flips it on, so the user
|
||||
@@ -625,6 +625,19 @@ async function downloadPluginBundle(pluginId: string, bundleHash?: string, tier?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caching is best effort. Where IndexedDB can't be written (some private
|
||||
* windows, storage disabled) the plugin must still be listed: the loader
|
||||
* fetches a managed bundle again when no local copy exists (#1327).
|
||||
*/
|
||||
async function cacheManagedBundle(pluginId: string, code: string): Promise<void> {
|
||||
try {
|
||||
await pluginStorage.saveCode(pluginId, code);
|
||||
} catch (err) {
|
||||
console.warn(`[plugin-store] Could not cache bundle for "${pluginId}":`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Server-side admin-approval helpers ───────────────────────
|
||||
|
||||
async function checkServerApproval(pluginId: string, bundleHash: string): Promise<{ status: 'pending' | 'approved' | 'denied' | 'not-requested' } | null> {
|
||||
|
||||
Reference in New Issue
Block a user