feat(backend): add tip of day

This commit is contained in:
KernelDeimos 2024-05-31 20:36:14 -04:00
parent 4bdad75766
commit 2d8e6240c6
3 changed files with 125 additions and 0 deletions

View File

@ -222,6 +222,9 @@ const install = async ({ services, app }) => {
const { DetailProviderService } = require('./services/DetailProviderService');
services.registerService('whoami', DetailProviderService);
const { DevTODService } = require('./services/DevTODService');
services.registerService('__dev-tod', DevTODService);
}
const install_legacy = async ({ services }) => {

View File

@ -57,6 +57,7 @@ class DevConsoleService extends BaseService {
// if a widget throws an error we MUST remove it;
// it's probably a stack overflow because it's printing.
const to_remove = [];
let positions = [];
for ( const w of this.widgets ) {
let output; try {
output = w();
@ -66,8 +67,43 @@ class DevConsoleService extends BaseService {
continue;
}
output = Array.isArray(output) ? output : [output];
positions.push([this.static_lines.length, output.length]);
this.static_lines.push(...output);
}
const DESIRED_MIN_OUT = 10;
const size_ok = () =>
process.stdout.rows - DESIRED_MIN_OUT > this.static_lines.length;
let n_hidden = 0;
for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) {
if ( size_ok() ) break;
const w = this.widgets[i];
if ( ! w.unimportant ) continue;
n_hidden++;
const [start, length] = positions[i];
this.static_lines.splice(start, length);
// update positions
for ( let j = i ; j < positions.length ; j++ ) {
positions[j][0] -= length;
}
}
for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) {
if ( size_ok() ) break;
n_hidden++;
const w = this.widgets[i];
const [start, length] = positions[i];
this.static_lines.splice(start, length);
}
if ( n_hidden && size_ok() ) {
this.static_lines.push(
`\x1B[33m` +
this.generateEnd(
`[ ${n_hidden} widget${n_hidden === 1 ? '' : 's'} hidden ]`
) +
`\x1B[0m`
);
}
if (!this.arrays_equal(initialOutput, this.static_lines)) {
this.mark_updated(); // Update only if outputs have changed
}

View File

@ -0,0 +1,86 @@
const { surrounding_box } = require("../fun/dev-console-ui-utils");
const BaseService = require("./BaseService");
const SOURCE_CODE_TIPS = `
Most services are registered in CoreModule.js
Boot sequence events are different from service events
ExpectationService exists to ensure Puter doesn't miss a step
Services are composable; StrategyService is a good example
API endpoints should be on a separate origin in production
There is some limited query-building in packages/backend/src/om
`;
const tips = (
// CLI tips
`
Type \`help\` to see a list of commands
\`logs:show\` toggles log output; useful when typing long commands
\`logs:indent \` toggles indentation for some logs
\`lock:locks \` will list any active mutex locks
`,
// Source code tips
`
Most services are registered in CoreModule.js
Boot sequence events are different from service events
ExpectationService exists to ensure Puter doesn't miss a step
Services are composable; StrategyService is a good example
API endpoints should be on a separate origin in production
These messages come from DevTODService.js
`
).split('\n').map((line) => line.trim())
.filter((line) => line.length)
.map(tip => {
const lines = [];
const WRAP = process.stdout.columns || 50;
while ( tip.length ) {
lines.push(tip.substring(0, WRAP));
tip = tip.substring(WRAP);
}
return lines;
})
class DevTODService extends BaseService {
async _init () {
const svc_commands = this.services.get('commands');
this._register_commands(svc_commands);
}
async ['__on_boot.consolidation'] () {
const random_tip = tips[Math.floor(Math.random() * tips.length)];
this.tod_widget = () => {
const lines = [
"",
"\x1B[1mTip of the Day\x1B[0m",
...random_tip,
"Type tod:dismiss to un-stick this message",
"",
];
surrounding_box('33;1', lines);
return lines;
}
this.tod_widget.unimportant = true;
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( ! svc_devConsole ) return;
svc_devConsole.add_widget(this.tod_widget);
}
_register_commands (commands) {
commands.registerCommands('tod', [
{
id: 'dismiss',
description: 'Dismiss the startup message',
handler: async (_, log) => {
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( ! svc_devConsole ) return;
svc_devConsole.remove_widget(this.tod_widget);
const lines = this.tod_widget();
for ( const line of lines ) log.log(line);
this.tod_widget = null;
}
}
]);
}
}
module.exports = { DevTODService };