add setup wizard, lockdown, team tasks, embed builder; fix admin dashboard
Four new independent features: /setup (guided onboarding wizard for module/channel/automod-strength config), /lockdown (raid protection with per-channel permission snapshot/restore and join-kick), /task (staff task tracker with status buttons + dashboard view), /embed create (modal-driven embed builder with optional link button). Also fixes the Admin dashboard, which always showed "-" because loadAdminData() double-wrapped the overview response and discarded activity data, plus mismatched field names against adminService's actual shape (guildCount/activeGuilds24/uptimeMs). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
66
src/commands/utility/task.ts
Normal file
66
src/commands/utility/task.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ChatInputCommandInteraction,
|
||||
EmbedBuilder,
|
||||
PermissionFlagsBits,
|
||||
SlashCommandBuilder
|
||||
} from 'discord.js';
|
||||
import { SlashCommand } from '../../utils/types';
|
||||
import { context } from '../../config/context';
|
||||
|
||||
const STATUS_LABELS: Record<string, string> = { open: 'Offen', in_progress: 'In Bearbeitung', done: 'Erledigt' };
|
||||
|
||||
export function buildTaskCard(task: { id: string; title: string; description: string | null; status: string; assigneeId: string | null; createdByTag: string }) {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(task.title)
|
||||
.setDescription(task.description || 'Keine Beschreibung')
|
||||
.setColor(0xf97316)
|
||||
.addFields(
|
||||
{ name: 'Status', value: STATUS_LABELS[task.status] || task.status, inline: true },
|
||||
{ name: 'Zugewiesen an', value: task.assigneeId ? `<@${task.assigneeId}>` : 'Niemand', inline: true },
|
||||
{ name: 'Erstellt von', value: task.createdByTag, inline: true }
|
||||
);
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder().setCustomId(`task:status:${task.id}:open`).setLabel('Offen').setStyle(task.status === 'open' ? ButtonStyle.Primary : ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId(`task:status:${task.id}:in_progress`).setLabel('In Bearbeitung').setStyle(task.status === 'in_progress' ? ButtonStyle.Primary : ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId(`task:status:${task.id}:done`).setLabel('Erledigt').setStyle(task.status === 'done' ? ButtonStyle.Success : ButtonStyle.Secondary)
|
||||
);
|
||||
return { embeds: [embed], components: [row] };
|
||||
}
|
||||
|
||||
const command: SlashCommand = {
|
||||
guildOnly: true,
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('task')
|
||||
.setDescription('Verwaltet Team-Aufgaben.')
|
||||
.addSubcommand((sub) =>
|
||||
sub
|
||||
.setName('create')
|
||||
.setDescription('Erstellt eine neue Team-Aufgabe.')
|
||||
.addStringOption((opt) => opt.setName('title').setDescription('Titel der Aufgabe').setRequired(true))
|
||||
.addStringOption((opt) => opt.setName('description').setDescription('Beschreibung'))
|
||||
.addUserOption((opt) => opt.setName('assignee').setDescription('Zuständige Person'))
|
||||
)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages),
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
if (!interaction.guildId) return;
|
||||
const title = interaction.options.getString('title', true);
|
||||
const description = interaction.options.getString('description') ?? undefined;
|
||||
const assignee = interaction.options.getUser('assignee');
|
||||
|
||||
const task = await context.tasks.createTask({
|
||||
guildId: interaction.guildId,
|
||||
title,
|
||||
description,
|
||||
assigneeId: assignee?.id,
|
||||
createdBy: interaction.user.id,
|
||||
createdByTag: interaction.user.tag
|
||||
});
|
||||
|
||||
await interaction.reply(buildTaskCard(task));
|
||||
}
|
||||
};
|
||||
|
||||
export default command;
|
||||
Reference in New Issue
Block a user