From 4af9b9e17fa5a62ca310a3f55ca7371bfebd351e Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Sat, 23 May 2026 14:30:56 +0200 Subject: [PATCH] (v4.2.0) Added 5 new question types Added support for dropdown, radio select, checkbox select, file upload & text display question types. --- .github/CONTRIBUTORS.json | 2 + .github/CONTRIBUTORS.svg | 188 ++++++++-------- package.json | 2 +- src/builders/embeds.ts | 18 +- src/builders/modals.ts | 173 --------------- src/commands/claim.ts | 2 +- src/commands/close.ts | 2 +- src/commands/delete.ts | 2 +- src/commands/pin.ts | 2 +- src/commands/reopen.ts | 2 +- src/commands/ticket.ts | 67 ++++-- src/commands/unclaim.ts | 2 +- src/commands/unpin.ts | 2 +- src/components/modals.ts | 302 ++++++++++++++++++++++++++ src/core/api/question.ts | 265 ++++++++++++++++------ src/core/api/ticket.ts | 3 +- src/core/cli/quickSetup.ts | 13 ++ src/core/mappings/action.ts | 3 +- src/core/mappings/builder.ts | 9 +- src/core/mappings/component.ts | 11 +- src/core/mappings/config.ts | 30 ++- src/core/startup/migration.ts | 13 ++ src/data/framework/checkerLoader.ts | 16 +- src/data/framework/configLoader.ts | 15 ++ src/data/openticket/questionLoader.ts | 90 ++++++-- src/index.ts | 4 +- 26 files changed, 837 insertions(+), 401 deletions(-) delete mode 100644 src/builders/modals.ts create mode 100644 src/components/modals.ts diff --git a/.github/CONTRIBUTORS.json b/.github/CONTRIBUTORS.json index 2803e3e..f703118 100644 --- a/.github/CONTRIBUTORS.json +++ b/.github/CONTRIBUTORS.json @@ -50,6 +50,7 @@ {"sectionId":"contributor","name":"Ashish5180","pictureUrl":"https://github.com/Ashish5180.png","profileUrl":"https://github.com/Ashish5180"}, {"sectionId":"contributor","name":"duboiss","pictureUrl":"https://github.com/duboiss.png","profileUrl":"https://github.com/duboiss"}, {"sectionId":"contributor","name":"sdehaarte","pictureUrl":"https://github.com/sdehaarte.png","profileUrl":"https://github.com/sdehaarte"}, + {"sectionId":"contributor","name":"MauroDruwel","pictureUrl":"https://github.com/MauroDruwel.png","profileUrl":"https://github.com/MauroDruwel"}, {"sectionId":"support","name":"smetsliam","pictureUrl":"https://github.com/smetsliam.png","profileUrl":"https://github.com/smetsliam"}, {"sectionId":"support","name":"Sank34","pictureUrl":"https://github.com/Sank34.png","profileUrl":"https://github.com/Sank34"}, {"sectionId":"support","name":"FrankVissers","pictureUrl":"https://github.com/FrankVissers.png","profileUrl":"https://github.com/FrankVissers"}, @@ -58,6 +59,7 @@ {"sectionId":"plugin-dev","name":"Imperatorix17","pictureUrl":"https://github.com/imperatorix17.png","profileUrl":"https://github.com/imperatorix17"}, {"sectionId":"plugin-dev","name":"DanoGlez","pictureUrl":"https://github.com/DanoGlez.png","profileUrl":"https://github.com/DanoGlez"}, {"sectionId":"plugin-dev","name":"yowsef","pictureUrl":"https://github.com/Yow-sef.png","profileUrl":"https://github.com/Yow-sef"}, + {"sectionId":"plugin-dev","name":"MeneerSouf","pictureUrl":"https://github.com/MeneerSouf.png","profileUrl":"https://github.com/MeneerSouf"}, {"sectionId":"plugin-dev","name":"challenger_nova","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""}, {"sectionId":"translator","name":"HanumeshGupta","pictureUrl":"https://github.com/HanumeshGupta.png","profileUrl":"https://github.com/HanumeshGupta"}, {"sectionId":"translator","name":"benzorich","pictureUrl":"https://github.com/benzorich.png","profileUrl":"https://github.com/benzorich"}, diff --git a/.github/CONTRIBUTORS.svg b/.github/CONTRIBUTORS.svg index 647121e..97cec2f 100644 --- a/.github/CONTRIBUTORS.svg +++ b/.github/CONTRIBUTORS.svg @@ -15,262 +15,274 @@ } ๐Ÿ› ๏ธ Contributors - + - + DJj123dj - + - + guillee3 - + - + SKaranjaN - + - + Ashish5180 - + - + duboiss - + - + sdehaarte + + + + + + MauroDruwel ๐Ÿ“ž Discord Support - + - + smetsliam - + - + Sank34 - + - + FrankVissers ๐Ÿงฉ Plugin Developers - + - + Rapid-Fast - + - + NotMukundOP - + - + Imperatorix17 - + - + DanoGlez - + - + yowsef - - + + - - challenger_nova + + MeneerSouf + + + + + + challenger_nova ๐Ÿ’ฌ Translators - + - + HanumeshGupta - + - + benzorich - + - + Reddishye - + - + josuens - + - + quiradon - + - + Imperatorix17 - + - + NoOneNook - + - + guillee3 - + - + Mods HD - + - + anderskiy - + - + SpyEye2 - + - + Sank34 - + - + thegamer5095 - + - + danoglez - + - + zhavis - + - + yuuslokrobjakkroval - + - + imLudwig - + - + iamnotmega - + - + Ronalds13424 - + - + dysashop - + - + fraden1mvp. - + - + palestinian - + - + challenger_nova - + - + erxg - + - + tsgindrius - + - + kornel0706 - + - + me.october - + - + ngocdiep2006 \ No newline at end of file diff --git a/package.json b/package.json index 3bb9c7c..83b1c84 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "license": "GPL-3.0-only", "dependencies": { "@discordjs/rest": "^2.6.1", - "@open-discord-bots/framework": "^0.4.4", + "@open-discord-bots/framework": "^0.5.2", "@types/node": "^22.5.0", "@types/terminal-kit": "^2.5.7", "ansis": "^4.2.0", diff --git a/src/builders/embeds.ts b/src/builders/embeds.ts index c8e7f7e..c5651fd 100644 --- a/src/builders/embeds.ts +++ b/src/builders/embeds.ts @@ -626,11 +626,19 @@ const ticketEmbeds = () => { if (generalConfig.data.ticketSystem.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields) const answers = ticket.get("opendiscord:answers").value - answers.forEach((answer) => { - if (!answer.value || answer.value.length == 0) return - if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false}) - else instance.addFields({name:answer.name,value:answer.value,inline:false}) - }) + for (const answer of answers){ + if (answer.type == "file-upload"){ + //render file upload fields + if (!answer.files) continue + const renderedFiles = answer.files.map((file) => `- [${file.name}](${file.url})`).join("\n") + instance.addFields({name:answer.name,value:renderedFiles,inline:false}) + + }else if (typeof answer.value == "string" && answer.value.length > 0){ + //render other fields + if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false}) + else instance.addFields({name:answer.name,value:answer.value,inline:false}) + } + } }else if (embedOptions.fields){ instance.setFields(embedOptions.fields) } diff --git a/src/builders/modals.ts b/src/builders/modals.ts deleted file mode 100644 index 281e93f..0000000 --- a/src/builders/modals.ts +++ /dev/null @@ -1,173 +0,0 @@ -/////////////////////////////////////// -//MODAL BUILDERS -/////////////////////////////////////// -import {opendiscord, api, utilities} from "../index.js" -import * as discord from "discord.js" - -const modals = opendiscord.builders.modals -const lang = opendiscord.languages - -export async function registerAllModals(){ - ticketModals() -} -const ticketModals = () => { - //TICKET QUESTIONS - modals.add(new api.ODModal("opendiscord:ticket-questions")) - modals.get("opendiscord:ticket-questions").workers.add( - new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,origin) => { - const {option} = params - - instance.setCustomId("od:ticket-questions_"+option.id.value+"_"+origin) - instance.setTitle(option.exists("opendiscord:name") ? option.get("opendiscord:name").value : option.id.value) - const questionIds = option.get("opendiscord:questions").value - questionIds.forEach((id) => { - const question = opendiscord.questions.get(id) - if (!question) return - if (question instanceof api.ODShortQuestion) instance.addQuestion({ - customId:question.id.value, - label:question.get("opendiscord:name").value, - style:"short", - required:question.get("opendiscord:required").value, - placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined, - minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined, - maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters - }) - else if (question instanceof api.ODParagraphQuestion) instance.addQuestion({ - customId:question.id.value, - label:question.get("opendiscord:name").value, - style:"paragraph", - required:question.get("opendiscord:required").value, - placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined, - minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined, - maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters - }) - }) - }) - ) - - //CLOSE TICKET REASON - modals.add(new api.ODModal("opendiscord:close-ticket-reason")) - modals.get("opendiscord:close-ticket-reason").workers.add( - new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:close-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.close")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.closePlaceholder") - }) - }) - ) - - //REOPEN TICKET REASON - modals.add(new api.ODModal("opendiscord:reopen-ticket-reason")) - modals.get("opendiscord:reopen-ticket-reason").workers.add( - new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:reopen-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.reopen")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.reopenPlaceholder") - }) - }) - ) - - //DELETE TICKET REASON - modals.add(new api.ODModal("opendiscord:delete-ticket-reason")) - modals.get("opendiscord:delete-ticket-reason").workers.add( - new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:delete-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.delete")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.deletePlaceholder") - }) - }) - ) - - //CLAIM TICKET REASON - modals.add(new api.ODModal("opendiscord:claim-ticket-reason")) - modals.get("opendiscord:claim-ticket-reason").workers.add( - new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:claim-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.claim")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.claimPlaceholder") - }) - }) - ) - - //UNCLAIM TICKET REASON - modals.add(new api.ODModal("opendiscord:unclaim-ticket-reason")) - modals.get("opendiscord:unclaim-ticket-reason").workers.add( - new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:unclaim-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.unclaim")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.unclaimPlaceholder") - }) - }) - ) - - //PIN TICKET REASON - modals.add(new api.ODModal("opendiscord:pin-ticket-reason")) - modals.get("opendiscord:pin-ticket-reason").workers.add( - new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:pin-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.pin")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.pinPlaceholder") - }) - }) - ) - - //UNPIN TICKET REASON - modals.add(new api.ODModal("opendiscord:unpin-ticket-reason")) - modals.get("opendiscord:unpin-ticket-reason").workers.add( - new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => { - const {channel,message} = params - - instance.setCustomId("od:unpin-ticket-reason|"+channel.id+"|"+message.id) - instance.setTitle(lang.getTranslation("actions.buttons.unpin")) - instance.addQuestion({ - customId:"reason", - label:lang.getTranslation("params.uppercase.reason"), - style:"paragraph", - required:true, - placeholder:lang.getTranslation("actions.modal.unpinPlaceholder") - }) - }) - ) -} \ No newline at end of file diff --git a/src/commands/claim.ts b/src/commands/claim.ts index 555e573..a2eb3a9 100644 --- a/src/commands/claim.ts +++ b/src/commands/claim.ts @@ -169,7 +169,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //CLAIM WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/close.ts b/src/commands/close.ts index 64f9595..ce0526d 100644 --- a/src/commands/close.ts +++ b/src/commands/close.ts @@ -177,7 +177,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //CLOSE WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/delete.ts b/src/commands/delete.ts index 8c153a8..400fdf3 100644 --- a/src/commands/delete.ts +++ b/src/commands/delete.ts @@ -202,7 +202,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //DELETE WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/pin.ts b/src/commands/pin.ts index 8ca9fc0..413be79 100644 --- a/src/commands/pin.ts +++ b/src/commands/pin.ts @@ -169,7 +169,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //PIN WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts index 2ba0772..d2fcc55 100644 --- a/src/commands/reopen.ts +++ b/src/commands/reopen.ts @@ -185,7 +185,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //REOPEN WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index 92c1c86..19f4192 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -50,7 +50,7 @@ export async function registerCommandResponders(){ //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //SEND MODAL - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build(origin,{guild,channel,user,option})) + instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build(origin,{guild,channel,user,option})) }else{ //check ticket permissions (modals need check after submit) if (!(await checkTicketCreationPerms(instance,origin,guild,user,option))) return cancel() @@ -99,7 +99,7 @@ export async function registerButtonResponders(){ //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //SEND MODAL - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option})) + instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option})) }else{ //check ticket permissions (modals need check after submit) if (!(await checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel() @@ -141,7 +141,7 @@ export async function registerDropdownResponders(){ //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //SEND MODAL - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option})) + instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option})) }else{ //check ticket permissions (modals need check after submit) if (!(await checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel() @@ -193,26 +193,47 @@ export async function registerModalResponders(){ if (!(await checkTicketCreationPerms(instance,originalOrigin,guild,user,option))) return cancel() //get answers - const answers: {id:string,name:string,type:"short"|"paragraph",value:string|null}[] = [] - option.get("opendiscord:questions").value.forEach((id) => { - const question = opendiscord.questions.get(id) - if (!question) return - if (question instanceof api.ODShortQuestion){ - answers.push({ - id, - name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id, - type:"short", - value:instance.values.getTextField(id,false) - }) - }else if (question instanceof api.ODParagraphQuestion){ - answers.push({ - id, - name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id, - type:"paragraph", - value:instance.values.getTextField(id,false) - }) - } - }) + const answers: api.ODQuestionAnswer[] = [] + for (const questionId of option.get("opendiscord:questions").value){ + const question = opendiscord.questions.get(questionId) + if (!question) continue + if (question instanceof api.ODShortQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"short", + value:instance.values.getTextField(questionId,false) + }) + else if (question instanceof api.ODParagraphQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"paragraph", + value:instance.values.getTextField(questionId,false) + }) + else if (question instanceof api.ODDropdownQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"dropdown", + value:instance.values.getStringDropdownValues(questionId)[0] ?? null + }) + else if (question instanceof api.ODRadioSelectQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"radio-select", + value:instance.values.getRadioGroup(questionId,false) + }) + else if (question instanceof api.ODCheckboxSelectQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"checkbox-select", + value:(instance.values.getCheckboxGroup(questionId).length > 0) ? instance.values.getCheckboxGroup(questionId).map((opt) => "> "+opt).join("\n") : null + }) + else if (question instanceof api.ODFileUploadQuestion) answers.push({ + id:questionId, + name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId, + type:"file-upload", + files:(instance.values.getUploadedFiles(questionId).length > 0) ? instance.values.getUploadedFiles(questionId).map(({id,url,name,title,description,contentType}) => ({id,url,name,title,description,contentType})) : [] + }) + } await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true) diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts index 6250061..ba48bba 100644 --- a/src/commands/unclaim.ts +++ b/src/commands/unclaim.ts @@ -168,7 +168,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //UNCLAIM WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts index a49d772..627e156 100644 --- a/src/commands/unpin.ts +++ b/src/commands/unpin.ts @@ -168,7 +168,7 @@ export async function registerVerifyBars(){ } }else if (params.selectedButtonId == "accept-with-reason"){ //UNPIN WITH REASON (MODAL) - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message})) + instance.modal(await opendiscord.components.modals.get("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message})) } }) ]) diff --git a/src/components/modals.ts b/src/components/modals.ts new file mode 100644 index 0000000..c1ed285 --- /dev/null +++ b/src/components/modals.ts @@ -0,0 +1,302 @@ +/////////////////////////////////////// +//REGISTER MODAL COMPONENTS +/////////////////////////////////////// +import {opendiscord, api, utilities} from "../index.js" +import * as discord from "discord.js" + +const modals = opendiscord.components.modals +const lang = opendiscord.languages +const generalConfig = opendiscord.configs.get("opendiscord:general") + +export async function registerModalComponents(){ + //TICKET QUESTIONS + modals.add(new api.ODComponentFactory("opendiscord:ticket-questions")) + modals.get("opendiscord:ticket-questions").workers.add( + new api.ODWorker("opendiscord:ticket-questions",0,(instance,params,origin) => { + const {option} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:questions-modal",{ + customId:"od:ticket-questions|"+option.id.value+"|"+origin, + title:lang.getTranslation("params.uppercase.ticket")+": "+(option.exists("opendiscord:name")) ? option.get("opendiscord:name").value : option.id.value + })) + + for (const questionId of option.get("opendiscord:questions").value){ + const question = opendiscord.questions.get(questionId) + if (!question) continue + + if (question instanceof api.ODShortQuestion){ + //SHORT QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODShortInputComponent(question.id.value,{ + customId:question.id.value, + required:question.get("opendiscord:required").value, + placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined, + minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined, + maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODParagraphQuestion){ + //PARAGRAPH QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODParagraphInputComponent(question.id.value,{ + customId:question.id.value, + required:question.get("opendiscord:required").value, + placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined, + minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined, + maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODDropdownQuestion){ + //DROPDOWN QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODDropdownComponent(question.id.value,{ + type:"string", + customId:question.id.value, + required:question.get("opendiscord:required").value, + placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined, + maxValues:1, + options:question.get("opendiscord:choices").value.map((choice) => ({ + label:choice.title, + emoji:choice.emoji, + description:choice.description, + value:choice.title + })) + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODRadioSelectQuestion){ + //RADIO SELECT QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODRadioGroupComponent(question.id.value,{ + customId:question.id.value, + required:question.get("opendiscord:required").value, + options:question.get("opendiscord:choices").value.map((choice) => ({ + label:choice.title, + default:choice.selectedByDefault, + description:choice.description, + value:choice.title + })) + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODCheckboxSelectQuestion){ + //CHECKBOX SELECT QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODCheckboxGroupComponent(question.id.value,{ + customId:question.id.value, + required:question.get("opendiscord:required").value, + minValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined, + maxValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined, + options:question.get("opendiscord:choices").value.map((choice) => ({ + label:choice.title, + default:choice.selectedByDefault, + description:choice.description, + value:choice.title + })) + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODFileUploadQuestion){ + //FILE UPLOAD QUESTION + const component = new api.ODLabelComponent(question.id.value,{ + title:question.get("opendiscord:name").value, + description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined, + }) + component.setComponent(new api.ODFileUploadComponent(question.id.value,{ + customId:question.id.value, + required:question.get("opendiscord:required").value, + minAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined, + maxAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined, + })) + modal.addComponent(component,"end") + }else if (question instanceof api.ODTextDisplayQuestion){ + //TEXT DISPLAY QUESTION + const component = new api.ODTextComponent(question.id.value,{ + content:question.get("opendiscord:text-contents").value + }) + modal.addComponent(component,"end") + } + } + }) + ) + + //CLOSE TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:close-ticket-reason")) + modals.get("opendiscord:close-ticket-reason").workers.add( + new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:close-ticket-reason",{ + customId:"od:close-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.close") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.closePlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //REOPEN TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:reopen-ticket-reason")) + modals.get("opendiscord:reopen-ticket-reason").workers.add( + new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:reopen-ticket-reason",{ + customId:"od:reopen-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.reopen") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.reopenPlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //DELETE TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:delete-ticket-reason")) + modals.get("opendiscord:delete-ticket-reason").workers.add( + new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:delete-ticket-reason",{ + customId:"od:delete-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.delete") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.deletePlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //CLAIM TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:claim-ticket-reason")) + modals.get("opendiscord:claim-ticket-reason").workers.add( + new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:claim-ticket-reason",{ + customId:"od:claim-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.claim") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.claimPlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //UNCLAIM TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:unclaim-ticket-reason")) + modals.get("opendiscord:unclaim-ticket-reason").workers.add( + new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unclaim-ticket-reason",{ + customId:"od:unclaim-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.unclaim") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.unclaimPlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //PIN TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:pin-ticket-reason")) + modals.get("opendiscord:pin-ticket-reason").workers.add( + new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:pin-ticket-reason",{ + customId:"od:pin-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.pin") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.pinPlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) + + //UNPIN TICKET REASON + modals.add(new api.ODComponentFactory("opendiscord:unpin-ticket-reason")) + modals.get("opendiscord:unpin-ticket-reason").workers.add( + new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => { + const {channel,message} = params + + const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unpin-ticket-reason",{ + customId:"od:unpin-ticket-reason|"+channel.id+"|"+message.id, + title:lang.getTranslation("actions.buttons.unpin") + })) + + const reasonComponent = new api.ODLabelComponent("reason",{ + title:lang.getTranslation("params.uppercase.reason"), + description:lang.getTranslation("actions.modal.unpinPlaceholder") + }) + reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{ + customId:"reason", + required:true, + placeholder:lang.getTranslation("params.uppercase.reason") + })) + modal.addComponent(reasonComponent,"end") + }) + ) +} \ No newline at end of file diff --git a/src/core/api/question.ts b/src/core/api/question.ts index bef825f..1dba0c4 100644 --- a/src/core/api/question.ts +++ b/src/core/api/question.ts @@ -2,6 +2,8 @@ //OPENTICKET OPTION MODULE /////////////////////////////////////// import * as api from "@open-discord-bots/framework/api" +import * as discord from "discord.js" +import { ODQuestionsJsonConfig_BaseQuestion, ODQuestionsJsonConfig_DropdownChoice, ODQuestionsJsonConfig_RadioCheckboxChoice } from "../mappings/config.js" /**## ODQuestionIdConstraint `type` * The constraint/layout for id mappings/interfaces of the `ODQuestion` class. @@ -14,9 +16,10 @@ export type ODQuestionIdConstraint = Record, + "opendiscord:description":ODQuestionData, "opendiscord:required":ODQuestionData, - "opendiscord:placeholder":ODQuestionData, + "opendiscord:placeholder":ODQuestionData, "opendiscord:length-enabled":ODQuestionData, "opendiscord:length-min":ODQuestionData, "opendiscord:length-max":ODQuestionData @@ -28,14 +31,77 @@ export interface ODShortQuestionIdMappings extends ODQuestionIdConstraint { */ export interface ODParagraphQuestionIdMappings extends ODQuestionIdConstraint { "opendiscord:name":ODQuestionData, + "opendiscord:description":ODQuestionData, "opendiscord:required":ODQuestionData, - "opendiscord:placeholder":ODQuestionData, + "opendiscord:placeholder":ODQuestionData, "opendiscord:length-enabled":ODQuestionData, "opendiscord:length-min":ODQuestionData, "opendiscord:length-max":ODQuestionData } +/**## ODDropdownQuestionIdMappings `interface` + * A list of all available IDs in the default `ODDropdownQuestion` class in `opendiscord`. + * It's used to generate typescript declarations for this class. + */ +export interface ODDropdownQuestionIdMappings extends ODQuestionIdConstraint { + "opendiscord:name":ODQuestionData, + "opendiscord:description":ODQuestionData, + "opendiscord:required":ODQuestionData, + + "opendiscord:placeholder":ODQuestionData, + "opendiscord:choices":ODQuestionData +} + +/**## ODRadioSelectQuestionIdMappings `interface` + * A list of all available IDs in the default `ODRadioSelectQuestion` class in `opendiscord`. + * It's used to generate typescript declarations for this class. + */ +export interface ODRadioSelectQuestionIdMappings extends ODQuestionIdConstraint { + "opendiscord:name":ODQuestionData, + "opendiscord:description":ODQuestionData, + "opendiscord:required":ODQuestionData, + + "opendiscord:choices":ODQuestionData +} + +/**## ODCheckboxSelectQuestionIdMappings `interface` + * A list of all available IDs in the default `ODCheckboxSelectQuestion` class in `opendiscord`. + * It's used to generate typescript declarations for this class. + */ +export interface ODCheckboxSelectQuestionIdMappings extends ODQuestionIdConstraint { + "opendiscord:name":ODQuestionData, + "opendiscord:description":ODQuestionData, + "opendiscord:required":ODQuestionData, + + "opendiscord:limits-enabled":ODQuestionData, + "opendiscord:limits-min":ODQuestionData, + "opendiscord:limits-max":ODQuestionData + "opendiscord:choices":ODQuestionData +} + +/**## ODFileUploadQuestionIdMappings `interface` + * A list of all available IDs in the default `ODFileUploadQuestion` class in `opendiscord`. + * It's used to generate typescript declarations for this class. + */ +export interface ODFileUploadQuestionIdMappings extends ODQuestionIdConstraint { + "opendiscord:name":ODQuestionData, + "opendiscord:description":ODQuestionData, + "opendiscord:required":ODQuestionData, + + "opendiscord:limits-enabled":ODQuestionData, + "opendiscord:limits-min":ODQuestionData, + "opendiscord:limits-max":ODQuestionData +} + +/**## ODTextDisplayQuestionIdMappings `interface` + * A list of all available IDs in the default `ODTextDisplayQuestion` class in `opendiscord`. + * It's used to generate typescript declarations for this class. + */ +export interface ODTextDisplayQuestionIdMappings extends ODQuestionIdConstraint { + "opendiscord:text-contents":ODQuestionData +} + /**## ODQuestionManager `class` * This is an Open Ticket question manager. * @@ -81,20 +147,19 @@ export interface ODQuestionJson { /**## ODQuestion `class` * This is an Open Ticket question. * - * This class contains all data related to this question (parsed from the config). + * This class contains all question data parsed from the config. * - * Use `ODShortQuestion` or `ODParagraphQuestion` instead! + * This is an abstract class. Use instances like `ODShortQuestion` or `ODParagraphQuestion` instead. */ -export class ODQuestion extends api.ODManager> { +export abstract class ODQuestion extends api.ODManager> { /**The id of this question. (from the config) */ id:api.ODId /**The type of this question (e.g. `opendiscord:short` or `opendiscord:paragraph`) */ - type: string + abstract readonly type: string - constructor(id:api.ODValidId, type:string, data:ODQuestionData[]){ + constructor(id:api.ODValidId, data:ODQuestionData[]){ super() this.id = new api.ODId(id) - this.type = type data.forEach((data) => { this.add(data) }) @@ -117,9 +182,25 @@ export class ODQuestion extends api.ODManager new ODQuestionData(data.id,data.value))) + get>(id:QuestionId): IdList[QuestionId] + get(id:api.ODValidId): ODQuestionData|null + + get(id:api.ODValidId): ODQuestionData|null { + return super.get(id) + } + + remove>(id:QuestionId): IdList[QuestionId] + remove(id:api.ODValidId): ODQuestionData|null + + remove(id:api.ODValidId): ODQuestionData|null { + return super.remove(id) + } + + exists(id:keyof api.ODNoGeneric): boolean + exists(id:api.ODValidId): boolean + + exists(id:api.ODValidId): boolean { + return super.exists(id) } } @@ -153,40 +234,36 @@ export class ODQuestionData extends api.OD } } +/**## ODQuestionAnswer `type` + * A question answer stored in the database. + */ +export type ODQuestionAnswer = { + id:string, + name:string, + type:Exclude, + value:string|null +}|{ + id:string, + name:string, + type:"file-upload", + files:{ + id:string, + url:string, + name:string, + title:string|null, + description:string|null, + contentType:string|null, + }[] +} /**## ODShortQuestion `class` - * This is an Open Ticket short question. - * - * This class contains all data related to an Open Ticket short question (parsed from the config). - * - * Use this question in an option to add a short text field to the modal! + * An Open Ticket short question. It contains all config properties of the short question type. */ -export class ODShortQuestion extends ODQuestion { - type: "opendiscord:short" = "opendiscord:short" +export class ODShortQuestion extends ODQuestion { + readonly type: "opendiscord:short" = "opendiscord:short" constructor(id:api.ODValidId, data:ODQuestionData[]){ - super(id,"opendiscord:short",data) - } - - get>(id:QuestionId): ODShortQuestionIdMappings[QuestionId] - get(id:api.ODValidId): ODQuestionData|null - - get(id:api.ODValidId): ODQuestionData|null { - return super.get(id) - } - - remove>(id:QuestionId): ODShortQuestionIdMappings[QuestionId] - remove(id:api.ODValidId): ODQuestionData|null - - remove(id:api.ODValidId): ODQuestionData|null { - return super.remove(id) - } - - exists(id:keyof api.ODNoGeneric): boolean - exists(id:api.ODValidId): boolean - - exists(id:api.ODValidId): boolean { - return super.exists(id) + super(id,data) } static fromJson(json: ODQuestionJson): ODShortQuestion { @@ -195,41 +272,91 @@ export class ODShortQuestion extends ODQuestion { } /**## ODParagraphQuestion `class` - * This is an Open Ticket paragraph question. - * - * This class contains all data related to an Open Ticket paragraph question (parsed from the config). - * - * Use this question in an option to add a paragraph text field to the modal! + * An Open Ticket paragraph question. It contains all config properties of the paragraph question type. */ -export class ODParagraphQuestion extends ODQuestion { - type: "opendiscord:paragraph" = "opendiscord:paragraph" +export class ODParagraphQuestion extends ODQuestion { + readonly type: "opendiscord:paragraph" = "opendiscord:paragraph" constructor(id:api.ODValidId, data:ODQuestionData[]){ - super(id,"opendiscord:paragraph",data) - } - - get>(id:QuestionId): ODParagraphQuestionIdMappings[QuestionId] - get(id:api.ODValidId): ODQuestionData|null - - get(id:api.ODValidId): ODQuestionData|null { - return super.get(id) - } - - remove>(id:QuestionId): ODParagraphQuestionIdMappings[QuestionId] - remove(id:api.ODValidId): ODQuestionData|null - - remove(id:api.ODValidId): ODQuestionData|null { - return super.remove(id) - } - - exists(id:keyof api.ODNoGeneric): boolean - exists(id:api.ODValidId): boolean - - exists(id:api.ODValidId): boolean { - return super.exists(id) + super(id,data) } static fromJson(json: ODQuestionJson): ODParagraphQuestion { return new ODParagraphQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) } +} + +/**## ODDropdownQuestion `class` + * An Open Ticket dropdown question. It contains all config properties of the dropdown question type. + */ +export class ODDropdownQuestion extends ODQuestion { + readonly type: "opendiscord:dropdown" = "opendiscord:dropdown" + + constructor(id:api.ODValidId, data:ODQuestionData[]){ + super(id,data) + } + + static fromJson(json: ODQuestionJson): ODDropdownQuestion { + return new ODDropdownQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) + } +} + +/**## ODRadioSelectQuestion `class` + * An Open Ticket radio-select question. It contains all config properties of the radio-select question type. + */ +export class ODRadioSelectQuestion extends ODQuestion { + readonly type: "opendiscord:radio-select" = "opendiscord:radio-select" + + constructor(id:api.ODValidId, data:ODQuestionData[]){ + super(id,data) + } + + static fromJson(json: ODQuestionJson): ODRadioSelectQuestion { + return new ODRadioSelectQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) + } +} + +/**## ODCheckboxSelectQuestion `class` + * An Open Ticket checkbox-select question. It contains all config properties of the checkbox-select question type. + */ +export class ODCheckboxSelectQuestion extends ODQuestion { + readonly type: "opendiscord:checkbox-select" = "opendiscord:checkbox-select" + + constructor(id:api.ODValidId, data:ODQuestionData[]){ + super(id,data) + } + + static fromJson(json: ODQuestionJson): ODCheckboxSelectQuestion { + return new ODCheckboxSelectQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) + } +} + +/**## ODFileUploadQuestion `class` + * An Open Ticket file-upload question. It contains all config properties of the file-upload question type. + */ +export class ODFileUploadQuestion extends ODQuestion { + readonly type: "opendiscord:file-upload" = "opendiscord:file-upload" + + constructor(id:api.ODValidId, data:ODQuestionData[]){ + super(id,data) + } + + static fromJson(json: ODQuestionJson): ODFileUploadQuestion { + return new ODFileUploadQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) + } +} + +/**## ODTextDisplayQuestion `class` + * An Open Ticket text-display question. It contains all config properties of the text-display question type. + */ +export class ODTextDisplayQuestion extends ODQuestion { + readonly type: "opendiscord:text-display" = "opendiscord:text-display" + + constructor(id:api.ODValidId, data:ODQuestionData[]){ + super(id,data) + } + + static fromJson(json: ODQuestionJson): ODTextDisplayQuestion { + return new ODTextDisplayQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value))) + } } \ No newline at end of file diff --git a/src/core/api/ticket.ts b/src/core/api/ticket.ts index be33d65..4fd5a24 100644 --- a/src/core/api/ticket.ts +++ b/src/core/api/ticket.ts @@ -4,6 +4,7 @@ import * as api from "@open-discord-bots/framework/api" import { ODTicketOption } from "./option.js" import * as discord from "discord.js" +import { ODQuestionAnswer } from "./question.js" /**## ODTicketIdConstraint `type` * The constraint/layout for id mappings/interfaces of the `ODTicket` class. @@ -48,7 +49,7 @@ export interface ODTicketIdMappings extends ODTicketIdConstraint { "opendiscord:autodelete-enabled":ODTicketData, "opendiscord:autodelete-days":ODTicketData, - "opendiscord:answers":ODTicketData<{id:string,name:string,type:"short"|"paragraph",value:string|null}[]>, + "opendiscord:answers":ODTicketData, "opendiscord:priority":ODTicketData, "opendiscord:topic":ODTicketData, "opendiscord:message-sent":ODTicketData, diff --git a/src/core/cli/quickSetup.ts b/src/core/cli/quickSetup.ts index 408694b..3b3b629 100644 --- a/src/core/cli/quickSetup.ts +++ b/src/core/cli/quickSetup.ts @@ -1411,6 +1411,19 @@ async function saveQuickSetupConfig(){ {title:"Choice D",description:"Fear",selectedByDefault:false} ] }, + { + id:"example-question-6", + name:"Example Question 6", + description:"This is a file upload question.", + type:"file-upload", + required:true, + + limits:{ + enabled:false, + min:0, + max:1 + } + }, { id:"example-text-display", type:"text-display", diff --git a/src/core/mappings/action.ts b/src/core/mappings/action.ts index b7a3478..4b1e354 100644 --- a/src/core/mappings/action.ts +++ b/src/core/mappings/action.ts @@ -8,6 +8,7 @@ import { ODTicket, ODTicketClearFilter } from "../api/ticket.js" import { ODTranscriptCompiler, ODTranscriptCompilerCompileResult } from "../api/transcript.js" import { ODRole, ODRoleUpdateMode, ODRoleUpdateResult } from "../api/role.js" import { ODPriorityLevel } from "../api/priority.js" +import { ODQuestionAnswer } from "../api/question.js" /**## ODActionManagerIdMappings `interface` * A list of all available IDs in the default `ODActionManager` class in `opendiscord`. @@ -28,7 +29,7 @@ export interface ODActionManagerIdMappings extends api.ODActionManagerIdConstrai }, "opendiscord:create-ticket":{ origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other", - params:{guild:discord.Guild,user:discord.User,option:ODTicketOption,answers:{id:string,name:string,type:"short"|"paragraph",value:string|null}[]}, + params:{guild:discord.Guild,user:discord.User,option:ODTicketOption,answers:ODQuestionAnswer[]}, result:{channel:discord.GuildTextBasedChannel,ticket:ODTicket}, workers:"opendiscord:create-ticket"|"opendiscord:send-ticket-message"|"opendiscord:discord-logs"|"opendiscord:logs" }, diff --git a/src/core/mappings/builder.ts b/src/core/mappings/builder.ts index 63dcfbe..311b5d7 100644 --- a/src/core/mappings/builder.ts +++ b/src/core/mappings/builder.ts @@ -235,14 +235,7 @@ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstr * It's used to generate typescript declarations for this class. */ export interface ODModalManagerIdMappings extends api.ODModalManagerIdConstraint { - "opendiscord:ticket-questions":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"} - "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:close-ticket-reason"} - "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:reopen-ticket-reason"} - "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:delete-ticket-reason"} - "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:claim-ticket-reason"} - "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unclaim-ticket-reason"} - "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:pin-ticket-reason"} - "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unpin-ticket-reason"} + //Deprecated, moved to ODModalComponentManagerIdMappings } ///////////////////////////// diff --git a/src/core/mappings/component.ts b/src/core/mappings/component.ts index db313c6..1e542a3 100644 --- a/src/core/mappings/component.ts +++ b/src/core/mappings/component.ts @@ -3,6 +3,8 @@ /////////////////////////////////////// import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" +import { ODTicketOption } from "../api/option.js" +import { ODTicket } from "../api/ticket.js" /**## ODSharedComponentManagerIdMappings `interface` * A list of all available IDs in the default `ODSharedComponentManager` class in `opendiscord`. @@ -25,7 +27,14 @@ export interface ODMessageComponentManagerIdMappings extends api.ODComponentMana * It's used to generate typescript declarations for this class. */ export interface ODModalComponentManagerIdMappings extends api.ODComponentManagerIdConstraint { - //"opendiscord:example-modal":{origin:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:example-modal"}, + "opendiscord:ticket-questions":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"}, + "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:close-ticket-reason"} + "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:reopen-ticket-reason"} + "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:delete-ticket-reason"} + "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:claim-ticket-reason"} + "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unclaim-ticket-reason"} + "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:pin-ticket-reason"} + "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unpin-ticket-reason"} } /**## ODComponentModifierManagerIdMappings `interface` diff --git a/src/core/mappings/config.ts b/src/core/mappings/config.ts index 4f2114b..51fc926 100644 --- a/src/core/mappings/config.ts +++ b/src/core/mappings/config.ts @@ -619,6 +619,18 @@ export interface ODQuestionsJsonConfig_CheckboxLimits { max:number } +/**## ODQuestionsJsonConfig_FileUploadLimits `interface` + * Verify the amount of uploaded files in a question. + */ +export interface ODQuestionsJsonConfig_FileUploadLimits { + /**Enable file limits. */ + enabled:boolean, + /**The minimum amount of uploaded files. */ + min:number, + /**The maximum amount of uploaded files. */ + max:number +} + /**## ODQuestionsJsonConfig_DropdownChoice `interface` * A dropdown choice used in `ODQuestionsJsonConfig_DropdownQuestion` */ @@ -654,7 +666,7 @@ export interface ODQuestionsJsonConfig_BaseQuestion { /**The description of this question. (Leave empty for none) */ description:string, /**The type of this question. */ - type:"short"|"paragraph"|"text-display"|"dropdown"|"radio-select"|"checkbox-select", + type:"short"|"paragraph"|"text-display"|"dropdown"|"radio-select"|"checkbox-select"|"file-upload", /**Is this question required? */ required:boolean, } @@ -662,9 +674,7 @@ export interface ODQuestionsJsonConfig_BaseQuestion { /**## ODQuestionsJsonConfig_TextDisplayQuestion `interface` * All properties for a text-display in the `questions.jsonc` config! */ -export interface ODQuestionsJsonConfig_TextDisplayQuestion { - /**The id of this text-display. */ - id:string, +export interface ODQuestionsJsonConfig_TextDisplayQuestion extends Omit { /**The type of this question. */ type:"text-display", /**The text contents to show in the modal. */ @@ -724,6 +734,15 @@ export interface ODQuestionsJsonConfig_CheckboxSelectQuestion extends ODQuestion choices:ODQuestionsJsonConfig_RadioCheckboxChoice[] } +/**## ODQuestionsJsonConfig_FileUploadQuestion `interface` + * All properties for checkbox select questions in the `questions.jsonc` config! + */ +export interface ODQuestionsJsonConfig_FileUploadQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"file-upload", + /**Verify the amount of uploaded files (minimum/maximum). */ + limits:ODQuestionsJsonConfig_FileUploadLimits +} + /**## ODQuestionsJsonConfig_QuestionsData `type` * All contents of the `questions.jsonc` config file. */ @@ -733,7 +752,8 @@ export type ODQuestionsJsonConfig_QuestionsData = ( ODQuestionsJsonConfig_TextDisplayQuestion| ODQuestionsJsonConfig_DropdownQuestion| ODQuestionsJsonConfig_RadioSelectQuestion| - ODQuestionsJsonConfig_CheckboxSelectQuestion + ODQuestionsJsonConfig_CheckboxSelectQuestion| + ODQuestionsJsonConfig_FileUploadQuestion )[] /////////////////////////////////////// diff --git a/src/core/startup/migration.ts b/src/core/startup/migration.ts index a62139f..3108fa6 100644 --- a/src/core/startup/migration.ts +++ b/src/core/startup/migration.ts @@ -311,6 +311,19 @@ export const migrations = [ {title:"Choice D",description:"Fear",selectedByDefault:false} ] }, + { + id:"example-file-upload", + name:"Example File Upload", + description:"With this question type, users can upload one or multiple files.", + type:"file-upload", + required:true, + + limits:{ + enabled:false, + min:0, + max:1 + } + }, { id:"example-text-display-question", type:"text-display", diff --git a/src/data/framework/checkerLoader.ts b/src/data/framework/checkerLoader.ts index 685732d..a0b1237 100644 --- a/src/data/framework/checkerLoader.ts +++ b/src/data/framework/checkerLoader.ts @@ -686,7 +686,21 @@ export const defaultQuestionsStructure = new api.ODCheckerArrayStructure("opendi ],cliDisplayName:"Choice",cliDisplayDescription:"A choice for this checkbox select question."}),cliDisplayName:"Choices",cliDisplayPropertyName:"choice",cliDisplayDescription:"Manage all available choices of this checkbox select question."})} ],cliDisplayName:"Checkbox Select Question",cliDisplayDescription:"Manage, customise and configure the checkbox select question to your preference."})}, -],cliDisplayName:"Question",cliDisplayDescription:"Manage a question of one of the 6 types: short, paragraph, text-display, dropdown, radio-select, checkbox-select."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."}) + //FILE UPLOAD QUESTION + {name:"File Upload Question",priority:0,properties:[{key:"type",value:"file-upload"}],checker:new api.ODCheckerObjectStructure("opendiscord:file-upload-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"limits",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:amount",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:amount",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:amount-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable checking the min/max amount of uploaded files."})}, + {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:amount-min",{min:0,max:10,floatAllowed:false,cliDisplayName:"Min Amount",cliDisplayDescription:"The minimum amount of uploaded files required."})}, + {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:amount-max",{min:1,max:10,floatAllowed:false,cliInitDefaultValue:10,cliDisplayName:"Max Amount",cliDisplayDescription:"The maximum amount of uploaded files allowed."})}, + ],cliDisplayName:"Upload Limits",cliDisplayDescription:"Verify the minimum or maximum amount of uploaded files."}),cliDisplayName:"Checkbox Limits",cliDisplayDescription:"Verify the minimum or maximum amount of uploaded files."})}, + ],cliDisplayName:"Checkbox Select Question",cliDisplayDescription:"Manage, customise and configure the file upload question to your preference."})}, + +],cliDisplayName:"Question",cliDisplayDescription:"Manage a question of one of the 7 types: short, paragraph, text-display, dropdown, radio-select, checkbox-select, file-upload."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."}) export const defaultTranscriptsStructure = new api.ODCheckerObjectStructure("opendiscord:transcripts",{children:[ //GENERAL diff --git a/src/data/framework/configLoader.ts b/src/data/framework/configLoader.ts index d845586..19e3fe5 100644 --- a/src/data/framework/configLoader.ts +++ b/src/data/framework/configLoader.ts @@ -286,6 +286,21 @@ export const defaultQuestionsFormatter = new fjs.TopLevelCommentFormatter(new fj new fjs.PropertyFormatter("selectedByDefault"), ])), ])}, + {key:"type",value:"file-upload",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A file upload modal question where users can upload one or more files."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("type"), + new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), + new fjs.ObjectFormatter("limits",true,[ + new fjs.MultiCommentFormatter("Configure minimum/maximum amount of files to upload."), + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("min"), + new fjs.PropertyFormatter("max"), + ]), + ])}, ]))) diff --git a/src/data/openticket/questionLoader.ts b/src/data/openticket/questionLoader.ts index 0d5d17a..0f5bb15 100644 --- a/src/data/openticket/questionLoader.ts +++ b/src/data/openticket/questionLoader.ts @@ -4,13 +4,15 @@ export async function loadAllQuestions(){ const questionConfig = opendiscord.configs.get("opendiscord:questions") if (!questionConfig) return - questionConfig.data.forEach((question) => { - if (question.type == "short"){ - opendiscord.questions.add(loadShortQuestion(question)) - }else if (question.type == "paragraph"){ - opendiscord.questions.add(loadParagraphQuestion(question)) - } - }) + for (const question of questionConfig.data){ + if (question.type === "short") opendiscord.questions.add(loadShortQuestion(question)) + else if (question.type === "paragraph") opendiscord.questions.add(loadParagraphQuestion(question)) + else if (question.type === "dropdown") opendiscord.questions.add(loadDropdownQuestion(question)) + else if (question.type === "radio-select") opendiscord.questions.add(loadRadioSelectQuestion(question)) + else if (question.type === "checkbox-select") opendiscord.questions.add(loadCheckboxSelectQuestion(question)) + else if (question.type === "file-upload") opendiscord.questions.add(loadFileUploadQuestion(question)) + else if (question.type === "text-display") opendiscord.questions.add(loadTextDisplayQuestion(question)) + } //update questions on config reload questionConfig.onReload(async () => { @@ -18,22 +20,25 @@ export async function loadAllQuestions(){ await opendiscord.questions.loopAll((data,id) => {opendiscord.questions.remove(id)}) //add new questions - questionConfig.data.forEach((question) => { - if (question.type == "short"){ - opendiscord.questions.add(loadShortQuestion(question)) - }else if (question.type == "paragraph"){ - opendiscord.questions.add(loadParagraphQuestion(question)) - } - }) + for (const question of questionConfig.data){ + if (question.type === "short") opendiscord.questions.add(loadShortQuestion(question)) + else if (question.type === "paragraph") opendiscord.questions.add(loadParagraphQuestion(question)) + else if (question.type === "dropdown") opendiscord.questions.add(loadDropdownQuestion(question)) + else if (question.type === "radio-select") opendiscord.questions.add(loadRadioSelectQuestion(question)) + else if (question.type === "checkbox-select") opendiscord.questions.add(loadCheckboxSelectQuestion(question)) + else if (question.type === "file-upload") opendiscord.questions.add(loadFileUploadQuestion(question)) + else if (question.type === "text-display") opendiscord.questions.add(loadTextDisplayQuestion(question)) + } }) } export const loadShortQuestion = (option:api.ODQuestionsJsonConfig_ShortQuestion) => { return new api.ODShortQuestion(option.id,[ new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), new api.ODQuestionData("opendiscord:required",option.required), + new api.ODQuestionData("opendiscord:placeholder",option.placeholder), - new api.ODQuestionData("opendiscord:length-enabled",option.length.enabled), new api.ODQuestionData("opendiscord:length-min",option.length.min), new api.ODQuestionData("opendiscord:length-max",option.length.max), @@ -43,11 +48,64 @@ export const loadShortQuestion = (option:api.ODQuestionsJsonConfig_ShortQuestion export const loadParagraphQuestion = (option:api.ODQuestionsJsonConfig_ParagraphQuestion) => { return new api.ODParagraphQuestion(option.id,[ new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), new api.ODQuestionData("opendiscord:required",option.required), + new api.ODQuestionData("opendiscord:placeholder",option.placeholder), - new api.ODQuestionData("opendiscord:length-enabled",option.length.enabled), new api.ODQuestionData("opendiscord:length-min",option.length.min), new api.ODQuestionData("opendiscord:length-max",option.length.max), ]) +} + +export const loadDropdownQuestion = (option:api.ODQuestionsJsonConfig_DropdownQuestion) => { + return new api.ODDropdownQuestion(option.id,[ + new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), + new api.ODQuestionData("opendiscord:required",option.required), + + new api.ODQuestionData("opendiscord:placeholder",option.placeholder), + new api.ODQuestionData("opendiscord:choices",option.choices) + ]) +} + +export const loadRadioSelectQuestion = (option:api.ODQuestionsJsonConfig_RadioSelectQuestion) => { + return new api.ODRadioSelectQuestion(option.id,[ + new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), + new api.ODQuestionData("opendiscord:required",option.required), + + new api.ODQuestionData("opendiscord:choices",option.choices) + ]) +} + +export const loadCheckboxSelectQuestion = (option:api.ODQuestionsJsonConfig_CheckboxSelectQuestion) => { + return new api.ODCheckboxSelectQuestion(option.id,[ + new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), + new api.ODQuestionData("opendiscord:required",option.required), + + new api.ODQuestionData("opendiscord:limits-enabled",option.limits.enabled), + new api.ODQuestionData("opendiscord:limits-min",option.limits.min), + new api.ODQuestionData("opendiscord:limits-max",option.limits.max), + new api.ODQuestionData("opendiscord:choices",option.choices) + ]) +} + +export const loadFileUploadQuestion = (option:api.ODQuestionsJsonConfig_FileUploadQuestion) => { + return new api.ODFileUploadQuestion(option.id,[ + new api.ODQuestionData("opendiscord:name",option.name), + new api.ODQuestionData("opendiscord:description",option.description), + new api.ODQuestionData("opendiscord:required",option.required), + + new api.ODQuestionData("opendiscord:limits-enabled",option.limits.enabled), + new api.ODQuestionData("opendiscord:limits-min",option.limits.min), + new api.ODQuestionData("opendiscord:limits-max",option.limits.max), + ]) +} + +export const loadTextDisplayQuestion = (option:api.ODQuestionsJsonConfig_TextDisplayQuestion) => { + return new api.ODTextDisplayQuestion(option.id,[ + new api.ODQuestionData("opendiscord:text-contents",option.textContents) + ]) } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2c61a46..f6afe08 100644 --- a/src/index.ts +++ b/src/index.ts @@ -647,7 +647,7 @@ const main = async () => { //load modal builders opendiscord.log("Loading modals...","system") if (opendiscord.sharedFuses.getFuse("modalBuildersLoading")){ - await (await import("./builders/modals.js")).registerAllModals() + //Deprecated, moved to "modal components" } await opendiscord.events.get("onModalBuilderLoad").emit([opendiscord.builders.modals,opendiscord.builders,opendiscord.actions]) await opendiscord.events.get("afterModalBuildersLoaded").emit([opendiscord.builders.modals,opendiscord.builders,opendiscord.actions]) @@ -671,7 +671,7 @@ const main = async () => { //load modal components opendiscord.log("Loading modal components...","system") if (opendiscord.sharedFuses.getFuse("modalComponentsLoading")){ - //TODO!! + await (await import("./components/modals.js")).registerModalComponents() } await opendiscord.events.get("onModalComponentLoad").emit([opendiscord.components.modals,opendiscord.components,opendiscord.actions]) await opendiscord.events.get("afterModalComponentsLoaded").emit([opendiscord.components.modals,opendiscord.components,opendiscord.actions])