refactor(configuration): Setup configuration and menu to be reuseable

This commit is contained in:
Michel Fedde 2025-06-23 00:57:02 +02:00
parent 863ae3fab2
commit d46bbd84c5
21 changed files with 551 additions and 452 deletions

View file

@ -0,0 +1,177 @@
import {ConfigurationHandler} from "./ConfigurationHandler";
import {
AnyMenuItem,
CollectionMenuItem,
FieldMenuItem, FieldMenuItemContext, FieldMenuItemSaveValue,
MenuItem,
MenuItemType,
PromptMenuItem
} from "../Menu/MenuRenderer.types";
import {TraversalPath} from "../Menu/MenuTraversal.types";
import {
channelMention,
ChannelSelectMenuBuilder,
ChannelType,
inlineCode,
italic,
StringSelectMenuBuilder, TextInputBuilder, TextInputStyle
} from "discord.js";
import {ChannelId} from "../types/DiscordTypes";
import {MessageActionRowComponentBuilder} from "@discordjs/builders";
import {TransformerType} from "./ConfigurationTransformer";
type FieldHandlerMenuItem = MenuItem & (Partial<PromptMenuItem> | Partial<FieldMenuItem>);
type HandlerMenuItem =
FieldHandlerMenuItem | CollectionMenuItem<HandlerMenuItem>
export class MenuHandler {
constructor(
private readonly config: ConfigurationHandler,
) {
}
public fillMenuItems(
menuItems: HandlerMenuItem[]
): AnyMenuItem[] {
const handler = this;
function resolve(path: TraversalPath, menuItem: HandlerMenuItem): AnyMenuItem {
path = [...path, menuItem.traversalKey];
if (menuItem.type === MenuItemType.Collection) {
menuItem.children = menuItem.children.map((nextMenuItem) => resolve(path, nextMenuItem))
return <CollectionMenuItem>menuItem;
}
const transformerType = handler.config.transformer.getTransformerType(path.join('.'));
if (transformerType === undefined || transformerType === null) {
throw new Error(`Can't resolve type for '${path.join('.')}'`);
}
menuItem.type = handler.findType(transformerType);
menuItem.setValue = handler.setValue.bind(handler);
menuItem.getCurrentValue = handler.findCurrentValueMethod(transformerType);
menuItem.getActionRowBuilder = handler.findActionRowBuilderMethod(transformerType);
return <AnyMenuItem>menuItem;
}
return menuItems.map((menuItem) => resolve([], menuItem))
}
private findType(transformer: TransformerType): MenuItemType.Field | MenuItemType.Prompt
{
switch (transformer) {
case TransformerType.String:
case TransformerType.Paragraph:
return MenuItemType.Prompt;
default:
return MenuItemType.Field;
}
}
private findCurrentValueMethod(transformer: TransformerType): (context: FieldMenuItemContext) => string
{
switch (transformer) {
case TransformerType.Channel:
return this.getChannelValue.bind(this);
case TransformerType.PermissionBoolean:
return this.getPermissionBooleanValue.bind(this);
case TransformerType.String:
case TransformerType.Paragraph:
return this.getStringValue.bind(this);
}
}
private findActionRowBuilderMethod(transformer: TransformerType):
((context: FieldMenuItemContext) => MessageActionRowComponentBuilder) | ((context: FieldMenuItemContext) => TextInputBuilder)
{
switch (transformer) {
case TransformerType.Channel:
return this.getChannelMenuBuilder.bind(this);
case TransformerType.PermissionBoolean:
return this.getPermissionBooleanBuilder.bind(this);
case TransformerType.String:
return this.getStringBuilder.bind(this);
case TransformerType.Paragraph:
return this.getTextareaBuilder.bind(this);
}
}
private getChannelValue(context: FieldMenuItemContext): string {
const value = this.config.getConfigurationByPath(context.path.join('.'));
if (value === undefined) {
return italic("None");
}
if (!value) {
return inlineCode("None");
}
return channelMention(<ChannelId>value);
}
private getChannelMenuBuilder(): MessageActionRowComponentBuilder {
return new ChannelSelectMenuBuilder()
.setChannelTypes(ChannelType.GuildText)
.setPlaceholder("New Value");
}
private getPermissionBooleanValue(context: FieldMenuItemContext) {
const value = this.config.getConfigurationByPath(context.path.join('.'));
if (value === undefined) {
return italic("None");
}
return value ? 'Allowed' : "Disallowed";
}
private getPermissionBooleanBuilder() {
return new StringSelectMenuBuilder()
.setOptions(
[
{
label: "Allow",
value: "1"
},
{
label: "Disallow",
value: "0"
}
]
)
}
private getStringValue(context: FieldMenuItemContext): string {
const value = this.config.getConfigurationByPath(context.path.join('.'));
if (!value) {
return "";
}
if (typeof value !== 'string') {
throw new TypeError(`Value of type ${typeof value} can't be used for a string value!`)
}
return value;
}
private getStringBuilder(): TextInputBuilder {
return new TextInputBuilder()
.setStyle(TextInputStyle.Short)
.setMaxLength(100)
}
private getTextareaBuilder(): TextInputBuilder {
return new TextInputBuilder()
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(2048)
}
private setValue(value: FieldMenuItemSaveValue[]|string, context: FieldMenuItemContext): void {
const savedValue = typeof value !== 'string' ?
value.join('; ') :
value;
this.config.save(context.path.join('.'), savedValue);
}
}