mirror of
https://github.com/HeyPuter/puter.git
synced 2025-02-02 23:28:39 +08:00
feat(backend): add tip of day
This commit is contained in:
parent
4bdad75766
commit
2d8e6240c6
@ -222,6 +222,9 @@ const install = async ({ services, app }) => {
|
|||||||
|
|
||||||
const { DetailProviderService } = require('./services/DetailProviderService');
|
const { DetailProviderService } = require('./services/DetailProviderService');
|
||||||
services.registerService('whoami', DetailProviderService);
|
services.registerService('whoami', DetailProviderService);
|
||||||
|
|
||||||
|
const { DevTODService } = require('./services/DevTODService');
|
||||||
|
services.registerService('__dev-tod', DevTODService);
|
||||||
}
|
}
|
||||||
|
|
||||||
const install_legacy = async ({ services }) => {
|
const install_legacy = async ({ services }) => {
|
||||||
|
@ -57,6 +57,7 @@ class DevConsoleService extends BaseService {
|
|||||||
// if a widget throws an error we MUST remove it;
|
// if a widget throws an error we MUST remove it;
|
||||||
// it's probably a stack overflow because it's printing.
|
// it's probably a stack overflow because it's printing.
|
||||||
const to_remove = [];
|
const to_remove = [];
|
||||||
|
let positions = [];
|
||||||
for ( const w of this.widgets ) {
|
for ( const w of this.widgets ) {
|
||||||
let output; try {
|
let output; try {
|
||||||
output = w();
|
output = w();
|
||||||
@ -66,8 +67,43 @@ class DevConsoleService extends BaseService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
output = Array.isArray(output) ? output : [output];
|
output = Array.isArray(output) ? output : [output];
|
||||||
|
positions.push([this.static_lines.length, output.length]);
|
||||||
this.static_lines.push(...output);
|
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)) {
|
if (!this.arrays_equal(initialOutput, this.static_lines)) {
|
||||||
this.mark_updated(); // Update only if outputs have changed
|
this.mark_updated(); // Update only if outputs have changed
|
||||||
}
|
}
|
||||||
|
86
packages/backend/src/services/DevTODService.js
Normal file
86
packages/backend/src/services/DevTODService.js
Normal 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 };
|
Loading…
Reference in New Issue
Block a user