mirror of
https://github.com/natankeddem/bale.git
synced 2026-04-23 06:50:41 +00:00
improved browse and find
This commit is contained in:
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
import stat
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
from nicegui import app, events, ui
|
||||
from nicegui import app, background_tasks, events, ui
|
||||
from fastapi.responses import StreamingResponse
|
||||
import asyncssh
|
||||
from bale import elements as el
|
||||
@@ -87,7 +87,7 @@ class SshFileBrowse(ui.dialog):
|
||||
row.tailwind.height("[40px]")
|
||||
el.DButton("Download", on_click=self._start_download)
|
||||
ui.button("Exit", on_click=lambda: self.submit("exit"))
|
||||
await self._update_grid()
|
||||
await self._update_handler()
|
||||
|
||||
async def _connect(self) -> Tuple[asyncssh.SSHClientConnection, asyncssh.SFTPClient]:
|
||||
ssh = await asyncssh.connect(self._zfs.hostname, username=self._zfs.username, client_keys=[self._zfs.key_path])
|
||||
@@ -137,7 +137,7 @@ class SshFileBrowse(ui.dialog):
|
||||
"permissions": attributes.permissions,
|
||||
}
|
||||
|
||||
async def _update_grid(self) -> None:
|
||||
async def _update_handler(self) -> None:
|
||||
self._grid.call_api_method("showLoadingOverlay")
|
||||
if self._ssh is None or self._sftp is None:
|
||||
self._ssh, self._sftp = await self._connect()
|
||||
@@ -165,7 +165,7 @@ class SshFileBrowse(ui.dialog):
|
||||
async def _handle_double_click(self, e: events.GenericEventArguments) -> None:
|
||||
self.path = e.args["data"]["path"]
|
||||
if e.args["data"]["type"] == "directory":
|
||||
await self._update_grid()
|
||||
await self._update_handler()
|
||||
else:
|
||||
await self._start_download(e)
|
||||
|
||||
@@ -226,8 +226,10 @@ class SshFileFind(SshFileBrowse):
|
||||
with el.DBody(height="fit", width="[90vw]"):
|
||||
with el.WColumn().classes("col"):
|
||||
filesystems = await self._zfs.filesystems
|
||||
self._filesystem = el.DSelect(list(filesystems.data.keys()), label="filesystem", with_input=True, on_change=self._update_grid)
|
||||
self._pattern = el.DInput("Pattern", on_change=self._update_grid)
|
||||
self._filesystem = el.DSelect(list(filesystems.data.keys()), label="filesystem", with_input=True, on_change=self._update_handler)
|
||||
with el.WRow():
|
||||
self._pattern = ui.input("Pattern").classes("col").on("keydown.enter", handler=self._update_handler)
|
||||
el.LgButton(icon="search", on_click=self._update_handler)
|
||||
self._grid = ui.aggrid(
|
||||
{
|
||||
"defaultColDef": {"flex": 1, "sortable": True, "suppressMovable": True, "sortingOrder": ["asc", "desc"]},
|
||||
@@ -264,15 +266,21 @@ class SshFileFind(SshFileBrowse):
|
||||
row.tailwind.height("[40px]")
|
||||
el.DButton("Download", on_click=self._start_download)
|
||||
ui.button("Exit", on_click=lambda: self.submit("exit"))
|
||||
await self._update_grid()
|
||||
self._grid.call_api_method("hideOverlay")
|
||||
|
||||
async def _update_grid(self) -> None:
|
||||
self._grid.call_api_method("showLoadingOverlay")
|
||||
if self._filesystem is not None:
|
||||
async def _update_handler(self) -> None:
|
||||
if len(self._pattern.value) > 0 and self._filesystem is not None:
|
||||
self._grid.call_api_method("showLoadingOverlay")
|
||||
self._filesystem.props("readonly")
|
||||
self._pattern.props("readonly")
|
||||
files = await self._zfs.find_files_in_snapshots(filesystem=self._filesystem.value, pattern=self._pattern.value)
|
||||
self._grid.options["rowData"] = files.data
|
||||
self._grid.update()
|
||||
self._grid.call_api_method("hideOverlay")
|
||||
if files.truncated is True:
|
||||
el.notify("Too many files found, truncating list.", type="warning")
|
||||
self._grid.update()
|
||||
self._filesystem.props(remove="readonly")
|
||||
self._pattern.props(remove="readonly")
|
||||
self._grid.call_api_method("hideOverlay")
|
||||
|
||||
async def _handle_double_click(self, e: events.GenericEventArguments) -> None:
|
||||
await self._start_download(e)
|
||||
|
||||
@@ -166,27 +166,28 @@ class Zfs:
|
||||
return result
|
||||
|
||||
async def find_files_in_snapshots(self, filesystem: str, pattern: str) -> Result:
|
||||
filesystems = await self.filesystems
|
||||
if filesystem in filesystems.data.keys():
|
||||
if "mountpoint" in filesystems.data[filesystem]:
|
||||
command = f"find {filesystems.data[filesystem]['mountpoint']}/.zfs/snapshot -type f -name '{pattern}' -printf '%h\t%f\t%s\t%T@\n'"
|
||||
result = await self.execute(command=command, notify=False)
|
||||
files = []
|
||||
for line in result.stdout_lines:
|
||||
matches = re.match(
|
||||
"^(?P<location>[^\t]+)\t(?P<name>[^\t]+)\t(?P<bytes>[^\t]+)\t(?P<modified_timestamp>[^\n]+)",
|
||||
line,
|
||||
)
|
||||
if matches is not None:
|
||||
md = matches.groupdict()
|
||||
md["path"] = f"{md['location']}/{md['name']}"
|
||||
md["bytes"] = int(md["bytes"])
|
||||
md["size"] = format_bytes(md["bytes"])
|
||||
md["modified_datetime"] = datetime.fromtimestamp(float(md["modified_timestamp"])).strftime("%Y/%m/%d %H:%M:%S")
|
||||
md["modified_timestamp"] = float(md["modified_timestamp"])
|
||||
files.append(md)
|
||||
result.data = files
|
||||
return result
|
||||
try:
|
||||
filesystems = await self.filesystems
|
||||
command = f"find {filesystems.data[filesystem]['mountpoint']}/.zfs/snapshot -type f -name '{pattern}' -printf '%h\t%f\t%s\t%T@\n'"
|
||||
result = await self.execute(command=command, notify=False, max_output_lines=1000)
|
||||
files = []
|
||||
for line in result.stdout_lines:
|
||||
matches = re.match(
|
||||
"^(?P<location>[^\t]+)\t(?P<name>[^\t]+)\t(?P<bytes>[^\t]+)\t(?P<modified_timestamp>[^\n]+)",
|
||||
line,
|
||||
)
|
||||
if matches is not None:
|
||||
md = matches.groupdict()
|
||||
md["path"] = f"{md['location']}/{md['name']}"
|
||||
md["bytes"] = int(md["bytes"])
|
||||
md["size"] = format_bytes(md["bytes"])
|
||||
md["modified_datetime"] = datetime.fromtimestamp(float(md["modified_timestamp"])).strftime("%Y/%m/%d %H:%M:%S")
|
||||
md["modified_timestamp"] = float(md["modified_timestamp"])
|
||||
files.append(md)
|
||||
result.data = files
|
||||
return result
|
||||
except KeyError:
|
||||
pass
|
||||
return Result()
|
||||
|
||||
@property
|
||||
|
||||
@@ -111,9 +111,12 @@ class Manage(Tab):
|
||||
result = await SelectionConfirm(container=self._confirm, label=">BROWSE<")
|
||||
if result == "confirm":
|
||||
rows = await self._grid.get_selected_rows()
|
||||
filesystems = await self.zfs.filesystems
|
||||
mount_path = filesystems.data[rows[0]["filesystem"]]["mountpoint"]
|
||||
await sshdl.SshFileBrowse(zfs=self.zfs, path=f"{mount_path}/.zfs/snapshot/{rows[0]['name']}")
|
||||
try:
|
||||
filesystems = await self.zfs.filesystems
|
||||
mount_path = filesystems.data[rows[0]["filesystem"]]["mountpoint"]
|
||||
await sshdl.SshFileBrowse(zfs=self.zfs, path=f"{mount_path}/.zfs/snapshot/{rows[0]['name']}")
|
||||
except KeyError:
|
||||
el.notify(f"Unable to browse {rows[0]['filesystem']}", type="warning")
|
||||
self._set_selection()
|
||||
|
||||
async def _find(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user