local_file_picker.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. from pathlib import Path
  2. from typing import Optional
  3. from nicegui import ui
  4. class local_file_picker(ui.dialog):
  5. def __init__(self, directory: str, *,
  6. upper_limit: Optional[str] = ..., multiple: bool = False, show_hidden_files: bool = False) -> None:
  7. """Local File Picker
  8. This is a simple file picker that allows you to select a file from the local filesystem where NiceGUI is running.
  9. :param directory: The directory to start in.
  10. :param upper_limit: The directory to stop at (None: no limit, default: same as the starting directory).
  11. :param multiple: Whether to allow multiple files to be selected.
  12. :param show_hidden_files: Whether to show hidden files.
  13. """
  14. super().__init__()
  15. self.path = Path(directory).expanduser()
  16. if upper_limit is None:
  17. self.upper_limit = None
  18. else:
  19. self.upper_limit = Path(directory if upper_limit == ... else upper_limit).expanduser()
  20. self.show_hidden_files = show_hidden_files
  21. with self, ui.card():
  22. self.grid = ui.aggrid({
  23. 'columnDefs': [{'field': 'name', 'headerName': 'File'}],
  24. 'rowSelection': 'multiple' if multiple else 'single',
  25. }, html_columns=[0]).classes('w-96').on('cellDoubleClicked', self.handle_double_click)
  26. with ui.row().classes('w-full justify-end'):
  27. ui.button('Cancel', on_click=self.close).props('outline')
  28. ui.button('Ok', on_click=self._handle_ok)
  29. self.update_grid()
  30. def update_grid(self) -> None:
  31. paths = list(self.path.glob('*'))
  32. if not self.show_hidden_files:
  33. paths = [p for p in paths if not p.name.startswith('.')]
  34. paths.sort(key=lambda p: p.name.lower())
  35. paths.sort(key=lambda p: not p.is_dir())
  36. self.grid.options['rowData'] = [
  37. {
  38. 'name': f'📁 <strong>{p.name}</strong>' if p.is_dir() else p.name,
  39. 'path': str(p),
  40. }
  41. for p in paths
  42. ]
  43. if self.upper_limit is None and self.path != self.path.parent or \
  44. self.upper_limit is not None and self.path != self.upper_limit:
  45. self.grid.options['rowData'].insert(0, {
  46. 'name': '📁 <strong>..</strong>',
  47. 'path': str(self.path.parent),
  48. })
  49. self.grid.update()
  50. async def handle_double_click(self, msg: dict) -> None:
  51. self.path = Path(msg['args']['data']['path'])
  52. if self.path.is_dir():
  53. self.update_grid()
  54. else:
  55. self.submit([str(self.path)])
  56. async def _handle_ok(self):
  57. rows = await ui.run_javascript(f'getElement({self.grid.id}).gridOptions.api.getSelectedRows()')
  58. self.submit([r['path'] for r in rows])