Skip to content

Commit 5d7c833

Browse files
committed
feat: enhance plugin system with new action handling and menu integration
1 parent f39b868 commit 5d7c833

File tree

4 files changed

+104
-76
lines changed

4 files changed

+104
-76
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
LANGUAGE=en
1+
MENU_LANGUAGE=en
22
DEBUG_LOG=true

README.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,41 +45,41 @@ The library provides two main methods for output:
4545
To create a new plugin, define an object implementing the `PluginType` interface:
4646

4747
```typescript
48-
import { addPlugin } from 'modular-cli-menu';
49-
import type { PluginType, ActionType } from 'modular-cli-menu';
48+
import { print, addPlugin } from 'modular-cli-menu';
5049

51-
const myPlugin: PluginType = {
50+
addPlugin({
5251
menu: {
53-
name: 'myplugin', // Unique menu name
54-
parent: 'main', // Parent menu (optional)
55-
color: 'blue', // Menu color (optional)
56-
choices: [ // Array of available actions
57-
'menu.myplugin.action1',
58-
'menu.myplugin.action2',
52+
name: 'test',
53+
parent: "main",
54+
choices: [
55+
'menu.test.action1',
5956
'menu.action.back'
6057
]
61-
},
58+
},
6259
actions: {
63-
'menu.myplugin.action1': {
60+
'menu.test.action1': {
6461
type: 'function',
65-
name: 'menu.myplugin.action1',
66-
color: 'green',
62+
name: 'menu.test.action1',
6763
options: {
68-
message: {
69-
text: 'Action 1 executed!',
70-
color: 'green'
71-
}
64+
message: { text: 'menu.test.action1.message'}
7265
}
7366
}
7467
},
7568
languages: {
7669
en: {
77-
'menu.myplugin.question': 'My Plugin',
78-
'menu.myplugin.action1': 'Execute Action 1',
79-
'menu.myplugin.action2': 'Execute Action 2'
70+
'menu.test.question': 'Test',
71+
'menu.test.action1.label': 'Action 1',
72+
'menu.test.action1.message': 'Something',
73+
},
74+
it: {
75+
'menu.test.question': 'Test',
76+
'menu.test.action1.label': 'Azione 1',
77+
'menu.test.action1.message': 'Qualcosa',
8078
}
8179
}
82-
};
80+
})
81+
82+
print();
8383
```
8484

8585
In the main file remember to register the plugin

src/languages.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type TranslationDictionary = {
77

88
let languages = { en, it };
99

10-
export function updateLanguages(pluginLanguages: Record<string, Record<string, string>>) {
10+
function updateLanguages(pluginLanguages: Record<string, Record<string, string>>) {
1111
Object.keys(languages).forEach(language => {
1212
if (pluginLanguages[language]) {
1313
languages[language as keyof typeof languages] = {
@@ -35,4 +35,4 @@ function getTranslation(label: string, language?: LanguageTypes): string {
3535
return translations[language ?? getLanguage()][label] || label;
3636
}
3737

38-
export { getLanguages, getLanguage, getTranslation };
38+
export { getLanguages, getLanguage, getTranslation, updateLanguages };

src/menu.ts

Lines changed: 80 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,61 @@ function getQuestion(item: MenuItemType) {
112112
}
113113
}
114114

115+
async function action(selectedAction: string, selectedMenu: string = 'main') {
116+
const action = actions[selectedAction];
117+
switch (action?.type) {
118+
case 'function':
119+
if(action.options?.message?.text) {
120+
console.log(write(action.options.message.text, action.options.message?.color));
121+
}
122+
if (action.options?.callback) {
123+
await action.options.callback(selectedMenu);
124+
}
125+
break;
126+
case 'goto':
127+
if(menu[selectedMenu].parent) {
128+
if (action.options?.callback) {
129+
await action.options.callback(menu[selectedMenu].parent);
130+
} else {
131+
print(menu[selectedMenu].parent);
132+
}
133+
} else {
134+
console.log(write(`menu.goto.target.notfound`, 'red'));
135+
}
136+
break;
137+
case 'input':
138+
if (action.options?.message) {
139+
const userInput = await waitForKeyPress({
140+
message: action.options.message.text,
141+
color: action.options.message?.color,
142+
default: action.options.default
143+
});
144+
145+
if (action.options.callback) {
146+
await action.options.callback(userInput, menu[selectedMenu]?.parent);
147+
}
148+
}
149+
break;
150+
case 'checkbox':
151+
if (action.options?.message) {
152+
const assetsAnswer = await checkbox({
153+
message: write(action.options.message.text, action.options.message?.color),
154+
choices: action.options.answers.map((item) => ({
155+
name: write(item.name, item.color),
156+
value: item.value
157+
}))
158+
});
159+
if (action.options.callback) {
160+
await action.options.callback(assetsAnswer, menu[selectedMenu]?.parent);
161+
}
162+
}
163+
break;
164+
default:
165+
console.log(write(`menu.action.notfound`, 'red'));
166+
break;
167+
}
168+
}
169+
115170
async function print(selectedMenu: string = 'main') {
116171
console.clear();
117172

@@ -123,58 +178,7 @@ async function print(selectedMenu: string = 'main') {
123178
if(menu[selectedMenu]) {
124179
const answer: string = await select(getQuestion(menu[selectedMenu]));
125180
if(menu[selectedMenu].choices.includes(answer)) {
126-
const action = actions[answer];
127-
switch (action?.type) {
128-
case 'function':
129-
if(action.options?.message?.text) {
130-
console.log(write(action.options.message.text, action.options.message?.color));
131-
}
132-
if (action.options?.callback) {
133-
await action.options.callback(selectedMenu);
134-
}
135-
break;
136-
case 'goto':
137-
if(menu[selectedMenu].parent) {
138-
if (action.options?.callback) {
139-
await action.options.callback(menu[selectedMenu].parent);
140-
} else {
141-
print(menu[selectedMenu].parent);
142-
}
143-
} else {
144-
console.log(write(`menu.goto.target.notfound`, 'red'));
145-
}
146-
break;
147-
case 'input':
148-
if (action.options?.message) {
149-
const userInput = await waitForKeyPress({
150-
message: action.options.message.text,
151-
color: action.options.message?.color,
152-
default: action.options.default
153-
});
154-
155-
if (action.options.callback) {
156-
await action.options.callback(userInput, menu[selectedMenu]?.parent);
157-
}
158-
}
159-
break;
160-
case 'checkbox':
161-
if (action.options?.message) {
162-
const assetsAnswer = await checkbox({
163-
message: write(action.options.message.text, action.options.message?.color),
164-
choices: action.options.answers.map((item) => ({
165-
name: write(item.name, item.color),
166-
value: item.value
167-
}))
168-
});
169-
if (action.options.callback) {
170-
await action.options.callback(assetsAnswer, menu[selectedMenu]?.parent);
171-
}
172-
}
173-
break;
174-
default:
175-
console.log(write(`menu.action.notfound`, 'red'));
176-
break;
177-
}
181+
action(answer, selectedMenu);
178182
} else if(menu[answer]) {
179183
print(answer);
180184
}
@@ -183,15 +187,39 @@ async function print(selectedMenu: string = 'main') {
183187
}
184188
}
185189

190+
async function addActionToMenu(action: string | ActionType, menuName: string = 'main') {
191+
if(typeof action === 'string') {
192+
action = actions[action];
193+
} else {
194+
if(!action.name) {
195+
throw new Error('Action must have a name property');
196+
}
197+
if(!action.type) {
198+
throw new Error('Action must have a type property');
199+
}
200+
actions[action.name] = action;
201+
}
202+
203+
if(action && menu[menuName]) {
204+
const tmp = getAction(action.name);
205+
if(!menu[menuName].choices.includes(tmp.value)) {
206+
menu[menuName].choices.push(tmp.value);
207+
}
208+
}
209+
}
210+
186211
export {
187212
type PluginType,
188213
type ActionType,
189214
type ActionsType,
190215
type MenuItemType,
191216
type MenuType,
217+
updateLanguages,
218+
action,
192219
print,
193220
write,
194221
addPlugin,
222+
addActionToMenu,
195223
actionExit,
196224
actionGoBack,
197225
waitForKeyPress

0 commit comments

Comments
 (0)