diff --git a/src/core/api/defaults/progressbar.ts b/src/core/api/defaults/progressbar.ts index 0b8f8ec..20127dd 100644 --- a/src/core/api/defaults/progressbar.ts +++ b/src/core/api/defaults/progressbar.ts @@ -2,15 +2,99 @@ //DEFAULT PROGRESS BAR MODULE /////////////////////////////////////// import { ODValidId } from "../modules/base" -import { ODProgressBar, ODProgressBarManager, ODProgressBarRenderer, ODProgressBarRendererManager } from "../modules/progressbar" +import { ODValidConsoleColor } from "../modules/console" +import { ODManualProgressBar, ODProgressBar, ODProgressBarManager, ODProgressBarRenderer, ODProgressBarRendererManager } from "../modules/progressbar" +import ansis from "ansis" +/**## ODProgressBarRenderer_DefaultSettingsLabel `type` + * All available label types for the default progress bar renderer + */ +export type ODProgressBarRenderer_DefaultSettingsLabel = "value"|"percentage"|"fraction"|"time-ms"|"time-sec"|"time-min" + +/**## ODProgressBarRenderer_DefaultSettings `interface` + * This interface contains the settings for the default progress bar renderer. + */ +export interface ODProgressBarRenderer_DefaultSettings { + /**The color of the progress bar border. */ + borderColor:ODValidConsoleColor|"openticket", + /**The color of the progress bar (filled side). */ + filledBarColor:ODValidConsoleColor|"openticket", + /**The color of the progress bar (empty side). */ + emptyBarColor:ODValidConsoleColor|"openticket", + /**The color of the text before the progress bar. */ + prefixColor:ODValidConsoleColor|"openticket", + /**The color of the text after the progress bar. */ + suffixColor:ODValidConsoleColor|"openticket", + /**The color of the progress bar label. */ + labelColor:ODValidConsoleColor|"openticket", + + /**The character used in the left border. */ + leftBorderChar:string, + /**The character used in the right border. */ + rightBorderChar:string, + /**The character used in the filled side of the progress bar. */ + filledBarChar:string, + /**The character used in the empty side of the progress bar. */ + emptyBarChar:string, + /**The label type. (will show a number related to the progress) */ + labelType:ODProgressBarRenderer_DefaultSettingsLabel, + /**The position of the label. */ + labelPosition:"start"|"end", + /**The width of the bar. (50 characters by default) */ + barWidth:number, + + /**Show the bar. */ + showBar:boolean, + /**Show the label. */ + showLabel:boolean, + /**Show the border. */ + showBorder:boolean, +} + +export class ODProgressBarRenderer_Default extends ODProgressBarRenderer { + constructor(id:ODValidId,settings:ODProgressBarRenderer_DefaultSettings){ + super(id,(settings,min,max,value,rawPrefix,rawSuffix) => { + const percentage = (value-min)/(max-min) + const barLevel = Math.round(percentage*settings.barWidth) + + const borderAnsis = (settings.borderColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.borderColor] + const filledBarAnsis = (settings.filledBarColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.filledBarColor] + const emptyBarAnsis = (settings.emptyBarColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.emptyBarColor] + const labelAnsis = (settings.labelColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.labelColor] + const prefixAnsis = (settings.prefixColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.prefixColor] + const suffixAnsis = (settings.suffixColor == "openticket") ? ansis.hex("#f8ba00") : ansis[settings.suffixColor] + + const leftBorder = (settings.showBorder) ? borderAnsis(settings.leftBorderChar) : "" + const rightBorder = (settings.showBorder) ? borderAnsis(settings.rightBorderChar) : "" + const bar = (settings.showBar) ? filledBarAnsis(settings.filledBarChar.repeat(barLevel))+emptyBarAnsis(settings.emptyBarChar.repeat(settings.barWidth-barLevel)) : "" + const prefix = (rawPrefix) ? prefixAnsis(rawPrefix)+" " : "" + const suffix = (rawSuffix) ? " "+suffixAnsis(rawSuffix) : "" + let label: string + if (!settings.showLabel) label = "" + if (settings.labelType == "fraction") label = labelAnsis(value+"/"+max) + else if (settings.labelType == "percentage") label = labelAnsis(Math.round(percentage*100)+"%") + else if (settings.labelType == "time-ms") label = labelAnsis(value+"ms") + else if (settings.labelType == "time-sec") label = labelAnsis(Math.round(value*10)/10+"sec") + else if (settings.labelType == "time-min") label = labelAnsis(Math.round(value*10)/10+"min") + else label = labelAnsis(value.toString()) + + const labelWithPrefixAndSuffix = prefix+label+suffix + return (settings.labelPosition == "start") ? labelWithPrefixAndSuffix+" "+leftBorder+bar+rightBorder : leftBorder+bar+rightBorder+" "+labelWithPrefixAndSuffix + },settings) + } +} /**## ODProgressBarRendererManagerIds_Default `interface` * This interface is a list of ids available in the `ODProgressBarRendererManager_Default` class. * It's used to generate typescript declarations for this class. */ export interface ODProgressBarRendererManagerIds_Default { - "test-progressbar-renderer":ODProgressBarRenderer<{}> + "openticket:value-renderer":ODProgressBarRenderer_Default, + "openticket:fraction-renderer":ODProgressBarRenderer_Default, + "openticket:percentage-renderer":ODProgressBarRenderer_Default, + "openticket:time-ms-renderer":ODProgressBarRenderer_Default, + "openticket:time-sec-renderer":ODProgressBarRenderer_Default, + "openticket:time-min-renderer":ODProgressBarRenderer_Default, } /**## ODProgressBarRendererManager_Default `default_class` @@ -47,7 +131,9 @@ export class ODProgressBarRendererManager_Default extends ODProgressBarRendererM * It's used to generate typescript declarations for this class. */ export interface ODProgressBarManagerIds_Default { - "test-progressbar":ODProgressBar + "openticket:slash-command-remove":ODManualProgressBar, + "openticket:slash-command-create":ODManualProgressBar, + "openticket:slash-command-update":ODManualProgressBar, } /**## ODProgressBarManager_Default `default_class` diff --git a/src/core/api/modules/client.ts b/src/core/api/modules/client.ts index 07eae5f..393b9dd 100644 --- a/src/core/api/modules/client.ts +++ b/src/core/api/modules/client.ts @@ -5,6 +5,7 @@ import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId } from "./base import * as discord from "discord.js" import { ODConsoleWarningMessage, ODDebugger } from "./console" import { ODMessageBuildResult, ODMessageBuildSentResult } from "./builder" +import { ODManualProgressBar } from "./progressbar" /**## ODClientIntents `type` * A list of intents required when inviting the bot. @@ -814,8 +815,12 @@ export class ODSlashCommandManager extends ODManager { return {registered,unregistered,unused} } /**Create all commands that are not registered yet.*/ - async createNewCommands(instances:ODSlashCommand[]){ + async createNewCommands(instances:ODSlashCommand[],progress?:ODManualProgressBar){ if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") + if (instances.length > 0 && progress){ + progress.max = instances.length + progress.start() + } for (const instance of instances){ await this.createCmd(instance) @@ -823,22 +828,32 @@ export class ODSlashCommandManager extends ODManager { {key:"id",value:instance.id.value}, {key:"name",value:instance.name} ]) + if (progress) progress.increase(1) } } /**Update all commands that are already registered. */ - async updateExistingCommands(instances:ODSlashCommand[]){ + async updateExistingCommands(instances:ODSlashCommand[],progress?:ODManualProgressBar){ if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") - + if (instances.length > 0 && progress){ + progress.max = instances.length + progress.start() + } + for (const instance of instances){ await this.createCmd(instance) this.#debug.debug("Updated existing slash command",[{key:"id",value:instance.id.value},{key:"name",value:instance.name}]) + if (progress) progress.increase(1) } } /**Remove all commands that are registered but unused by Open Ticket. */ - async removeUnusedCommands(instances:ODSlashCommandUniversalCommand[],guildId?:string){ + async removeUnusedCommands(instances:ODSlashCommandUniversalCommand[],guildId?:string,progress?:ODManualProgressBar){ if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register slash commands!") - + if (instances.length > 0 && progress){ + progress.max = instances.length + progress.start() + } + const cmds = await this.commandManager.fetch({guildId}) for (const instance of instances){ @@ -852,6 +867,7 @@ export class ODSlashCommandManager extends ODManager { throw new ODSystemError("Failed to delete slash command '/"+cmd.name+"'!") } } + if (progress) progress.increase(1) } } /**Create a slash command. **(SYSTEM ONLY)** => Use `ODSlashCommandManager` for registering commands the default way! */ diff --git a/src/core/api/modules/progressbar.ts b/src/core/api/modules/progressbar.ts index 2a4209b..182360b 100644 --- a/src/core/api/modules/progressbar.ts +++ b/src/core/api/modules/progressbar.ts @@ -37,7 +37,7 @@ export class ODProgressBarManager extends ODManager { /**## ODProgressBarRenderFunc `type` * This is the render function for an Open Ticket console progress bar. */ -export type ODProgressBarRenderFunc = (settings:Settings,min:number,max:number,value:number) => string +export type ODProgressBarRenderFunc = (settings:Settings,min:number,max:number,value:number,prefix:string|null,suffix:string|null) => string /**## ODProgressBarRenderer `class` * This is an open ticket console progress bar renderer. @@ -57,14 +57,22 @@ export class ODProgressBarRenderer extends ODManagerData { } /**Render a progress bar using this renderer. */ - render(min:number,max:number,value:number){ + render(min:number,max:number,value:number,prefix:string|null,suffix:string|null){ try { - return this.#render(this.settings,min,max,value) + return this.#render(this.settings,min,max,value,prefix,suffix) }catch(err){ process.emit("uncaughtException",err) return "" } } + + withAdditionalSettings(settings:Partial): ODProgressBarRenderer { + const newSettings: Settings = {...this.settings} + for (const key of Object.keys(settings)){ + if (typeof settings[key] != "undefined") newSettings[key] = settings[key] + } + return new ODProgressBarRenderer(this.id,this.#render,newSettings) + } } /**## ODProgressBar `class` @@ -90,11 +98,15 @@ export class ODProgressBar extends ODManagerData { max: number /**The initial value of the progress bar. */ initialValue: number + /**The prefix displayed in the progress bar. */ + prefix:string|null + /**The prefix displayed in the progress bar. */ + suffix:string|null /**Enable automatic stopping when reaching `min` or `max`. */ autoStop: null|"min"|"max" - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,min:number,max:number,value:number,autoStop:null|"min"|"max"){ + constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,min:number,max:number,value:number,autoStop:null|"min"|"max",prefix:string|null,suffix:string|null){ super(id) this.renderer = renderer this.min = min @@ -102,6 +114,8 @@ export class ODProgressBar extends ODManagerData { this.initialValue = this.#parseValue(value) this.value = this.#parseValue(value) this.autoStop = autoStop + this.prefix = prefix + this.suffix = suffix } /**Parse a value in such a way that it doesn't go below/above the min/max limits. */ #parseValue(value:number){ @@ -114,18 +128,19 @@ export class ODProgressBar extends ODManagerData { if (!this.#active) return readline.clearLine(process.stdout,0) readline.cursorTo(process.stdout,0) - process.stdout.write(this.renderer.render(this.min,this.max,this.value)) + process.stdout.write(this.renderer.render(this.min,this.max,this.value,this.prefix,this.suffix)) } /**Start showing this progress bar in the console. */ - start(){ - if (this.#active) throw new ODSystemError("ODProgressBar => unable to start when already active!") + start(): boolean { + if (this.#active) return false this.value = this.#parseValue(this.initialValue) this.#active = true this.#renderStdout() + return true } /**Update this progress bar while active. (will automatically update the progress bar in the console) */ - protected update(value:number,stop?:boolean){ - if (!this.#active) throw new ODSystemError("ODProgressBar => unable to update when not active yet!") + protected update(value:number,stop?:boolean): boolean { + if (!this.#active) return false this.value = this.#parseValue(value) this.#renderStdout() if (stop || (this.autoStop == "max" && this.value == this.max) || (this.autoStop == "min" && this.value == this.min)){ @@ -134,6 +149,7 @@ export class ODProgressBar extends ODManagerData { this.#stopListeners.forEach((cb) => cb()) this.#stopListeners = [] } + return true } /**Wait for the progress bar to finish. */ finished(): Promise { @@ -155,8 +171,8 @@ export class ODTimedProgressBar extends ODProgressBar { /**The mode of the timer. */ mode: "increasing"|"decreasing" - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,time:number,mode:"increasing"|"decreasing"){ - super(id,renderer,0,time,0,(mode == "increasing") ? "max" : "min") + constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,time:number,mode:"increasing"|"decreasing",prefix:string|null,suffix:string|null){ + super(id,renderer,0,time,0,(mode == "increasing") ? "max" : "min",prefix,suffix) this.time = time this.mode = mode } @@ -180,8 +196,10 @@ export class ODTimedProgressBar extends ODProgressBar { } } start(){ - super.start() + const res = super.start() + if (!res) return false this.#execute() + return true } } @@ -192,11 +210,8 @@ export class ODTimedProgressBar extends ODProgressBar { * You can update the progress manually using `update()`. */ export class ODManualProgressBar extends ODProgressBar { - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,amount:number,autoStop:null|"min"|"max"){ - super(id,renderer,0,amount,0,autoStop) - } - start(){ - super.start() + constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,amount:number,autoStop:null|"min"|"max",prefix:string|null,suffix:string|null){ + super(id,renderer,0,amount,0,autoStop,prefix,suffix) } /**Set the value of the progress bar. */ set(value:number,stop?:boolean){ diff --git a/src/data/framework/progressBarLoader.ts b/src/data/framework/progressBarLoader.ts index afc94bf..f990c17 100644 --- a/src/data/framework/progressBarLoader.ts +++ b/src/data/framework/progressBarLoader.ts @@ -1,7 +1,67 @@ import {openticket, api, utilities} from "../../index" export const loadAllProgressBarRenderers = async () => { + const defaultSettings: api.ODProgressBarRenderer_DefaultSettings = { + borderColor:"gray", + filledBarColor:"openticket", + emptyBarColor:"gray", + prefixColor:"white", + suffixColor:"white", + labelColor:"white", + + leftBorderChar:"[", + rightBorderChar:"]", + filledBarChar:"█", + emptyBarChar:"▒", + labelType:"value", + labelPosition:"end", + barWidth:50, + + showBar:true, + showLabel:true, + showBorder:true, + } + + //VALUE RENDERER + const valueRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + valueRendererSettings.labelType = "value" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:value-renderer",valueRendererSettings)) + + //FRACTION RENDERER + const fractionRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + fractionRendererSettings.labelType = "fraction" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:fraction-renderer",fractionRendererSettings)) + + //PERCENTAGE RENDERER + const percentageRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + percentageRendererSettings.labelType = "percentage" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:percentage-renderer",percentageRendererSettings)) + + //TIME MS RENDERER + const timeMsRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + timeMsRendererSettings.labelType = "time-ms" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:time-ms-renderer",timeMsRendererSettings)) + + //TIME SEC RENDERER + const timeSecRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + timeSecRendererSettings.labelType = "time-sec" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:time-sec-renderer",timeSecRendererSettings)) + + //TIME MIN RENDERER + const timeMinRendererSettings: api.ODProgressBarRenderer_DefaultSettings = {...defaultSettings} + timeMinRendererSettings.labelType = "time-min" + openticket.progressbars.renderers.add(new api.ODProgressBarRenderer_Default("openticket:time-min-renderer",timeMinRendererSettings)) } export const loadAllProgressBars = async () => { + const fractRenderer = openticket.progressbars.renderers.get("openticket:fraction-renderer") + + //SLASH COMMAND REMOVE (doesn't have correct amount yet) + openticket.progressbars.add(new api.ODManualProgressBar("openticket:slash-command-remove",fractRenderer.withAdditionalSettings({filledBarColor:"red"}),0,"max",null,"Commands Removed")) + + //SLASH COMMAND CREATE (doesn't have correct amount yet) + openticket.progressbars.add(new api.ODManualProgressBar("openticket:slash-command-create",fractRenderer.withAdditionalSettings({filledBarColor:"green"}),0,"max",null,"Commands Created")) + + //SLASH COMMAND UPDATE (doesn't have correct amount yet) + openticket.progressbars.add(new api.ODManualProgressBar("openticket:slash-command-update",fractRenderer.withAdditionalSettings({filledBarColor:"openticket"}),0,"max",null,"Commands Updated")) } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 24d20a2..e356ba9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -411,11 +411,19 @@ const main = async () => { if (openticket.defaults.getDefault("slashCommandRegistering")){ //get all commands that are already registered in the bot const cmds = await openticket.client.slashCommands.getAllRegisteredCommands() + const removableCmds = cmds.unused.map((cmd) => cmd.cmd) + const newCmds = cmds.unregistered.map((cmd) => cmd.instance) + const updatableCmds = cmds.registered.filter((cmd) => cmd.requiresUpdate || openticket.defaults.getDefault("forceSlashCommandRegistration")).map((cmd) => cmd.instance) + + //init progress bars + const removeProgress = openticket.progressbars.get("openticket:slash-command-remove") + const createProgress = openticket.progressbars.get("openticket:slash-command-create") + const updateProgress = openticket.progressbars.get("openticket:slash-command-update") //remove unused cmds, create new cmds & update existing cmds - if (openticket.defaults.getDefault("allowSlashCommandRemoval")) await openticket.client.slashCommands.removeUnusedCommands(cmds.unused.map((cmd) => cmd.cmd)) - await openticket.client.slashCommands.createNewCommands(cmds.unregistered.map((cmd) => cmd.instance)) - await openticket.client.slashCommands.updateExistingCommands(cmds.registered.filter((cmd) => cmd.requiresUpdate || openticket.defaults.getDefault("forceSlashCommandRegistration")).map((cmd) => cmd.instance)) + if (openticket.defaults.getDefault("allowSlashCommandRemoval")) await openticket.client.slashCommands.removeUnusedCommands(removableCmds,undefined,removeProgress) + await openticket.client.slashCommands.createNewCommands(newCmds,createProgress) + await openticket.client.slashCommands.updateExistingCommands(updatableCmds,updateProgress) await openticket.events.get("afterSlashCommandsRegistered").emit([openticket.client.slashCommands,openticket.client]) }