Paginator viewing for issues, merge requests, and milestones

This commit is contained in:
Zeva Rose 2021-07-23 13:47:04 -06:00
parent 2ba042aedc
commit 5622209f4d
2 changed files with 221 additions and 113 deletions

View file

@ -34,7 +34,8 @@ class ErrorHandlerCog(commands.Cog):
) )
else: else:
await ctx.send( await ctx.send(
f"Error processing command:\n```{error}```", hidden=True f"Error processing command:\n```{error}```",
hidden=True,
) )

View file

@ -17,36 +17,6 @@ from jarvis.utils.field import Field
guild_ids = [862402786116763668] guild_ids = [862402786116763668]
def create_layout(command: str):
buttons = [
manage_components.create_button(
style=ButtonStyle.gray, emoji="", custom_id=f"back_{command}"
),
manage_components.create_button(
style=ButtonStyle.gray,
emoji="",
custom_id=f"next_{command}",
),
]
action_row = manage_components.spread_to_rows(*buttons, max_in_row=2)
return action_row
def create_issues_layout():
return create_layout("issues")
def edit_paging_components(
components: list, disable_left: bool = False, disable_right: bool = False
):
components[0]["components"][0]["disabled"] = disable_left
components[0]["components"][1]["disabled"] = disable_right
return components
command_lookup = {"issues": create_issues_layout}
class GitlabCog(commands.Cog): class GitlabCog(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -200,7 +170,7 @@ class GitlabCog(commands.Cog):
@cog_ext.cog_subcommand( @cog_ext.cog_subcommand(
base="gl", base="gl",
name="mr", name="mergerequest",
description="Get an merge request from GitLab", description="Get an merge request from GitLab",
guild_ids=guild_ids, guild_ids=guild_ids,
options=[ options=[
@ -212,7 +182,7 @@ class GitlabCog(commands.Cog):
) )
], ],
) )
async def _mr(self, ctx: SlashContext, id: int): async def _mergerequest(self, ctx: SlashContext, id: int):
try: try:
mr = self.project.mergerequests.get(int(id)) mr = self.project.mergerequests.get(int(id))
except gitlab.exceptions.GitlabGetError: except gitlab.exceptions.GitlabGetError:
@ -283,23 +253,28 @@ class GitlabCog(commands.Cog):
) )
await ctx.send(embed=embed) await ctx.send(embed=embed)
def build_embed_page(self, issues: list, t_state: str): def build_embed_page(self, api_list: list, t_state: str, name: str):
title = ""
if t_state:
title = f"{t_state} "
title += f"J.A.R.V.I.S. {name}s"
fields = [] fields = []
for issue in issues: for item in api_list:
fields.append( fields.append(
Field( Field(
name=f"[#{issue.iid}] {issue.title}", name=f"[#{item.iid}] {item.title}",
value=issue.description value=item.description
+ f"\n\n[View this issue]({issue.web_url})", + f"\n\n[View this {name}]({item.web_url})",
inline=False, inline=False,
) )
) )
embed = build_embed( embed = build_embed(
title=f"{t_state} J.A.R.V.I.S. issues", title=title,
description="", description="",
fields=fields, fields=fields,
url="https://git.zevaryx.com/stark-industries/j.a.r.v.i.s./issues", url="https://git.zevaryx.com/stark-industries/j.a.r.v.i.s./"
+ f"{name.replace(' ', '_')}s",
) )
embed.set_author( embed.set_author(
name="J.A.R.V.I.S.", name="J.A.R.V.I.S.",
@ -313,6 +288,16 @@ class GitlabCog(commands.Cog):
) )
return embed return embed
def check_cache(self, ctx: SlashContext, **kwargs):
if not kwargs:
kwargs = {}
return find(
lambda x: x["command"] == ctx.subcommand_name
and x["user"] == ctx.author.id
and all(x[k] == v for k, v in kwargs.items()),
self.cache.values(),
)
@cog_ext.cog_subcommand( @cog_ext.cog_subcommand(
base="gl", base="gl",
name="issues", name="issues",
@ -333,17 +318,12 @@ class GitlabCog(commands.Cog):
], ],
) )
async def _issues(self, ctx: SlashContext, state: str = "opened"): async def _issues(self, ctx: SlashContext, state: str = "opened"):
exists = find( exists = self.check_cache(ctx, state=state)
lambda x: x["_command"] == "issues"
and x["user"] == ctx.author.id
and x["state"] == state,
self.cache.values(),
)
if exists: if exists:
await ctx.defer(hidden=True) await ctx.defer(hidden=True)
await ctx.send( await ctx.send(
"Please use existing interaction: " "Please use existing interaction: "
+ f"{exists['_message'].jump_url}", + f"{exists['paginator']._message.jump_url}",
hidden=True, hidden=True,
) )
return return
@ -351,91 +331,221 @@ class GitlabCog(commands.Cog):
m_state = state m_state = state
if m_state == "all": if m_state == "all":
m_state = None m_state = None
# issues = [] issues = []
# page = 1 page = 1
try: try:
# issues += self.project.issues.list(page=page, state=m_state, order_by="created_at", sort="desc", per_page=100) while curr_page := self.project.issues.list(
issues = self.project.issues.list( page=page,
page=1,
state=m_state, state=m_state,
order_by="created_at", order_by="created_at",
sort="desc", sort="desc",
per_page=5, per_page=100,
) ):
next_issues = self.project.issues.list( issues += curr_page
page=2, page += 1
state=m_state,
order_by="created_at",
sort="desc",
per_page=5,
)
except gitlab.exceptions.GitlabGetError: except gitlab.exceptions.GitlabGetError:
await ctx.send("Unable to get issues", hidden=True) # Only send error on first page. Otherwise, use pages retrieved
if page == 1:
await ctx.send("Unable to get issues")
return
if len(issues) == 0:
await ctx.send("No issues match that criteria")
return return
t_state = state t_state = state
if t_state == "opened": if t_state == "opened":
t_state = "open" t_state = "open"
pages = []
t_state = t_state[0].upper() + t_state[1:] t_state = t_state[0].upper() + t_state[1:]
for i in range(0, len(issues), 5):
pages.append(
self.build_embed_page(
issues[i : i + 5], t_state=t_state, name="issue"
)
)
components = create_issues_layout() paginator = Paginator(
components = edit_paging_components( bot=self.bot,
components, True, next_issues == [] ctx=ctx,
embeds=pages,
only=ctx.author,
timeout=60 * 5, # 5 minute timeout
disable_after_timeout=True,
use_extend=len(pages) > 2,
left_button_style=ButtonStyle.grey,
right_button_style=ButtonStyle.grey,
basic_buttons=["", ""],
) )
embed = self.build_embed_page(issues, t_state=t_state)
message = await ctx.send(embed=embed, components=components) self.cache[hash(paginator)] = {
self.cache[message.id] = {
"user": ctx.author.id, "user": ctx.author.id,
"state": state,
"t_state": t_state,
"page": 1,
"timeout": datetime.utcnow() + timedelta(minutes=5), "timeout": datetime.utcnow() + timedelta(minutes=5),
"_command": "issues", "command": ctx.subcommand_name,
"_message": message, "state": state,
"paginator": paginator,
} }
@cog_ext.cog_component(components=create_issues_layout()) await paginator.start()
async def _process(self, ctx: ComponentContext):
await ctx.defer(edit_origin=True) @cog_ext.cog_subcommand(
cache = self.cache[ctx.origin_message.id] base="gl",
if ctx.author.id != cache["user"]: name="mergerequests",
description="Get open issues from GitLab",
guild_ids=guild_ids,
options=[
create_option(
name="state",
description="State of issues to get",
option_type=3,
required=False,
choices=[
create_choice(name="Open", value="opened"),
create_choice(name="Closed", value="closed"),
create_choice(name="Merged", value="merged"),
create_choice(name="All", value="all"),
],
)
],
)
async def _mergerequests(self, ctx: SlashContext, state: str = "opened"):
exists = self.check_cache(ctx, state=state)
if exists:
await ctx.defer(hidden=True)
await ctx.send(
"Please use existing interaction: "
+ f"{exists['paginator']._message.jump_url}",
hidden=True,
)
return
await ctx.defer()
m_state = state
if m_state == "all":
m_state = None
merges = []
page = 1
try:
while curr_page := self.project.mergerequests.list(
page=page,
state=m_state,
order_by="created_at",
sort="desc",
per_page=100,
):
merges += curr_page
page += 1
except gitlab.exceptions.GitlabGetError:
# Only send error on first page. Otherwise, use pages retrieved
if page == 1:
await ctx.send("Unable to get merge requests")
return
if len(merges) == 0:
await ctx.send("No merge requests match that criteria")
return return
state = cache["state"] t_state = state
page = cache["page"] if t_state == "opened":
if ctx.custom_id == "back": t_state = "open"
page -= 1 pages = []
else: t_state = t_state[0].upper() + t_state[1:]
page += 1 for i in range(0, len(merges), 5):
try: pages.append(
issues = self.project.issues.list( self.build_embed_page(
page=page, merges[i : i + 5], t_state=t_state, name="merge request"
state=state, )
order_by="created_at",
sort="desc",
per_page=5,
) )
next_issues = self.project.issues.list(
page=page + 1, paginator = Paginator(
state=state, bot=self.bot,
order_by="created_at", ctx=ctx,
sort="desc", embeds=pages,
per_page=5, only=ctx.author,
timeout=60 * 5, # 5 minute timeout
disable_after_timeout=True,
use_extend=len(pages) > 2,
left_button_style=ButtonStyle.grey,
right_button_style=ButtonStyle.grey,
basic_buttons=["", ""],
)
self.cache[hash(paginator)] = {
"user": ctx.author.id,
"timeout": datetime.utcnow() + timedelta(minutes=5),
"command": ctx.subcommand_name,
"state": state,
"paginator": paginator,
}
await paginator.start()
@cog_ext.cog_subcommand(
base="gl",
name="milestones",
description="Get open issues from GitLab",
guild_ids=guild_ids,
)
async def _milestones(self, ctx: SlashContext):
exists = self.check_cache(ctx)
if exists:
await ctx.defer(hidden=True)
await ctx.send(
"Please use existing interaction: "
+ f"{exists['paginator']._message.jump_url}",
hidden=True,
) )
except gitlab.exceptions.GitlabGetError:
await ctx.edit_origin(content="Unable to get issues", hidden=True)
return return
components = create_issues_layout() await ctx.defer()
components = edit_paging_components( milestones = []
components=components, page = 1
disable_left=page == 1, try:
disable_right=next_issues == [], while curr_page := self.project.milestones.list(
page=page,
order_by="created_at",
sort="desc",
per_page=100,
):
milestones += curr_page
page += 1
except gitlab.exceptions.GitlabGetError:
# Only send error on first page. Otherwise, use pages retrieved
if page == 1:
await ctx.send("Unable to get milestones")
return
if len(milestones) == 0:
await ctx.send("No milestones exist")
return
pages = []
for i in range(0, len(milestones), 5):
pages.append(
self.build_embed_page(
milestones[i : i + 5], t_state=None, name="milestone"
)
)
paginator = Paginator(
bot=self.bot,
ctx=ctx,
embeds=pages,
only=ctx.author,
timeout=60 * 5, # 5 minute timeout
disable_after_timeout=True,
use_extend=len(pages) > 2,
left_button_style=ButtonStyle.grey,
right_button_style=ButtonStyle.grey,
basic_buttons=["", ""],
) )
embed = self.build_embed_page(
issues=issues, t_state=self.cache[ctx.origin_message.id]["t_state"] self.cache[hash(paginator)] = {
) "user": ctx.author.id,
self.cache[ctx.origin_message.id]["page"] = page "timeout": datetime.utcnow() + timedelta(minutes=5),
await ctx.edit_origin(embed=embed, components=components) "command": ctx.subcommand_name,
"paginator": paginator,
}
await paginator.start()
@loop(minutes=1) @loop(minutes=1)
async def _expire_interaction(self): async def _expire_interaction(self):
@ -444,9 +554,6 @@ class GitlabCog(commands.Cog):
if self.cache[key]["timeout"] <= datetime.utcnow() + timedelta( if self.cache[key]["timeout"] <= datetime.utcnow() + timedelta(
minutes=1 minutes=1
): ):
components = create_layout(self.cache[key]["_command"])
components = edit_paging_components(components, True, True)
await self.cache[key]["_message"].edit(components=components)
del self.cache[key] del self.cache[key]