(discord): Fill in discord interfaces

This commit is contained in:
2026-07-29 15:48:47 +03:00
parent 9203a795e3
commit 8fc0ff0667
4 changed files with 618 additions and 6 deletions
+139
View File
@@ -0,0 +1,139 @@
"""
Defines widgets for displaying a campaign
"""
from typing import Optional, TYPE_CHECKING
import asyncio
import datetime as dt
import discord
from discord.ui import Modal
from discord.ui.select import select, Select, SelectOption
from discord.ui.button import button, Button, ButtonStyle
from discord.ui.text_input import TextInput, TextStyle
from meta import LionBot
from meta.errors import UserInputError
from meta.config import conf
from utils.lib import tabulate, utc_now, MessageArgs, parse_duration
from utils.ui import MessageUI, AButton, AsComponents, ConfigEditor
from utils.ui.micros import FastModal
from utils.ui.pagers import BasePager, Pager
from ...campaign import RewardCampaign
from ...data import EarnedReward
from .. import logger
from .rewards import RewardList
class CampaignDashboard(MessageUI):
def __init__(self, bot: LionBot, campaign: RewardCampaign, **kwargs):
super().__init__(**kwargs)
self.bot = bot
self.campaign = campaign
# UI state
# ------ UI API -----
# ------ UI Components -----
# Button to open rewards list
@button(label="Rewards Earned")
async def rewards_list_button(self, press: discord.Interaction, pressed: Button):
await press.response.defer()
widget = RewardList(
bot=self.bot,
campaign=self.campaign,
callerid=self._callerid,
)
self._slaves.append(widget)
await widget.run(press)
await widget.wait()
self._slaves.remove(widget)
@button(emoji=conf.emojis.cancel, style=ButtonStyle.red)
async def quit_button(self, press: discord.Interaction, pressed: Button):
"""Close the UI and all children."""
await press.response.defer(thinking=False)
await self.quit()
@button(emoji=conf.emojis.refresh)
async def refresh_button(self, press: discord.Interaction, pressed: Button):
await press.response.defer()
await self.refresh()
# ------ UI Flow -----
async def refresh_layout(self):
# Nothing to refresh
pass
async def make_message(self) -> MessageArgs:
embed = discord.Embed(
title=f"{self.campaign.row.campaign_name} Campaign Dashboard"
)
# embed.set_footer with last update
# Don't show the webhook url since it contains secrets, just show whether it is set
# Hard-coded channel/timer URL for now
campaign = self.campaign
started_at = (
discord.utils.format_dt(campaign.row.started_at, "F")
if campaign.row.started_at
else "*Not Started*"
)
all_rewards = await campaign.get_rewards()
rewards_earned = len(all_rewards)
reward_cap = campaign.row.target_rewards
if reward_cap is not None:
rewards = f"{rewards_earned} out of {reward_cap}"
else:
rewards = f"{rewards_earned}"
description = (
f"Campaign running since {started_at} with {rewards} rewards given."
)
table = {
"Created at": discord.utils.format_dt(campaign.row.created_at, "F"),
"Started at": started_at,
"Moderator Role": f"<&@{campaign.row.moderator_role_id}>" if campaign.row.moderator_role_id else "*Not Set*",
"Logging webhook": "*Set Up*" if campaign.row.logging_webhook_url else "*Not Set*",
"Rewards Earned": str(rewards_earned),
"Rewards Cap": str(reward_cap),
}
if campaign.row.completed_at is not None:
table['Finished at'] = discord.utils.format_dt(campaign.row.completed_at, "F")
prop_table = '\n'.join(tabulate(*table.items()))
embed.description = f"{description}\n\n{prop_table}"
# Brief summary of rewards in columns. 12 per column. Empty titles?
rewardrows = []
for reward in all_rewards:
name = reward.twitch_user_name or str(reward.twitch_user_id) or str(reward.profileid)
fluffed = reward.fulfilled_at is not None
fluffed_emoji = '' if fluffed else '🔳'
rewardrows.append(f"{fluffed_emoji} {name}")
blocks = ['\n'.join(rewardrows[i:i+12]) for i in range(0, len(rewardrows), 12)]
embed.add_field(
name="Rewards Summary",
value=blocks[0] or 'No Rewards Earned',
inline=True
)
for block in blocks[1:]:
embed.add_field(
name="--",
value=block,
)
return MessageArgs(embed=embed)
async def reload(self):
await self.campaign.row.refresh()