Files
GiTui/screens/repo_view_screen.py

225 lines
8.1 KiB
Python

from textual.screen import Screen
from textual.app import ComposeResult
from textual.widgets import Input, Select, LoadingIndicator, Static, DataTable, ContentSwitcher, Tabs, Tab, Button
from textual.containers import VerticalGroup, Vertical, HorizontalGroup, Right
from textual import work
from widgets import Navbar
from datetime import datetime
from human_readable import time_delta
import requests
class RepoViewScreen(Screen):
CSS_PATH = "../assets/repo_view_screen.tcss"
def __init__(self, owner_name: str, repo_name: str):
super().__init__()
self.owner_name = owner_name
self.repo_name = repo_name
def get_icon_from_name_and_type(self, file_name: str, is_folder: bool):
# nerd font icons my beloved
if not is_folder:
if not "." in file_name:
match file_name:
case "Makefile":
return "\ue673"
case "Dockerfile":
return "\ue7b0"
case "requirements.txt":
return "\ue73c"
case "LICENSE":
return "\uf1f9"
case _:
return "\uf15b"
extension = file_name[file_name.index(".")+1:]
match extension:
case 'c' | 'h':
return "\ue61e"
case 'cpp':
return "\ue61d"
case 'py':
return "\ue73c"
case 'js':
return "\ue781"
case 'json':
return "\ueb0f"
case 'gitignore' | 'gitmodules':
return "\ue702"
case 'html' | 'htm':
return "\ue736"
case 'css' | 'tcss':
return "\ue749"
case 'svg':
return "\ue698"
case 'ico':
return "\ue623"
case 'go':
return "\ue65e"
case 'rs':
return "\ue7a8"
case 'grnd':
return "\uf44f"
case 'md':
return "\ueb1d"
case 'fish':
return "\uee41"
case 'sh':
return "\ue760"
case 'bat':
return "\ue70f"
case 'png' | 'jpg' | 'jpeg' | 'avif':
return "\uf03e"
case 'lua':
return "\ue620"
case 'zip' | 'tar' | 'gz' | "7z":
return "\ue6aa"
case _:
return "\uf15b"
else:
return "\ue5ff"
@work(thread=True, exclusive=True)
def on_mount(self):
files: DataTable = self.query_one("#files")
loading = self.query_one(LoadingIndicator)
files.display = False
# get files in root dir
files_response = requests.get(
self.app.GITEA_HOST + f"api/v1/repos/{self.owner_name}/{self.repo_name}/contents"
)
loading.display = False
if not files_response.ok:
self.notify(files_response.text, title="Failed to get files:", severity="error")
return
# get most recent commit
commits_response = requests.get(
self.app.GITEA_HOST + f"api/v1/repos/{self.owner_name}/{self.repo_name}/commits",
params={
"limit": 1
}
)
if not commits_response.ok:
self.notify(commits_response.text, title="Failed to get most recent commit:", severity="error")
return
most_recent_commit = commits_response.json()[0]
files.add_columns(
f"[b]{most_recent_commit["author"]["login"]}[/]",
f"[r]{most_recent_commit["sha"][:10]}[/]",
f"[d]{most_recent_commit["commit"]["message"]}"
)
rows = []
commit_page_number = 1
page_size = 50
commit_data = {}
while True:
commits = requests.get(
self.app.GITEA_HOST + f"api/v1/repos/{self.owner_name}/{self.repo_name}/commits",
params={
#"path": ".",
"verification": False,
"files": False,
"page": commit_page_number,
"limit": page_size
}
).json()
commit_data.update({commit["sha"]: commit for commit in commits})
if len(commits) == page_size: # we reached end of the page
commit_page_number += 1
else:
break
for file in files_response.json():
commit = commit_data[file["last_commit_sha"]]
commit_created_at = datetime.fromisoformat(commit["created"]).replace(tzinfo=None)
rows.append((
f"[cyan]{self.get_icon_from_name_and_type(file["name"], file["type"] != "file")}[/] {file["name"]}",
f"[d]{commit["commit"]["message"]}",
f"[d]Updated {time_delta(datetime.now() - commit_created_at)} ago"
))
files.add_rows(rows)
files.display = True
def compose(self) -> ComposeResult:
# get repo data via a request
response = requests.get(
url=self.app.GITEA_HOST + f"api/v1/repos/{self.owner_name}/{self.repo_name}"
)
if not response.ok:
self.notify(response.text, title="Failed to get repo:", severity="error")
yield Navbar()
return
data = response.json()
yield Navbar()
with VerticalGroup(id="top"):
with HorizontalGroup():
yield Static(f" {self.owner_name}/[b]{self.repo_name}[/]", id="title")
with Right(id="buttons"):
yield Button("Star [d](0)", variant="warning", flat=True)
yield Button("Watch [d](0)", flat=True)
yield Tabs(
"\uf44f Code",
"\uebf8 Issues",
"\ue726 Pull Requests",
"\uf500 Actions",
"\ueb29 Packages",
"\uf502 Projects",
"\uf02b Releases",
"\ueaa4 Wiki",
"\uf21e Activity"
)
with ContentSwitcher(initial="Code"):
with HorizontalGroup(id="Code"):
with Vertical(id="commits"):
with HorizontalGroup(id="branch-info"):
yield Static("\uf4b6 1 Commits")
yield Static("\uf418 1 Branch")
yield Static("\uf02b 0 Tags")
with HorizontalGroup(id="branch-options"):
yield Select.from_values([
"main"
], allow_blank=False, id="branch")
yield Button("\ue726", flat=True, id="new-pull-request", tooltip="New Pull Request")
yield Button("Go to file", flat=True)
table = DataTable(id="files", show_cursor=False)
#table.add_columns("SpookyDervish [r]9b32c417e9[/]", "switched from tabs to spaces", "51 minutes ago")
#table.add_row("\ue5ff screens", "[d]switched from tabs to spaces", "[d]51 minutes ago")
yield table
yield LoadingIndicator()
with Vertical(id="repo-info"):
with HorizontalGroup():
yield Input("Search code...", id="search-query")
yield Button("\uf002", flat=True, id="search-btn")
yield Static("\n[b] Description")
yield Static("[d]" + data["description"], id="description")