-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add `run` to both the component button and select menu helper - Add `run` to both the component button and select menu helper -> Allows you to listen for a button press directly on the button helper itself -> Only listens for about 10 minutes (might change to customizable times in the future) - Fix `Structures.Message.deleted` not updating on channel/guild deletes - Update `Structures.Message` -> Add `.hasFlagEphemeral` - Update `Interactions.InteractionCommand` -> Default `global` to false if `global` isn't present and `guildIds` is present * Fix Component Helper's Typings * Update `Structures.Message` - Update `Structures.Message` -> Add `.canEdit` -> Add checks for ephemeral in `.canDelete` -> Default `.deleted` as true if is an ephemeral message * Add `Components`, Update `ShardClient` - Add `Components` to `Utils` -> Allows you to manage a message's components much easier as well as have a custom timeout and a listener to any button press on the message --> Timeout is defaulted to 10 minutes - Fix interaction commands not updating if a select menu option changes `required` - Update `Structures.Member` -> Add `.canEditRole()` (checks our role hierarchy with the role provided to see if its under us) * Update `Constants` - Update `Constants` -> Remove `COMPONENT_` constants -> Add `MAX_ACTION_ROW_BUTTONS` and `MAX_ACTION_ROW_SELECT_MENUS` - Update Components Types * Fix `ActionRow.isFull` * Add types to thread rest endpoints * 0.16.2 release
- Loading branch information
Showing
21 changed files
with
1,397 additions
and
401 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
const { Constants, InteractionCommandClient, Utils } = require('../../../lib'); | ||
const { InteractionCallbackTypes, MessageFlags, Permissions } = Constants; | ||
const { Components, ComponentActionRow } = Utils; | ||
|
||
|
||
const guildId = ''; | ||
const token = ''; | ||
const interactionClient = new InteractionCommandClient(token); | ||
|
||
interactionClient.add({ | ||
description: 'ping!', | ||
name: 'ping', | ||
guildIds: [guildId], | ||
run: (context) => { | ||
const actionRow = new ComponentActionRow(); | ||
actionRow.createButton({ | ||
label: 'ping, but clear buttons', | ||
run: (componentContext) => componentContext.editOrRespond({content: 'pong from the button!', components: []}), | ||
}); | ||
actionRow.createButton({ | ||
label: 'ping, but respond', | ||
run: (componentContext) => { | ||
return componentContext.respond(InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE, { | ||
content: 'pong!', | ||
flags: MessageFlags.EPHEMERAL, | ||
}); | ||
}, | ||
}); | ||
return context.editOrRespond({content: 'pong!', components: [actionRow]}); | ||
}, | ||
}); | ||
|
||
interactionClient.add({ | ||
description: 'Click Test', | ||
name: 'click-test', | ||
guildIds: [guildId], | ||
run: (context) => { | ||
const components = new Components({ | ||
timeout: 5 * (60 * 1000), | ||
onTimeout: () => context.editOrRespond({content: 'didnt click for 5 minutes', components: []}), | ||
}); | ||
{ | ||
const actionRow = components.createActionRow(); | ||
actionRow.createButton({ | ||
label: 'click me', | ||
run: (componentContext) => componentContext.editOrRespond({content: `clicked by ${componentContext.user}`, components: []}), | ||
}); | ||
} | ||
return context.editOrRespond({content: 'click the button', components}); | ||
}, | ||
}); | ||
|
||
interactionClient.add({ | ||
description: 'Give yourself a role', | ||
name: 'give-role', | ||
guildIds: [guildId], | ||
disableDm: true, | ||
permissions: [Permissions.MANAGE_ROLES], | ||
permissionsClient: [Permissions.MANAGE_ROLES], | ||
onPermissionsFail: (context, permissions) => context.editOrRespond('You need manage roles'), | ||
onPermissionsFailClient: (context, permissions) => context.editOrRespond('The bot needs manage roles'), | ||
onBefore: (context) => context.me.canEdit(context.member), | ||
onCancel: (context) => context.editOrRespond('The bot cannot edit you, change some role hierachy or something'), | ||
run: (context) => { | ||
const components = new Components({ | ||
timeout: 5 * (60 * 1000), | ||
onTimeout: () => context.editOrRespond({content: 'Choosing Expired', components: []}), | ||
run: async (componentContext) => { | ||
if (componentContext.userId !== context.userId || !context.values) { | ||
// ignore the press because it wasnt from the initiator | ||
return componentContext.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE); | ||
} | ||
|
||
const roleIds = context.values; | ||
if (roleIds.length) { | ||
if (context.me.canEdit(context.member)) { | ||
for (let roleId of context.values) { | ||
if (!context.member.roles.has(roleId) && context.me.canEditRole(roleId)) { | ||
await context.member.addRole(roleId); | ||
} | ||
} | ||
context.editOrRespond(`Ok, gave ${roleIds.length} roles to you`); | ||
} else { | ||
context.editOrRespond('Can\'t edit you anymore'); | ||
} | ||
} else { | ||
context.editOrRespond('choose some roles!'); | ||
} | ||
}, | ||
}); | ||
|
||
if (context.guild) { | ||
const rolesWeCanAdd = context.guild.roles.filter((role) => { | ||
return !context.member.roles.has(roleId) && context.me.canEditRole(role); | ||
}); | ||
if (rolesWeCanAdd.length) { | ||
components.createSelectMenu({ | ||
placeholder: 'Choose', | ||
options: rolesWeCanAdd.slice(0, 25).map((role) => { | ||
return { | ||
label: role.name, | ||
value: role.id, | ||
}; | ||
}), | ||
}); | ||
} | ||
} | ||
return context.editOrRespond({content: 'choose a role', components, flags: MessageFlags.EPHEMERAL}); | ||
}, | ||
}); | ||
|
||
|
||
(async () => { | ||
const cluster = await interactionClient.run(); | ||
console.log('running'); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { Timers } from 'detritus-utils'; | ||
|
||
import { BaseCollection } from '../collections'; | ||
import { Interaction, InteractionDataComponent } from '../structures'; | ||
import { Components, ComponentContext } from '../utils'; | ||
|
||
|
||
export class ComponentHandler { | ||
listeners = new BaseCollection<string, Components>(); | ||
|
||
delete(listenerId: string): boolean { | ||
if (this.listeners.has(listenerId)) { | ||
const listener = this.listeners.get(listenerId)!; | ||
if (listener._timeout) { | ||
listener._timeout.stop(); | ||
} | ||
return this.listeners.delete(listenerId); | ||
} | ||
return false; | ||
} | ||
|
||
async execute(interaction: Interaction): Promise<void> { | ||
if (!this.listeners.length || !interaction.isFromMessageComponent || !interaction.message || !interaction.data) { | ||
return; | ||
} | ||
const message = interaction.message; | ||
const data = interaction.data as InteractionDataComponent; | ||
|
||
const listener = this.listeners.get(message.interaction?.id || message.id) || this.listeners.get(message.id); | ||
if (listener) { | ||
try { | ||
if (typeof(listener.run) === 'function') { | ||
const context = new ComponentContext(interaction); | ||
await Promise.resolve(listener.run(context)); | ||
} | ||
} catch(error) { | ||
|
||
} | ||
|
||
for (let actionRow of listener.components) { | ||
const component = actionRow.components.find((c) => c.customId === data.customId); | ||
if (component) { | ||
try { | ||
if (typeof(component.run) === 'function') { | ||
const context = new ComponentContext(interaction); | ||
await Promise.resolve(component.run(context)); | ||
} | ||
} catch(error) { | ||
|
||
} | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
insert(listener: Components) { | ||
const listenerId = listener.id; | ||
if (listenerId) { | ||
if (this.listeners.has(listenerId)) { | ||
const oldListener = this.listeners.get(listenerId)!; | ||
if (oldListener._timeout) { | ||
oldListener._timeout.stop(); | ||
} | ||
this.delete(listenerId); | ||
} | ||
|
||
if (listener.timeout) { | ||
const timeout = listener._timeout = new Timers.Timeout(); | ||
timeout.start(listener.timeout, async () => { | ||
if (this.listeners.get(listenerId) === listener) { | ||
this.delete(listenerId); | ||
|
||
try { | ||
if (typeof(listener.onTimeout) === 'function') { | ||
await Promise.resolve(listener.onTimeout()); | ||
} | ||
} catch(error) { | ||
|
||
} | ||
} | ||
}); | ||
} | ||
|
||
this.listeners.set(listenerId, listener); | ||
} | ||
} | ||
} |
Oops, something went wrong.