mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: put plugin file actions behind a more button in the phone selection toolbar
This commit is contained in:
@@ -17,6 +17,11 @@ import type { FileResourceView } from '@/lib/plugin-types';
|
||||
vi.mock('@/lib/debug', () => ({ debug: { log: () => {}, warn: () => {}, error: () => {} } }));
|
||||
vi.mock('@/components/settings/share-collection-dialog', () => ({ ShareCollectionDialog: () => null }));
|
||||
vi.mock('@/components/plugins/plugin-iframe-slot', () => import('@/components/plugins/__tests__/fake-slot-offer'));
|
||||
const device = vi.hoisted(() => ({ isMobile: false }));
|
||||
vi.mock('@/hooks/use-media-query', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('@/hooks/use-media-query')>()),
|
||||
useIsMobile: () => device.isMobile,
|
||||
}));
|
||||
|
||||
const folder = {
|
||||
id: 'f-docs', name: 'Documents', serverName: 'Documents', isDirectory: true, contentType: '', contentLength: 0,
|
||||
@@ -97,6 +102,7 @@ function rowOf(name: string): HTMLElement {
|
||||
const dispatch = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
device.isMobile = false;
|
||||
localStorage.clear();
|
||||
dispatch.mockClear();
|
||||
setActionDispatcher(dispatch);
|
||||
@@ -159,6 +165,26 @@ describe('file-actions', () => {
|
||||
expect(context.files.map((f) => f.id)).toEqual(['f-notes', 'f-photo']);
|
||||
});
|
||||
|
||||
it('puts them behind one more button in the phone selection toolbar', async () => {
|
||||
device.isMobile = true;
|
||||
act(() => setPluginActions('ocr', 'OCR', 'file-actions', [
|
||||
{ id: 'archive', label: 'Archive' },
|
||||
{ id: 'read-text', label: 'Read text', mimeTypes: ['text/'] },
|
||||
]));
|
||||
renderBrowser(['notes.txt']);
|
||||
|
||||
const toolbar = screen.getByRole('toolbar', { name: 'selection_actions' });
|
||||
expect(within(toolbar).queryByRole('button', { name: 'Archive' })).toBeNull();
|
||||
const more = within(toolbar).getByRole('button', { name: 'more_actions' });
|
||||
// Not in the row that scrolls sideways, where it could end up out of sight.
|
||||
expect(more.closest('.overflow-x-auto')).toBeNull();
|
||||
fireEvent.click(more);
|
||||
expect(await screen.findByRole('menuitem', { name: 'Read text' })).toBeInTheDocument();
|
||||
await act(async () => { fireEvent.click(screen.getByRole('menuitem', { name: 'Archive' })); });
|
||||
const context = dispatch.mock.calls[0][3] as { files: FileResourceView[] };
|
||||
expect(context.files.map((f) => f.id)).toEqual(['f-notes']);
|
||||
});
|
||||
|
||||
it('filters the toolbar by the type of a single selected file', () => {
|
||||
act(() => setPluginActions('ocr', 'OCR', 'file-actions', [{ id: 'read-text', label: 'Read text', mimeTypes: ['text/'] }]));
|
||||
renderBrowser(['photo.png']);
|
||||
|
||||
@@ -138,8 +138,10 @@ export function FilesHeader({
|
||||
<ToolButton icon={Scissors} label={t("cut")} onClick={selection.onCut} compact />
|
||||
<ToolButton icon={Copy} label={t("copy")} onClick={selection.onCopy} compact />
|
||||
<ToolButton icon={Trash2} label={t("delete")} onClick={selection.onDelete} compact destructive />
|
||||
<SelectionPluginActions files={selection.pluginFiles} mimeType={selection.pluginMimeType} />
|
||||
{!compact && <SelectionPluginActions files={selection.pluginFiles} mimeType={selection.pluginMimeType} />}
|
||||
</div>
|
||||
{/* Outside the scrolling row, so the "more" button never scrolls out of sight. */}
|
||||
{compact && <SelectionPluginActions files={selection.pluginFiles} mimeType={selection.pluginMimeType} overflow />}
|
||||
<div className="flex-1" />
|
||||
<DetailsToggle showDetails={showDetails} onToggle={onToggleDetails} label={t("details")} />
|
||||
</div>
|
||||
@@ -434,8 +436,11 @@ function SortItem({ label, checked, onClick, icon: Icon }: {
|
||||
);
|
||||
}
|
||||
|
||||
/** Plugin buttons in the selection toolbar, icon-only like the app's own. */
|
||||
function SelectionPluginActions({ files, mimeType }: { files: FileResourceView[]; mimeType?: string }) {
|
||||
/**
|
||||
* Plugin buttons in the selection toolbar, icon-only like the app's own. On
|
||||
* phones the toolbar has no room for them: they go behind one "more" button.
|
||||
*/
|
||||
function SelectionPluginActions({ files, mimeType, overflow }: { files: FileResourceView[]; mimeType?: string; overflow?: boolean }) {
|
||||
const context = useMemo(() => ({ files }), [files]);
|
||||
return <PluginActions surface="file-actions" context={context} mimeType={mimeType} compact className="flex-nowrap gap-0.5" />;
|
||||
return <PluginActions surface="file-actions" context={context} mimeType={mimeType} compact overflow={overflow} className="flex-nowrap gap-0.5 flex-shrink-0" />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user