cleanup
This commit is contained in:
4
.envtempl
Normal file
4
.envtempl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# This is a sample / template enviroment file
|
||||||
|
# It is relativley straight forward and you dont need too many things to get started
|
||||||
|
DISCORD_BOT_TOKEN= # Your API key for Discord, you get this in your bot console
|
||||||
|
DISCORD_CHANNEL_ID= # your channel where you want the bot to deposit its contents
|
||||||
45
ComitsPaginatedView.py
Normal file
45
ComitsPaginatedView.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import PaginatedView
|
||||||
|
from CommitsSelectMenu import CommitSelectMenu
|
||||||
|
from typing import *
|
||||||
|
import datetime
|
||||||
|
from discord.ui import Select, SelectOption
|
||||||
|
import discord
|
||||||
|
|
||||||
|
BRANCH = "main"
|
||||||
|
|
||||||
|
class CommitsPaginatedView(PaginatedView):
|
||||||
|
"""Paginated view for commits"""
|
||||||
|
def __init__(self, commits: List[Dict], repo_info: str):
|
||||||
|
super().__init__(commits, page_size=5)
|
||||||
|
self.repo_info = repo_info
|
||||||
|
self.commits = commits
|
||||||
|
# Add file selection button
|
||||||
|
self.add_item(CommitSelectMenu(self.commits))
|
||||||
|
|
||||||
|
async def update_message(self, interaction: discord.Interaction):
|
||||||
|
embed = self.create_embed()
|
||||||
|
await interaction.response.edit_message(embed=embed, view=self)
|
||||||
|
|
||||||
|
def create_embed(self):
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"📚 Commits ({self.current_page + 1}/{self.total_pages})",
|
||||||
|
description=f"**Repository:** {self.repo_info}\n**Branch:** {BRANCH}",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
|
||||||
|
page_data = self.get_page_data()
|
||||||
|
for i, commit in enumerate(page_data, start=self.current_page * self.page_size):
|
||||||
|
msg = commit['commit']['message'].split('\n')[0][:80]
|
||||||
|
author = commit['commit']['author']['name']
|
||||||
|
sha = commit['sha'][:7]
|
||||||
|
date = datetime.fromisoformat(commit['commit']['committer']['date'].replace('Z', '+00:00'))
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name=f"{i+1}. `{sha}` by {author}",
|
||||||
|
value=f"```{msg}```\n🕒 {discord.utils.format_dt(date, 'R')}",
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.set_footer(text="Select a commit from the dropdown below to view details")
|
||||||
|
return embed
|
||||||
|
|
||||||
57
CommitsActionView.py
Normal file
57
CommitsActionView.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from typing import Dict, List
|
||||||
|
import discord
|
||||||
|
from discord.ui import View, Button
|
||||||
|
from FileBrowserSelect import FileBrowserSelect
|
||||||
|
|
||||||
|
class CommitActionsView(View):
|
||||||
|
"""Action buttons for a specific commit"""
|
||||||
|
def __init__(self, commit: Dict, files: List[Dict], timeout: int = 60):
|
||||||
|
super().__init__(timeout=timeout)
|
||||||
|
self.commit = commit
|
||||||
|
self.files = files
|
||||||
|
self.commit_sha = commit['sha']
|
||||||
|
self.commit_short = commit['sha'][:7]
|
||||||
|
|
||||||
|
# Link button that opens the commit in Gitea
|
||||||
|
link_button = Button(
|
||||||
|
label="🔗 Open in Gitea",
|
||||||
|
style=discord.ButtonStyle.link,
|
||||||
|
url=commit['html_url'],
|
||||||
|
emoji="🔗"
|
||||||
|
)
|
||||||
|
self.add_item(link_button)
|
||||||
|
|
||||||
|
# Add a file browser select if files exist
|
||||||
|
if files:
|
||||||
|
self.add_item(FileBrowserSelect(files, self.commit_sha))
|
||||||
|
|
||||||
|
@discord.ui.button(label="📊 View Diff", style=discord.ButtonStyle.primary)
|
||||||
|
async def view_diff(self, interaction: discord.Interaction, button: Button):
|
||||||
|
# Import here to avoid circular import with main.py
|
||||||
|
from main import show_commit_diff_interactive
|
||||||
|
await show_commit_diff_interactive(interaction, self.commit_sha)
|
||||||
|
|
||||||
|
@discord.ui.button(label="📁 Browse Files", style=discord.ButtonStyle.secondary)
|
||||||
|
async def browse_files(self, interaction: discord.Interaction, button: Button):
|
||||||
|
if not self.files:
|
||||||
|
await interaction.response.send_message("No files changed in this commit.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"📁 Files in commit `{self.commit_short}`",
|
||||||
|
description="Select a file to view its diff:",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
|
||||||
|
file_list = "\n".join([
|
||||||
|
f"• `{f['filename']}` (+{f.get('additions', 0)}/-{f.get('deletions', 0)})"
|
||||||
|
for f in self.files[:10]
|
||||||
|
])
|
||||||
|
if len(self.files) > 10:
|
||||||
|
file_list += f"\n... and {len(self.files) - 10} more"
|
||||||
|
|
||||||
|
embed.add_field(name="Changed Files", value=file_list, inline=False)
|
||||||
|
|
||||||
|
view = FileBrowserSelect(self.files, self.commit_sha)
|
||||||
|
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
|
||||||
|
|
||||||
36
CommitsSelectMenu.py
Normal file
36
CommitsSelectMenu.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import discord
|
||||||
|
from typing import *
|
||||||
|
from discord.ui import *
|
||||||
|
|
||||||
|
from main import create_commit_embed, fetch_commit_files
|
||||||
|
from CommitsActionView import CommitActionsView
|
||||||
|
|
||||||
|
class CommitSelectMenu(Select):
|
||||||
|
"""Dropdown menu for selecting a commit"""
|
||||||
|
def __init__(self, commits: List[Dict]):
|
||||||
|
options = [
|
||||||
|
discord.SelectOption(
|
||||||
|
label=f"{commit['sha'][:7]} - {commit['commit']['message'].split('\n')[0][:45]}",
|
||||||
|
value=str(i),
|
||||||
|
description=f"by {commit['commit']['author']['name']}"
|
||||||
|
)
|
||||||
|
for i, commit in enumerate(commits[:25]) # Discord limit: 25 options
|
||||||
|
]
|
||||||
|
super().__init__(
|
||||||
|
placeholder="📝 Select a commit to view details...",
|
||||||
|
min_values=1,
|
||||||
|
max_values=1,
|
||||||
|
options=options
|
||||||
|
)
|
||||||
|
self.commits = commits
|
||||||
|
|
||||||
|
async def callback(self, interaction: discord.Interaction):
|
||||||
|
selected_idx = int(self.values[0])
|
||||||
|
commit = self.commits[selected_idx]
|
||||||
|
|
||||||
|
# Fetch file info
|
||||||
|
files = await fetch_commit_files(commit['sha'])
|
||||||
|
|
||||||
|
embed = create_commit_embed(commit, files)
|
||||||
|
view = CommitActionsView(commit, files)
|
||||||
|
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
|
||||||
32
FileBrowserSelect.py
Normal file
32
FileBrowserSelect.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from discord.ui import *
|
||||||
|
import discord
|
||||||
|
from typing import *
|
||||||
|
from main import show_file_diff
|
||||||
|
|
||||||
|
class FileBrowserSelect(Select):
|
||||||
|
"""Dropdown for browsing files in a commit"""
|
||||||
|
def __init__(self, files: List[Dict], commit_sha: str):
|
||||||
|
options = [
|
||||||
|
discord.SelectOption(
|
||||||
|
label=f"{f['filename'][:45]}",
|
||||||
|
value=str(i),
|
||||||
|
description=f"+{f.get('additions', 0)}/-{f.get('deletions', 0)} - {f.get('status', 'modified')}"
|
||||||
|
)
|
||||||
|
for i, f in enumerate(files[:25])
|
||||||
|
]
|
||||||
|
super().__init__(
|
||||||
|
placeholder="📄 Select a file to view diff...",
|
||||||
|
min_values=1,
|
||||||
|
max_values=1,
|
||||||
|
options=options
|
||||||
|
)
|
||||||
|
self.files = files
|
||||||
|
self.commit_sha = commit_sha
|
||||||
|
|
||||||
|
async def callback(self, interaction: discord.Interaction):
|
||||||
|
selected_idx = int(self.values[0])
|
||||||
|
file_info = self.files[selected_idx]
|
||||||
|
filename = file_info['filename']
|
||||||
|
|
||||||
|
await show_file_diff(interaction, self.commit_sha, filename)
|
||||||
|
|
||||||
55
PaginatedView.py
Normal file
55
PaginatedView.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ui import View, Button
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
class PaginatedView(View):
|
||||||
|
"""Base class for paginated views"""
|
||||||
|
def __init__(self, data: List, page_size: int = 5, timeout: int = 60):
|
||||||
|
super().__init__(timeout=timeout)
|
||||||
|
self.data = data
|
||||||
|
self.page_size = page_size
|
||||||
|
self.current_page = 0
|
||||||
|
self.total_pages = (len(data) + page_size - 1) // page_size
|
||||||
|
self.update_buttons()
|
||||||
|
|
||||||
|
def update_buttons(self):
|
||||||
|
"""Enable/disable navigation buttons based on current page"""
|
||||||
|
self.children[0].disabled = self.current_page == 0 # First
|
||||||
|
self.children[1].disabled = self.current_page == 0 # Previous
|
||||||
|
self.children[2].disabled = self.current_page >= self.total_pages - 1 # Next
|
||||||
|
self.children[3].disabled = self.current_page >= self.total_pages - 1 # Last
|
||||||
|
|
||||||
|
def get_page_data(self):
|
||||||
|
"""Get data for current page"""
|
||||||
|
start = self.current_page * self.page_size
|
||||||
|
end = start + self.page_size
|
||||||
|
return self.data[start:end]
|
||||||
|
|
||||||
|
async def update_message(self, interaction: discord.Interaction):
|
||||||
|
"""Update the message with current page"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@discord.ui.button(emoji="⏪", style=discord.ButtonStyle.secondary)
|
||||||
|
async def first_page(self, interaction: discord.Interaction, button: Button):
|
||||||
|
self.current_page = 0
|
||||||
|
self.update_buttons()
|
||||||
|
await self.update_message(interaction)
|
||||||
|
|
||||||
|
@discord.ui.button(emoji="◀️", style=discord.ButtonStyle.secondary)
|
||||||
|
async def previous_page(self, interaction: discord.Interaction, button: Button):
|
||||||
|
self.current_page = max(0, self.current_page - 1)
|
||||||
|
self.update_buttons()
|
||||||
|
await self.update_message(interaction)
|
||||||
|
|
||||||
|
@discord.ui.button(emoji="▶️", style=discord.ButtonStyle.secondary)
|
||||||
|
async def next_page(self, interaction: discord.Interaction, button: Button):
|
||||||
|
self.current_page = min(self.total_pages - 1, self.current_page + 1)
|
||||||
|
self.update_buttons()
|
||||||
|
await self.update_message(interaction)
|
||||||
|
|
||||||
|
@discord.ui.button(emoji="⏩", style=discord.ButtonStyle.secondary)
|
||||||
|
async def last_page(self, interaction: discord.Interaction, button: Button):
|
||||||
|
self.current_page = self.total_pages - 1
|
||||||
|
self.update_buttons()
|
||||||
|
await self.update_message(interaction)
|
||||||
|
|
||||||
23
SearchModal.py
Normal file
23
SearchModal.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from discord.ui import *
|
||||||
|
import discord
|
||||||
|
|
||||||
|
from main import search_commits
|
||||||
|
|
||||||
|
class SearchModal(Modal):
|
||||||
|
"""Modal for searching commits"""
|
||||||
|
def __init__(self, search_type: str = "message"):
|
||||||
|
super().__init__(title=f"🔍 Search Commits by {search_type.capitalize()}")
|
||||||
|
self.search_type = search_type
|
||||||
|
|
||||||
|
self.search_term = TextInput(
|
||||||
|
label=f"Enter search term:",
|
||||||
|
placeholder=f"Search in commit {search_type}...",
|
||||||
|
min_length=2,
|
||||||
|
max_length=100
|
||||||
|
)
|
||||||
|
self.add_item(self.search_term)
|
||||||
|
|
||||||
|
async def on_submit(self, interaction: discord.Interaction):
|
||||||
|
await interaction.response.defer()
|
||||||
|
await search_commits(interaction, self.search_type, self.search_term.value)
|
||||||
|
|
||||||
0
__init__.py
Normal file
0
__init__.py
Normal file
250
main.py
250
main.py
@@ -7,6 +7,11 @@ from datetime import datetime
|
|||||||
from typing import List, Dict, Optional
|
from typing import List, Dict, Optional
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from CommitsActionView import CommitActionsView
|
||||||
|
import SearchModal
|
||||||
|
import FileBrowserSelect
|
||||||
|
from ComitsPaginatedView import CommitsPaginatedView
|
||||||
|
|
||||||
# Load environment variables from .env file
|
# Load environment variables from .env file
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -35,249 +40,6 @@ bot = commands.Bot(
|
|||||||
# Store last checked commit
|
# Store last checked commit
|
||||||
last_commit_sha = None
|
last_commit_sha = None
|
||||||
|
|
||||||
# ---------- UI COMPONENTS ----------
|
|
||||||
|
|
||||||
class PaginatedView(View):
|
|
||||||
"""Base class for paginated views"""
|
|
||||||
def __init__(self, data: List, page_size: int = 5, timeout: int = 60):
|
|
||||||
super().__init__(timeout=timeout)
|
|
||||||
self.data = data
|
|
||||||
self.page_size = page_size
|
|
||||||
self.current_page = 0
|
|
||||||
self.total_pages = (len(data) + page_size - 1) // page_size
|
|
||||||
self.update_buttons()
|
|
||||||
|
|
||||||
def update_buttons(self):
|
|
||||||
"""Enable/disable navigation buttons based on current page"""
|
|
||||||
self.children[0].disabled = self.current_page == 0 # First
|
|
||||||
self.children[1].disabled = self.current_page == 0 # Previous
|
|
||||||
self.children[2].disabled = self.current_page >= self.total_pages - 1 # Next
|
|
||||||
self.children[3].disabled = self.current_page >= self.total_pages - 1 # Last
|
|
||||||
|
|
||||||
def get_page_data(self):
|
|
||||||
"""Get data for current page"""
|
|
||||||
start = self.current_page * self.page_size
|
|
||||||
end = start + self.page_size
|
|
||||||
return self.data[start:end]
|
|
||||||
|
|
||||||
async def update_message(self, interaction: discord.Interaction):
|
|
||||||
"""Update the message with current page"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@discord.ui.button(emoji="⏪", style=discord.ButtonStyle.secondary)
|
|
||||||
async def first_page(self, interaction: discord.Interaction, button: Button):
|
|
||||||
self.current_page = 0
|
|
||||||
self.update_buttons()
|
|
||||||
await self.update_message(interaction)
|
|
||||||
|
|
||||||
@discord.ui.button(emoji="◀️", style=discord.ButtonStyle.secondary)
|
|
||||||
async def previous_page(self, interaction: discord.Interaction, button: Button):
|
|
||||||
self.current_page = max(0, self.current_page - 1)
|
|
||||||
self.update_buttons()
|
|
||||||
await self.update_message(interaction)
|
|
||||||
|
|
||||||
@discord.ui.button(emoji="▶️", style=discord.ButtonStyle.secondary)
|
|
||||||
async def next_page(self, interaction: discord.Interaction, button: Button):
|
|
||||||
self.current_page = min(self.total_pages - 1, self.current_page + 1)
|
|
||||||
self.update_buttons()
|
|
||||||
await self.update_message(interaction)
|
|
||||||
|
|
||||||
@discord.ui.button(emoji="⏩", style=discord.ButtonStyle.secondary)
|
|
||||||
async def last_page(self, interaction: discord.Interaction, button: Button):
|
|
||||||
self.current_page = self.total_pages - 1
|
|
||||||
self.update_buttons()
|
|
||||||
await self.update_message(interaction)
|
|
||||||
|
|
||||||
|
|
||||||
class CommitsPaginatedView(PaginatedView):
|
|
||||||
"""Paginated view for commits"""
|
|
||||||
def __init__(self, commits: List[Dict], repo_info: str):
|
|
||||||
super().__init__(commits, page_size=5)
|
|
||||||
self.repo_info = repo_info
|
|
||||||
self.commits = commits
|
|
||||||
# Add file selection button
|
|
||||||
self.add_item(CommitSelectMenu(self.commits))
|
|
||||||
|
|
||||||
async def update_message(self, interaction: discord.Interaction):
|
|
||||||
embed = self.create_embed()
|
|
||||||
await interaction.response.edit_message(embed=embed, view=self)
|
|
||||||
|
|
||||||
def create_embed(self):
|
|
||||||
embed = discord.Embed(
|
|
||||||
title=f"📚 Commits ({self.current_page + 1}/{self.total_pages})",
|
|
||||||
description=f"**Repository:** {self.repo_info}\n**Branch:** {BRANCH}",
|
|
||||||
color=discord.Color.blue()
|
|
||||||
)
|
|
||||||
|
|
||||||
page_data = self.get_page_data()
|
|
||||||
for i, commit in enumerate(page_data, start=self.current_page * self.page_size):
|
|
||||||
msg = commit['commit']['message'].split('\n')[0][:80]
|
|
||||||
author = commit['commit']['author']['name']
|
|
||||||
sha = commit['sha'][:7]
|
|
||||||
date = datetime.fromisoformat(commit['commit']['committer']['date'].replace('Z', '+00:00'))
|
|
||||||
|
|
||||||
embed.add_field(
|
|
||||||
name=f"{i+1}. `{sha}` by {author}",
|
|
||||||
value=f"```{msg}```\n🕒 {discord.utils.format_dt(date, 'R')}",
|
|
||||||
inline=False
|
|
||||||
)
|
|
||||||
|
|
||||||
embed.set_footer(text="Select a commit from the dropdown below to view details")
|
|
||||||
return embed
|
|
||||||
|
|
||||||
|
|
||||||
class CommitSelectMenu(Select):
|
|
||||||
"""Dropdown menu for selecting a commit"""
|
|
||||||
def __init__(self, commits: List[Dict]):
|
|
||||||
options = [
|
|
||||||
discord.SelectOption(
|
|
||||||
label=f"{commit['sha'][:7]} - {commit['commit']['message'].split('\n')[0][:45]}",
|
|
||||||
value=str(i),
|
|
||||||
description=f"by {commit['commit']['author']['name']}"
|
|
||||||
)
|
|
||||||
for i, commit in enumerate(commits[:25]) # Discord limit: 25 options
|
|
||||||
]
|
|
||||||
super().__init__(
|
|
||||||
placeholder="📝 Select a commit to view details...",
|
|
||||||
min_values=1,
|
|
||||||
max_values=1,
|
|
||||||
options=options
|
|
||||||
)
|
|
||||||
self.commits = commits
|
|
||||||
|
|
||||||
async def callback(self, interaction: discord.Interaction):
|
|
||||||
selected_idx = int(self.values[0])
|
|
||||||
commit = self.commits[selected_idx]
|
|
||||||
|
|
||||||
# Fetch file info
|
|
||||||
files = await fetch_commit_files(commit['sha'])
|
|
||||||
|
|
||||||
embed = create_commit_embed(commit, files)
|
|
||||||
view = CommitActionsView(commit, files)
|
|
||||||
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
|
|
||||||
|
|
||||||
|
|
||||||
class CommitActionsView(View):
|
|
||||||
"""Action buttons for a specific commit"""
|
|
||||||
def __init__(self, commit: Dict, files: List[Dict], timeout: int = 60):
|
|
||||||
super().__init__(timeout=timeout)
|
|
||||||
self.commit = commit
|
|
||||||
self.files = files
|
|
||||||
self.commit_sha = commit['sha']
|
|
||||||
self.commit_short = commit['sha'][:7]
|
|
||||||
|
|
||||||
# 1. Regular buttons with callbacks
|
|
||||||
view_diff_button = Button(
|
|
||||||
label="📊 View Diff",
|
|
||||||
style=discord.ButtonStyle.primary,
|
|
||||||
custom_id=f"view_diff_{self.commit_short}"
|
|
||||||
)
|
|
||||||
view_diff_button.callback = self.view_diff_callback
|
|
||||||
self.add_item(view_diff_button)
|
|
||||||
|
|
||||||
browse_files_button = Button(
|
|
||||||
label="📁 Browse Files",
|
|
||||||
style=discord.ButtonStyle.secondary,
|
|
||||||
custom_id=f"browse_files_{self.commit_short}"
|
|
||||||
)
|
|
||||||
browse_files_button.callback = self.browse_files_callback
|
|
||||||
self.add_item(browse_files_button)
|
|
||||||
|
|
||||||
# 2. Link button - MUST have a URL, not a callback
|
|
||||||
if 'html_url' in commit and commit['html_url']:
|
|
||||||
link_button = Button(
|
|
||||||
label="🔗 Open in Gitea",
|
|
||||||
style=discord.ButtonStyle.link,
|
|
||||||
url=commit['html_url'] # Required for link buttons
|
|
||||||
)
|
|
||||||
self.add_item(link_button)
|
|
||||||
else:
|
|
||||||
# If no URL, disable the button
|
|
||||||
disabled_button = Button(
|
|
||||||
label="🔗 No Link Available",
|
|
||||||
style=discord.ButtonStyle.secondary,
|
|
||||||
disabled=True
|
|
||||||
)
|
|
||||||
self.add_item(disabled_button)
|
|
||||||
|
|
||||||
# 3. Add file browser dropdown if files exist
|
|
||||||
if files:
|
|
||||||
self.add_item(FileBrowserSelect(files, self.commit_sha))
|
|
||||||
|
|
||||||
async def view_diff_callback(self, interaction: discord.Interaction):
|
|
||||||
"""Callback for viewing diff"""
|
|
||||||
await interaction.response.defer(ephemeral=True)
|
|
||||||
await show_commit_diff_interactive(interaction, self.commit_sha)
|
|
||||||
|
|
||||||
async def browse_files_callback(self, interaction: discord.Interaction):
|
|
||||||
"""Callback for browsing files"""
|
|
||||||
if not self.files:
|
|
||||||
await interaction.response.send_message("No files changed in this commit.", ephemeral=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
embed = discord.Embed(
|
|
||||||
title=f"📁 Files in commit `{self.commit_short}`",
|
|
||||||
description="Select a file to view its diff:",
|
|
||||||
color=discord.Color.blue()
|
|
||||||
)
|
|
||||||
|
|
||||||
file_list = "\n".join([f"• `{f['filename']}` (+{f.get('additions', 0)}/-{f.get('deletions', 0)})"
|
|
||||||
for f in self.files[:10]])
|
|
||||||
if len(self.files) > 10:
|
|
||||||
file_list += f"\n... and {len(self.files) - 10} more"
|
|
||||||
|
|
||||||
embed.add_field(name="Changed Files", value=file_list, inline=False)
|
|
||||||
|
|
||||||
view = FileBrowserSelect(self.files, self.commit_sha)
|
|
||||||
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
|
|
||||||
|
|
||||||
class FileBrowserSelect(Select):
|
|
||||||
"""Dropdown for browsing files in a commit"""
|
|
||||||
def __init__(self, files: List[Dict], commit_sha: str):
|
|
||||||
options = [
|
|
||||||
discord.SelectOption(
|
|
||||||
label=f"{f['filename'][:45]}",
|
|
||||||
value=str(i),
|
|
||||||
description=f"+{f.get('additions', 0)}/-{f.get('deletions', 0)} - {f.get('status', 'modified')}"
|
|
||||||
)
|
|
||||||
for i, f in enumerate(files[:25])
|
|
||||||
]
|
|
||||||
super().__init__(
|
|
||||||
placeholder="📄 Select a file to view diff...",
|
|
||||||
min_values=1,
|
|
||||||
max_values=1,
|
|
||||||
options=options
|
|
||||||
)
|
|
||||||
self.files = files
|
|
||||||
self.commit_sha = commit_sha
|
|
||||||
|
|
||||||
async def callback(self, interaction: discord.Interaction):
|
|
||||||
selected_idx = int(self.values[0])
|
|
||||||
file_info = self.files[selected_idx]
|
|
||||||
filename = file_info['filename']
|
|
||||||
|
|
||||||
await show_file_diff(interaction, self.commit_sha, filename)
|
|
||||||
|
|
||||||
|
|
||||||
class SearchModal(Modal):
|
|
||||||
"""Modal for searching commits"""
|
|
||||||
def __init__(self, search_type: str = "message"):
|
|
||||||
super().__init__(title=f"🔍 Search Commits by {search_type.capitalize()}")
|
|
||||||
self.search_type = search_type
|
|
||||||
|
|
||||||
self.search_term = TextInput(
|
|
||||||
label=f"Enter search term:",
|
|
||||||
placeholder=f"Search in commit {search_type}...",
|
|
||||||
min_length=2,
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
self.add_item(self.search_term)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
await interaction.response.defer()
|
|
||||||
await search_commits(interaction, self.search_type, self.search_term.value)
|
|
||||||
|
|
||||||
|
|
||||||
# ---------- API FUNCTIONS ----------
|
# ---------- API FUNCTIONS ----------
|
||||||
|
|
||||||
async def fetch_commits(limit=10, sha=None):
|
async def fetch_commits(limit=10, sha=None):
|
||||||
@@ -297,7 +59,6 @@ async def fetch_commits(limit=10, sha=None):
|
|||||||
print(f"Exception fetching commits: {e}")
|
print(f"Exception fetching commits: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def fetch_commit_files(sha):
|
async def fetch_commit_files(sha):
|
||||||
"""Fetch file changes for a specific commit"""
|
"""Fetch file changes for a specific commit"""
|
||||||
try:
|
try:
|
||||||
@@ -331,7 +92,6 @@ async def fetch_commit_diff(sha):
|
|||||||
print(f"Exception fetching diff: {e}")
|
print(f"Exception fetching diff: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def format_diff_stats(files):
|
def format_diff_stats(files):
|
||||||
"""Format file changes into a readable string"""
|
"""Format file changes into a readable string"""
|
||||||
if not files:
|
if not files:
|
||||||
|
|||||||
Reference in New Issue
Block a user