Files
GiTui/screens/search_screen.py

135 lines
4.0 KiB
Python

from textual.screen import Screen
from textual.widgets import Input, Select, LoadingIndicator, Static
from textual.containers import HorizontalGroup, ScrollableContainer
from textual.app import ComposeResult
from textual import work
from widgets import Navbar
from screens.repo_view_screen import RepoViewScreen
from human_readable import time_delta
from datetime import datetime, timedelta
import requests
class SearchResult(HorizontalGroup):
DEFAULT_CSS = """
SearchResult {
padding: 0 1;
margin: 0 1;
margin-top: 1;
border: tall $surface;
Static {
width: auto;
link-style: bold;
link-color: $primary;
}
}
"""
def __init__(
self,
repo_data: dict
):
super().__init__()
self.repo_data = repo_data
self.author = repo_data["owner"]
self.repo_name = repo_data["name"]
self.description = repo_data["description"]
self.is_fork = repo_data["fork"]
self.updated_at = datetime.fromisoformat(repo_data["updated_at"]).replace(tzinfo=None)
def compose(self) -> ComposeResult:
updated_string = time_delta(datetime.now() - self.updated_at)
yield Static(f"[@click='view_user({self.author["id"]})']{self.author["login"]}[/] / [@click='screen.view_repo(\"{self.author["login"]}\",\"{self.repo_name}\")']{self.repo_name}[/]{' [d]\[[cyan]fork[/]]' if self.is_fork else ''}\n{self.description}\n[d]Updated {updated_string} ago")
class SearchScreen(Screen):
DEFAULT_CSS = """
#search-box {
padding: 1;
padding-bottom: 0;
border-bottom: hkey $surface;
#query {
width: 1fr;
}
Select {
width: 25;
}
}
"""
def action_view_repo(self, author: str, repo_name: str):
self.app.switch_screen(RepoViewScreen(author, repo_name))
@work(exclusive=True)
async def action_search_query(self):
query_input = self.query_one("#query")
loading = self.query_one(LoadingIndicator)
results = self.query_one(ScrollableContainer)
loading.display = True
# send off a request
response = requests.get(
url=self.app.GITEA_HOST + "api/v1/repos/search",
params={
"q": query_input.value,
"limit": 20
}
)
loading.display = False
# error handling
if not response.ok:
self.notify(response.text, title="Error while getting search results:", severity="error")
return
# display results
results.remove_children(SearchResult)
to_mount = []
for result in response.json()["data"]:
to_mount.append(SearchResult(result))
results.mount_all(to_mount)
# self explanitory
query_input.clear()
query_input.focus()
def on_input_submitted(self, event: Input.Submitted):
if event.input.id == "query":
self.action_search_query()
def on_mount(self):
self.action_search_query()
#self.query_one(LoadingIndicator).display = False
def compose(self) -> ComposeResult:
yield Navbar()
with HorizontalGroup(id="search-box"):
yield Input(placeholder="Search repos...", id="query")
yield Select.from_values([
"Alphabetical",
"Creation date",
"Last updated",
"Size",
"ID"
], id="sort-select", allow_blank=False, value="Last updated")
yield Select.from_values([
"Ascending",
"Descending"
], id="order-select", allow_blank=False, value="Ascending")
yield Select.from_values([
"Repositories",
"Users",
], id="search-select", allow_blank=False, value="Repositories")
with ScrollableContainer(id="results"):
yield LoadingIndicator()